committing more tests
This commit is contained in:
parent
9271042e78
commit
315a200c9b
6 changed files with 1604 additions and 0 deletions
122
minimal.cpp
Normal file
122
minimal.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include "Map.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// basically an int wrapper
|
||||
class MyKeyType {
|
||||
private:
|
||||
int val;
|
||||
|
||||
public:
|
||||
//not default constructable, not copy assignable, not move assignable
|
||||
MyKeyType() = delete;
|
||||
MyKeyType& operator=(const MyKeyType&) = delete;
|
||||
MyKeyType& operator=(MyKeyType&&) = delete;
|
||||
|
||||
// copy constructable and move assignable
|
||||
MyKeyType(MyKeyType&&) = default;
|
||||
MyKeyType(const MyKeyType&) = default;
|
||||
~MyKeyType() = default;
|
||||
|
||||
MyKeyType(int i) : val(i) { }
|
||||
|
||||
bool operator<(const MyKeyType& other) const {
|
||||
return this->val < other.val;
|
||||
}
|
||||
|
||||
bool operator==(const MyKeyType &other) const {
|
||||
return this->val == other.val;
|
||||
}
|
||||
};
|
||||
|
||||
// same as keytype except no operator<
|
||||
class MyValueType {
|
||||
private:
|
||||
int val;
|
||||
|
||||
public:
|
||||
//not default constructable, not copy assignable, not move assignable
|
||||
MyValueType() = delete;
|
||||
MyValueType& operator=(const MyValueType&) = delete;
|
||||
MyValueType& operator=(MyValueType&&) = delete;
|
||||
|
||||
// copy constructable and move assignable
|
||||
MyValueType(MyValueType&&) = default;
|
||||
MyValueType(const MyValueType&) = default;
|
||||
~MyValueType() = default;
|
||||
|
||||
MyValueType(int i) : val(i) { }
|
||||
|
||||
bool operator==(const MyValueType &other) const {
|
||||
return this->val == other.val;
|
||||
}
|
||||
};
|
||||
|
||||
class MyDefaultConstructible {
|
||||
|
||||
friend bool operator<(const MyDefaultConstructible &o1, const MyDefaultConstructible &o2) {
|
||||
return o1.val < o2.val;
|
||||
}
|
||||
|
||||
private:
|
||||
int val = 0;
|
||||
|
||||
public:
|
||||
// not copy assignable, not move assignable
|
||||
MyDefaultConstructible& operator=(const MyDefaultConstructible&) = delete;
|
||||
MyDefaultConstructible& operator=(MyDefaultConstructible&&) = delete;
|
||||
|
||||
// default constructable, copy constructable and move assignable
|
||||
MyDefaultConstructible() = default;
|
||||
MyDefaultConstructible(MyDefaultConstructible&&) = default;
|
||||
MyDefaultConstructible(const MyDefaultConstructible&) = default;
|
||||
~MyDefaultConstructible() = default;
|
||||
|
||||
MyDefaultConstructible(int i) : val(i) { }
|
||||
|
||||
bool operator==(const MyDefaultConstructible &other) const {
|
||||
return this->val == other.val;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MyAssignable {
|
||||
private:
|
||||
int val = 0;
|
||||
|
||||
public:
|
||||
MyAssignable() = default;
|
||||
MyAssignable(int i) : val(i) { }
|
||||
bool operator==(const MyAssignable &other) const {
|
||||
return this->val == other.val;
|
||||
}
|
||||
};
|
||||
|
||||
// manual instantiation, instantiates every member function instead of
|
||||
// just the ones called
|
||||
template class cs440::Map<MyKeyType, MyDefaultConstructible>;
|
||||
|
||||
|
||||
int main() {
|
||||
cs440::Map<MyKeyType, MyValueType> m{{3, 5}};
|
||||
m.insert({{2}, {3}});
|
||||
m.insert({{1}, {3}});
|
||||
m.insert({{5}, {3}});
|
||||
m.insert({{7}, {3}});
|
||||
m.at(2);
|
||||
auto iter = m.find(2);
|
||||
m.erase(iter);
|
||||
auto m_copy = m;
|
||||
assert(m_copy == m);
|
||||
|
||||
cs440::Map<MyKeyType, MyDefaultConstructible> m2{{8, 9}};
|
||||
m2[10]; // should default construct these values
|
||||
m2[15];
|
||||
|
||||
cs440::Map<MyKeyType, MyAssignable> m3{{6, 7}};
|
||||
m3[20] = {5}; // move assign
|
||||
MyAssignable ma{1};
|
||||
m3[10] = ma; //copy assign
|
||||
|
||||
return 0;
|
||||
}
|
67
morseex.cpp
Normal file
67
morseex.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "Map.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cctype>
|
||||
|
||||
|
||||
cs440::Map<char, std::string> morse {
|
||||
{',', "--..--"},
|
||||
{'.', ".-.-.-"},
|
||||
{'?', "..--.."},
|
||||
{'0', "----- "},
|
||||
{'1', ".---- "},
|
||||
{'2', "..--- "},
|
||||
{'3', "...-- "},
|
||||
{'4', "....- "},
|
||||
{'5', "..... "},
|
||||
{'6', "-.... "},
|
||||
{'7', "--... "},
|
||||
{'8', "---.. "},
|
||||
{'9', "----. "},
|
||||
{'A', ".-"},
|
||||
{'B', "-..."},
|
||||
{'C', "-.-."},
|
||||
{'D', "-.. "},
|
||||
{'E', "."},
|
||||
{'F', "..-."},
|
||||
{'G', "--."},
|
||||
{'H', "...."},
|
||||
{'I', ".."},
|
||||
{'J', ".---"},
|
||||
{'K', "-.-"},
|
||||
{'L', ".-.."},
|
||||
{'M', "--"},
|
||||
{'N', "-."},
|
||||
{'O', "---"},
|
||||
{'P', ".--."},
|
||||
{'Q', "--.-"},
|
||||
{'R', ".-."},
|
||||
{'S', "..."},
|
||||
{'T', "-"},
|
||||
{'U', "..-"},
|
||||
{'V', "...-"},
|
||||
{'W', ".--"},
|
||||
{'X', "-..-"},
|
||||
{'Y', "-.--"},
|
||||
{'Z', "--.."},
|
||||
};
|
||||
|
||||
|
||||
int main() {
|
||||
std::cout << "Enter messages to be translated (CTRL+D to exit)\n";
|
||||
|
||||
std::string message;
|
||||
while(std::cin >> message) {
|
||||
for (auto c : message) {
|
||||
try {
|
||||
std::cout << morse.at(toupper(c)) << '\n';
|
||||
} catch (std::out_of_range) {
|
||||
std::cout << "invalid character: " << c << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
35
ta.cpp
Normal file
35
ta.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "Map.hpp"
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
template class cs440::Map<int, int>;
|
||||
int main(void) {
|
||||
cs440::Map<std::string, int> a;
|
||||
std::stringstream ss;
|
||||
std::string s;
|
||||
for (std::size_t i = 10; i >= 1; i--) {
|
||||
ss << i;
|
||||
ss >> s;
|
||||
a.insert({s, i});
|
||||
for (std::size_t j = 10; j >= i; j--) {
|
||||
ss << j;
|
||||
ss >> s;
|
||||
}
|
||||
}
|
||||
for (std::size_t i = 1; i <= 10; i++) {
|
||||
ss << i;
|
||||
ss >> s;
|
||||
}
|
||||
for (std::size_t i = 10; i >= 5; i--) {
|
||||
std::cout << i << std::endl;
|
||||
ss << i;
|
||||
ss >> s;
|
||||
auto b = a.find(s);
|
||||
a.erase(b);
|
||||
for (std::size_t j = 1; j <= i; j++) {
|
||||
ss << j;
|
||||
ss >> s;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
620
test-kec.cpp
Normal file
620
test-kec.cpp
Normal file
|
@ -0,0 +1,620 @@
|
|||
/*
|
||||
* Run with
|
||||
*
|
||||
* -i iterations
|
||||
*
|
||||
* to do a stress test for the given number of iterations.
|
||||
*
|
||||
* -p
|
||||
*
|
||||
* to print correct output.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include "Map.hpp"
|
||||
|
||||
/*
|
||||
* Wrapper class around std::map to handle slight difference in return value and also
|
||||
* provide an Iterator nested name.
|
||||
*/
|
||||
|
||||
template <typename K, typename V>
|
||||
class test_map : public std::map<K, V> {
|
||||
private:
|
||||
using base_t = std::map<K, V>;
|
||||
public:
|
||||
using Iterator = typename base_t::iterator;
|
||||
std::pair<typename base_t::iterator, bool>insert(const std::pair<const K, V> &p) {
|
||||
return this->base_t::insert(p);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Person class.
|
||||
*/
|
||||
|
||||
struct Person {
|
||||
friend bool operator<(const Person &p1, const Person &p2) {
|
||||
return p1.name < p2.name;
|
||||
}
|
||||
friend bool operator==(const Person &p1, const Person &p2) {
|
||||
return p1.name == p2.name;
|
||||
}
|
||||
Person(const char *n) : name(n) {}
|
||||
void print() const {
|
||||
printf("Name: %s\n", name.c_str());
|
||||
}
|
||||
const std::string name;
|
||||
Person &operator=(const Person &) = delete;
|
||||
};
|
||||
|
||||
void
|
||||
print(const std::pair<const Person, int> &p) {
|
||||
p.first.print();
|
||||
printf(" %d\n", p.second);
|
||||
}
|
||||
|
||||
/*
|
||||
* MyClass class.
|
||||
*/
|
||||
|
||||
struct MyClass {
|
||||
friend bool operator<(const MyClass &o1, const MyClass &o2) {
|
||||
return o1.num < o2.num;
|
||||
}
|
||||
friend bool operator==(const MyClass &o1, const MyClass &o2) {
|
||||
return o1.num == o2.num;
|
||||
}
|
||||
MyClass(double n) : num(n) {}
|
||||
double num;
|
||||
};
|
||||
|
||||
void
|
||||
print(const std::pair<const int, std::string> &p) {
|
||||
printf("%d, %s; ", p.first, p.second.c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
* Stress class.
|
||||
*/
|
||||
|
||||
struct Stress {
|
||||
friend bool operator<(const Stress& o1, const Stress& o2) {
|
||||
return o1.val < o2.val;
|
||||
}
|
||||
friend bool operator==(const Stress& o1, const Stress& o2) {
|
||||
return o1.val == o2.val;
|
||||
}
|
||||
Stress(int _v) : val(_v){}
|
||||
int val;
|
||||
};
|
||||
// Helper function for stress testing. This orders iterators by what they point to.
|
||||
template <template <typename, typename> class MAP_T>
|
||||
inline bool
|
||||
less(const typename MAP_T<const Stress, double>::Iterator &lhs, const typename MAP_T<const Stress, double>::Iterator &rhs) {
|
||||
return (*lhs).first.val < (*rhs).first.val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Additional test functions for BST.
|
||||
*/
|
||||
|
||||
template <template <typename, typename> class MAP_T>
|
||||
void traverse(const MAP_T<const Person, int> &, int level);
|
||||
|
||||
template <template <typename, typename> class MAP_T>
|
||||
void traverse2(int level);
|
||||
|
||||
template <template <typename, typename> class MAP_T>
|
||||
void check(const MAP_T<const Stress, double> &, const std::map<const Stress, double> &);
|
||||
|
||||
/*
|
||||
* The actual test code. It's a template so that it can be run with the std::map and the
|
||||
* assignment Map.
|
||||
*/
|
||||
|
||||
template <template <typename, typename> class MAP_T>
|
||||
void
|
||||
run_test(int iterations) {
|
||||
|
||||
/*
|
||||
* Test with Person.
|
||||
*/
|
||||
|
||||
{
|
||||
Person p1("Jane");
|
||||
Person p2("John");
|
||||
Person p3("Mary");
|
||||
Person p4("Dave");
|
||||
|
||||
MAP_T<const Person, int> map;
|
||||
|
||||
// Insert people into the map.
|
||||
auto p1_it = map.insert(std::make_pair(p1, 1));
|
||||
map.insert(std::make_pair(p2, 2));
|
||||
map.insert(std::make_pair(p3, 3));
|
||||
map.insert(std::make_pair(p4, 4));
|
||||
|
||||
// Check iterator equality.
|
||||
{
|
||||
// Returns an iterator pointing to the first element.
|
||||
auto it1 = map.begin();
|
||||
// Returns an iterator pointing to one PAST the last element. This
|
||||
// iterator is obviously conceptual only. It cannot be
|
||||
// dereferenced.
|
||||
auto it2 = map.end();
|
||||
|
||||
it1++; // Second node now.
|
||||
it1++; // Third node now.
|
||||
it2--; // Fourth node now.
|
||||
it2--; // Third node now.
|
||||
assert(it1 == it2);
|
||||
it2--; // Second node now.
|
||||
it2--; // First node now.
|
||||
assert(map.begin() == it2);
|
||||
}
|
||||
|
||||
// Check insert return value.
|
||||
{
|
||||
printf("---- Test insert() return.\n");
|
||||
// Insert returns an interator. If it's already in, it returns an
|
||||
// iterator to the already inserted element.
|
||||
auto it = map.insert(std::make_pair(p1, 1));
|
||||
assert(it.first == p1_it.first);
|
||||
// Now insert one that is new.
|
||||
it = map.insert(std::make_pair(Person("Larry"), 5));
|
||||
print(*(it.first));
|
||||
map.erase(it.first);
|
||||
}
|
||||
|
||||
// Print the whole thing now, to verify ordering.
|
||||
printf("---- Before erasures.\n");
|
||||
|
||||
// Iterate through the whole map, and call print() on each Person.
|
||||
for (auto &e : map) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
// Test multiple traversals of the same map.
|
||||
printf("---- Multiple traversals\n");
|
||||
traverse(map, 4);
|
||||
|
||||
// Test multiple BST at the same time.
|
||||
printf("---- Multiple BST\n");
|
||||
traverse2<MAP_T>(4);
|
||||
|
||||
/*
|
||||
* Test some erasures.
|
||||
*/
|
||||
|
||||
// Erase first element.
|
||||
map.erase(map.begin());
|
||||
auto it = map.end();
|
||||
--it; // it now points to last element.
|
||||
it--; // it now points to penultimate element.
|
||||
map.erase(it);
|
||||
|
||||
printf("---- After erasures.\n");
|
||||
|
||||
// Iterate through the whole map, and call print() on each Person.
|
||||
for (auto &e : map) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
// Test iterator validity.
|
||||
{
|
||||
// Iterators must be valid even when other things are inserted or
|
||||
// erased.
|
||||
printf("---- Test iterator non-invalidation\n");
|
||||
|
||||
// Get iterator to the first.
|
||||
auto b = map.begin();
|
||||
|
||||
// Insert element which will be at the end.
|
||||
auto it = map.insert(std::make_pair(Person("Zeke"), 10));
|
||||
|
||||
// Iterator to the first should still be valid.
|
||||
print(*b);
|
||||
|
||||
// Delete first, saving the actual object.
|
||||
auto tmp(*b); // Save, so we can reinsert.
|
||||
map.erase(map.begin()); // Erase it.
|
||||
|
||||
// Check iterator for inserted. Iterator to end should still be valid.
|
||||
print(*it.first); // This should still be valid.
|
||||
|
||||
// Reinsert first element.
|
||||
map.insert(tmp);
|
||||
|
||||
// Erase inserted last element.
|
||||
map.erase(it.first);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Map with MyClass.
|
||||
*/
|
||||
|
||||
{
|
||||
MAP_T<const MyClass, std::string> map;
|
||||
|
||||
// Empty container, should print nothing.
|
||||
for (auto it = map.begin(); it != map.end(); ++it) {
|
||||
abort();
|
||||
}
|
||||
|
||||
MyClass m1(0), m2(3), m3(1), m4(2);
|
||||
auto m1_it = map.insert(std::make_pair(m1, "mmm1"));
|
||||
map.insert(std::make_pair(m2, "mmm2"));
|
||||
map.insert(std::make_pair(m3, "mmm3"));
|
||||
map.insert(std::make_pair(m4, "mmm4"));
|
||||
|
||||
// Should print 0.0 1.0 2.0 3.0
|
||||
for (auto &e : map) {
|
||||
printf("%3.1f ", e.first.num);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Check return value of insert.
|
||||
{
|
||||
// Already in, so must return equal to m1_it.
|
||||
auto it = map.insert(std::make_pair(m1, "mmm1"));
|
||||
assert(it.first == m1_it.first);
|
||||
}
|
||||
|
||||
// Erase the first element.
|
||||
map.erase(map.begin());
|
||||
// Should print "1.0 2.0 3.0".
|
||||
for (auto &e : map) {
|
||||
printf("%3.1f ", e.first.num);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Erase the new first element.
|
||||
map.erase(map.begin());
|
||||
// Should print "2.0 3.0".
|
||||
for (auto &e : map) {
|
||||
printf("%3.1f ", e.first.num);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
map.erase(--map.end());
|
||||
// Should print "2.0".
|
||||
for (auto &e : map) {
|
||||
printf("%3.1f ", e.first.num);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Erase the last element.
|
||||
map.erase(map.begin());
|
||||
// Should print nothing.
|
||||
for (auto &e : map) {
|
||||
printf("%3.1f ", e.first.num);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Map with plain int.
|
||||
*/
|
||||
|
||||
{
|
||||
MAP_T<const int, std::string> map;
|
||||
|
||||
// Empty container, should print nothing.
|
||||
for (auto &e : map) {
|
||||
printf("%d ", e.first);
|
||||
}
|
||||
|
||||
auto p1(std::make_pair(4, "444"));
|
||||
auto p2(std::make_pair(3, "333"));
|
||||
auto p3(std::make_pair(0, "000"));
|
||||
auto p4(std::make_pair(2, "222"));
|
||||
auto p5(std::make_pair(1, "111"));
|
||||
|
||||
map.insert(p1);
|
||||
map.insert(p2);
|
||||
map.insert(p3);
|
||||
map.insert(p4);
|
||||
map.insert(p5);
|
||||
|
||||
// Should print "0 1 2 3 4".
|
||||
for (auto it = map.begin(); it != map.end(); ++it) {
|
||||
print(*it);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Insert dupes.
|
||||
map.insert(p4);
|
||||
map.insert(p1);
|
||||
map.insert(p3);
|
||||
map.insert(p2);
|
||||
map.insert(p5);
|
||||
// Should print "0 1 2 3 4".
|
||||
for (auto it = map.begin(); it != map.end(); ++it) {
|
||||
print(*it);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Erase the first element.
|
||||
map.erase(map.begin());
|
||||
|
||||
// Erase the new first element.
|
||||
map.erase(map.begin());
|
||||
|
||||
// Erase the element in the end.
|
||||
map.erase(--map.end());
|
||||
// Should print "2 3".
|
||||
for (auto &e : map) {
|
||||
print(e);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Erase all elements.
|
||||
map.erase(map.begin());
|
||||
map.erase(map.begin());
|
||||
// Should print nothing.
|
||||
for (auto &e : map) {
|
||||
print(e);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Stress test Map.
|
||||
*/
|
||||
|
||||
if (iterations > 0) {
|
||||
|
||||
MAP_T<const Stress, double> map;
|
||||
using it_t = typename MAP_T<const Stress, double>::Iterator;
|
||||
using mirror_t = std::map<const Stress, double>;
|
||||
mirror_t mirror;
|
||||
|
||||
using iters_t = std::set<it_t, bool(*)(const it_t &lhs, const it_t &rhs)>;
|
||||
iters_t iters(&less<MAP_T>);
|
||||
|
||||
std::cout << "---- Starting stress test:" << std::endl;
|
||||
|
||||
const int N = iterations;
|
||||
|
||||
srand(9757);
|
||||
int n_inserted = 0, n_erased = 0, n_iters_changed = 0, n_empty = 0, n_dupes = 0;
|
||||
double avg_size = 0;
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
|
||||
double op = drand48();
|
||||
|
||||
// The probability of removal should be slightly higher than the
|
||||
// probability of insertion so that the map is often empty.
|
||||
if (op < .44) {
|
||||
|
||||
// Insert an element. Repeat until no duplicate.
|
||||
do {
|
||||
// Limit the range of values of Stress so that we get some dupes.
|
||||
auto v(std::make_pair(Stress(rand()%50000), drand48()));
|
||||
auto find_it = map.find(v.first);
|
||||
auto it = map.insert(v);
|
||||
auto mir_res = mirror.insert(v);
|
||||
if (mir_res.second) {
|
||||
// If insert into mirror succeeded, insert into the map
|
||||
// should also have succeeded. It should not have
|
||||
// found it before insert.
|
||||
assert(find_it == map.end());
|
||||
// Store the iterator.
|
||||
iters.insert(it.first);
|
||||
break;
|
||||
}
|
||||
// If insert into mirror did not succeed, insert into map
|
||||
// should also not have succeeded, in which case, we
|
||||
// generate another value to store. Also, find should have
|
||||
// found it, and insert should have returned same iterator.
|
||||
assert(find_it == it.first);
|
||||
n_dupes++;
|
||||
} while (true);
|
||||
|
||||
++n_inserted;
|
||||
|
||||
} else if (op < .90) {
|
||||
|
||||
// Erase an element.
|
||||
if (iters.size() != 0) {
|
||||
|
||||
// Pick a random index.
|
||||
int index = rand()%iters.size();
|
||||
typename iters_t::iterator iit = iters.begin();
|
||||
while(index--) {
|
||||
++iit;
|
||||
}
|
||||
|
||||
auto it = *iit;
|
||||
// The iterator should not be end()
|
||||
assert(it != map.end());
|
||||
|
||||
Stress s((*it).first);
|
||||
mirror.erase(s);
|
||||
iters.erase(iit);
|
||||
map.erase(it);
|
||||
|
||||
++n_erased;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Does either postfix or prefix inc/dec operation.
|
||||
auto either_or = [&](it_t &it, it_t &(it_t::*f1)(), it_t (it_t::*f2)(int)) {
|
||||
if (rand()%2 == 0) {
|
||||
(it.*f1)();
|
||||
} else {
|
||||
(it.*f2)(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Increment or decrement an iterator.
|
||||
|
||||
// Size of containers should be same
|
||||
assert(iters.size() == mirror.size());
|
||||
|
||||
// If the container is empty, skip
|
||||
if (iters.size() != 0) {
|
||||
|
||||
// Pick a random index
|
||||
int index = rand()%iters.size();
|
||||
typename iters_t::iterator iters_it = iters.begin();
|
||||
while (index--) {
|
||||
++iters_it;
|
||||
}
|
||||
|
||||
auto it = *iters_it;
|
||||
// The iterator should not be end().
|
||||
assert(it != map.end());
|
||||
|
||||
// If it is the begin(), then only increment,
|
||||
// otherwise, pick either forward or backward.
|
||||
if (it == map.begin()) {
|
||||
either_or(it, &it_t::operator++, &it_t::operator++);
|
||||
++iters_it;
|
||||
} else {
|
||||
if (rand()%2 == 0) {
|
||||
either_or(it, &it_t::operator++, &it_t::operator++);
|
||||
++iters_it;
|
||||
} else {
|
||||
either_or(it, &it_t::operator--, &it_t::operator--);
|
||||
--iters_it;
|
||||
}
|
||||
}
|
||||
// If we didn't hit the end, replace the resulting iterator
|
||||
// in the iterator list.
|
||||
// Note that the set is sorted.
|
||||
if (it != map.end()) {
|
||||
assert(it == *iters_it);
|
||||
iters.erase(iters_it);
|
||||
iters.insert(it);
|
||||
}
|
||||
}
|
||||
|
||||
++n_iters_changed;
|
||||
}
|
||||
|
||||
avg_size += double(iters.size())/N;
|
||||
|
||||
if (iters.size() == 0) {
|
||||
++n_empty;
|
||||
}
|
||||
|
||||
check(map, mirror);
|
||||
}
|
||||
|
||||
std::cout << "inserted: " << n_inserted << " times" << std::endl;
|
||||
std::cout << "erased: " << n_erased << " times" << std::endl;
|
||||
std::cout << "iterators changed: " << n_iters_changed << " times" << std::endl;
|
||||
std::cout << "empty count: " << n_empty << std::endl;
|
||||
std::cout << "avg size: " << avg_size << std::endl;
|
||||
std::cout << "n dupes: " << n_dupes << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Main.
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
|
||||
bool correct_output = false;
|
||||
int iterations = 0;
|
||||
|
||||
{
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "pi:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'p':
|
||||
correct_output = true;
|
||||
break;
|
||||
case 'i':
|
||||
iterations = atoi(optarg);
|
||||
break;
|
||||
case '?':
|
||||
fprintf(stderr, "Unrecog.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srand48(1234);
|
||||
|
||||
if (correct_output) {
|
||||
run_test<test_map>(iterations);
|
||||
} else {
|
||||
run_test<cs440::Map>(iterations);
|
||||
}
|
||||
}
|
||||
|
||||
template <template <typename, typename> class MAP_T>
|
||||
void
|
||||
check(const MAP_T<const Stress, double> &map, const std::map<const Stress, double> &mirror) {
|
||||
|
||||
// Check if the reference container and stress container is identical
|
||||
auto it = map.begin();
|
||||
auto mit = mirror.begin();
|
||||
|
||||
for( ; it != map.end() && mit != mirror.end(); ++it, ++mit) {
|
||||
|
||||
if ((*it).first == (*mit).first) {
|
||||
if ((*it).second == (*mit).second) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Reference tree and test tree differ.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (it != map.end() || mit != mirror.end()) {
|
||||
fprintf(stderr, "Reference tree and test tree differ.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Test single list being traversed by multiple iterators simultaneously.
|
||||
template <template <typename, typename> class MAP_T>
|
||||
void
|
||||
traverse(const MAP_T<const Person, int> &m, int level) {
|
||||
for (auto it = m.begin(); it != m.end(); ++it) {
|
||||
print(*it);
|
||||
if (level != 0) {
|
||||
traverse(m, level - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test multiple lists and multiple iterators.
|
||||
template <template <typename, typename> class MAP_T>
|
||||
void
|
||||
traverse2(int level) {
|
||||
|
||||
MAP_T<const Person, int> map;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char name[30];
|
||||
sprintf(name, "Jane%d", int(10000*drand48()));
|
||||
printf("Generated name: %s\n", name);
|
||||
map.insert(std::make_pair(Person(name), 10*level + i));
|
||||
}
|
||||
|
||||
for (auto &e : map) {
|
||||
print(e);
|
||||
if (level != 0) {
|
||||
traverse2<MAP_T>(level - 1);
|
||||
}
|
||||
}
|
||||
}
|
620
test-scaling.cpp
Normal file
620
test-scaling.cpp
Normal file
|
@ -0,0 +1,620 @@
|
|||
#include "Map.hpp"
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <cxxabi.h>
|
||||
#include <assert.h>
|
||||
#include <map>
|
||||
#include <initializer_list>
|
||||
#include <set>
|
||||
|
||||
//Enables iteration test on a map larger than the memory available to the remote cluster
|
||||
//WARNING: This will be VERY slow.
|
||||
#define DO_BIG_ITERATION_TEST 0
|
||||
|
||||
namespace cs440 {
|
||||
template <typename K, typename V>
|
||||
class StdMapWrapper {
|
||||
private:
|
||||
using base_map = std::map<K, V>;
|
||||
|
||||
public:
|
||||
typedef typename base_map::iterator Iterator;
|
||||
typedef typename base_map::const_iterator ConstIterator;
|
||||
typedef typename base_map::reverse_iterator ReverseIterator;
|
||||
typedef typename base_map::const_reverse_iterator ConstReverseIterator;
|
||||
typedef typename base_map::value_type value_type;
|
||||
typedef typename base_map::mapped_type mapped_type;
|
||||
typedef typename base_map::key_type key_type;
|
||||
|
||||
StdMapWrapper() {}
|
||||
StdMapWrapper(std::initializer_list<std::pair<K,V>> il) {
|
||||
for(auto x : il) {
|
||||
m_map.insert(x);
|
||||
}
|
||||
}
|
||||
|
||||
StdMapWrapper(StdMapWrapper &&other)
|
||||
: m_map(std::move(other.m_map))
|
||||
{}
|
||||
|
||||
StdMapWrapper(const StdMapWrapper &other)
|
||||
: m_map(other.m_map)
|
||||
{}
|
||||
|
||||
StdMapWrapper &operator=(const StdMapWrapper &other) {
|
||||
if(this != &other) {
|
||||
StdMapWrapper tmp(other);
|
||||
std::swap(m_map, tmp.m_map);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
StdMapWrapper &operator=(const StdMapWrapper &&other) {
|
||||
StdMapWrapper tmp(other);
|
||||
std::swap(tmp.m_map, m_map);
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////// Iterators
|
||||
Iterator begin() {
|
||||
return m_map.begin();
|
||||
}
|
||||
|
||||
ConstIterator begin() const {
|
||||
return m_map.begin();
|
||||
}
|
||||
|
||||
ConstIterator cbegin() const {
|
||||
return m_map.begin();
|
||||
}
|
||||
|
||||
ReverseIterator rbegin() {
|
||||
return m_map.rbegin();
|
||||
}
|
||||
|
||||
/*
|
||||
ConstReverseIterator rbegin() const {
|
||||
return m_map.rbegin();
|
||||
}
|
||||
|
||||
ConstReverseIterator crbegin() const {
|
||||
return m_map.crbegin();
|
||||
}
|
||||
*/
|
||||
|
||||
Iterator end() {
|
||||
return m_map.end();
|
||||
}
|
||||
|
||||
ConstIterator end() const {
|
||||
return m_map.end();
|
||||
}
|
||||
|
||||
ConstIterator cend() const {
|
||||
return m_map.cend();
|
||||
}
|
||||
|
||||
ReverseIterator rend() {
|
||||
return m_map.rend();
|
||||
}
|
||||
|
||||
/*
|
||||
ConstReverseIterator rend() const {
|
||||
return m_map.rend();
|
||||
}
|
||||
|
||||
ConstReverseIterator crend() const {
|
||||
return m_map.crend();
|
||||
}
|
||||
*/
|
||||
|
||||
///////// Capacity
|
||||
size_t size() const {
|
||||
return m_map.size();
|
||||
}
|
||||
|
||||
size_t max_size() const {
|
||||
return m_map.max_size();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return m_map.empty();
|
||||
}
|
||||
|
||||
|
||||
///////// Modifiers
|
||||
Iterator insert(const value_type &value) {
|
||||
return m_map.insert(value).first;
|
||||
}
|
||||
|
||||
Iterator insert(value_type &&value) {
|
||||
return m_map.insert(std::move(value)).first;
|
||||
}
|
||||
|
||||
void erase(const K &k) {
|
||||
m_map.erase(k);
|
||||
}
|
||||
|
||||
|
||||
void erase(Iterator it) {
|
||||
m_map.erase(it);
|
||||
}
|
||||
|
||||
///////// Lookup
|
||||
V &at(const K &k) {
|
||||
return m_map.at(k);
|
||||
}
|
||||
|
||||
const V &at(const K &k) const {
|
||||
return m_map.at(k);
|
||||
}
|
||||
|
||||
Iterator find(const K &k) {
|
||||
return m_map.find(k);
|
||||
}
|
||||
|
||||
ConstIterator find(const K &k) const {
|
||||
return m_map.find(k);
|
||||
}
|
||||
|
||||
V &operator[](const K &k) {
|
||||
return m_map[k];
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
base_map m_map;
|
||||
|
||||
template<typename A, typename B>
|
||||
friend
|
||||
bool operator==(const StdMapWrapper<A,B>&, const StdMapWrapper<A,B>&);
|
||||
|
||||
template<typename A, typename B>
|
||||
friend bool operator!=(const StdMapWrapper<A,B>&, const StdMapWrapper<A,B>&);
|
||||
template<typename A, typename B>
|
||||
friend bool operator<=(const StdMapWrapper<A,B>&, const StdMapWrapper<A,B>&);
|
||||
template<typename A, typename B>
|
||||
friend bool operator<(const StdMapWrapper<A,B>&, const StdMapWrapper<A,B>&);
|
||||
template<typename A, typename B>
|
||||
friend bool operator>=(const StdMapWrapper<A,B>&, const StdMapWrapper<A,B>&);
|
||||
template<typename A, typename B>
|
||||
friend bool operator>(const StdMapWrapper<A,B>&, const StdMapWrapper<A,B>&);
|
||||
};
|
||||
|
||||
template<typename K, typename T>
|
||||
bool operator==(const StdMapWrapper<K,T> &a, const StdMapWrapper<K,T> &b) {
|
||||
return a.m_map == b.m_map;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
bool operator!=(const StdMapWrapper<K,T> &a, const StdMapWrapper<K,T> &b) {
|
||||
return a.m_map != b.m_map;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
bool operator<=(const StdMapWrapper<K,T> &a, const StdMapWrapper<K,T> &b) {
|
||||
return a.m_map <= b.m_map;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
bool operator<(const StdMapWrapper<K,T> &a, const StdMapWrapper<K,T> &b) {
|
||||
return a.m_map < b.m_map;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
bool operator>=(const StdMapWrapper<K,T> &a, const StdMapWrapper<K,T> &b) {
|
||||
return a.m_map >= b.m_map;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
bool operator>(const StdMapWrapper<K,T> &a, const StdMapWrapper<K,T> &b) {
|
||||
return a.m_map > b.m_map;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using Milli = std::chrono::duration<double, std::ratio<1,1000>>;
|
||||
using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
|
||||
|
||||
void dispTestName(const char *testName, const char *typeName) {
|
||||
std::cout << std::endl << std::endl << "************************************" << std::endl;
|
||||
std::cout << "\t" << testName << " for " << typeName << "\t" << std::endl;
|
||||
std::cout << "************************************" << std::endl << std::endl;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T ascendingInsert(int count, bool print = true) {
|
||||
using namespace std::chrono;
|
||||
TimePoint start, end;
|
||||
start = system_clock::now();
|
||||
T map;
|
||||
for(int i = 0; i < count; i++) {
|
||||
map.insert(std::pair<int, int>(i,i));
|
||||
}
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed = end - start;
|
||||
|
||||
if(print)
|
||||
std::cout << "Inserting " << count << " elements in aescending order took " << elapsed.count() << " milliseconds" << std::endl;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T descendingInsert(int count, bool print = true) {
|
||||
using namespace std::chrono;
|
||||
TimePoint start, end;
|
||||
start = system_clock::now();
|
||||
T map;
|
||||
for(int i = count; i > 0; i--) {
|
||||
map.insert(std::pair<int, int>(i,i));
|
||||
}
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed = end - start;
|
||||
|
||||
if(print)
|
||||
std::cout << "Inserting " << count << " elements in descending order took " << elapsed.count() << " milliseconds" << std::endl;
|
||||
return map;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deleteTest() {
|
||||
using namespace std::chrono;
|
||||
TimePoint start, end;
|
||||
T m1 = ascendingInsert<T>(10000, false);
|
||||
T m2 = ascendingInsert<T>(100000, false);
|
||||
T m3 = ascendingInsert<T>(1000000, false);
|
||||
T m4 = ascendingInsert<T>(10000000, false);
|
||||
|
||||
std::set<int> toDelete;
|
||||
for(int i = 0; i < 10000; i++) {
|
||||
toDelete.insert(i);
|
||||
}
|
||||
|
||||
start = system_clock::now();
|
||||
for(const int e : toDelete)
|
||||
m1.erase(e);
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed1 = end - start;
|
||||
|
||||
std::cout << "deleting 10000 elements from a map of size 10000 took " << elapsed1.count() << " milliseconds" << std::endl;
|
||||
|
||||
{
|
||||
toDelete.clear();
|
||||
std::default_random_engine generator;
|
||||
std::uniform_int_distribution<int> distribution(0,99999);
|
||||
while(toDelete.size() < 10000) {
|
||||
toDelete.insert(distribution(generator));
|
||||
}
|
||||
}
|
||||
|
||||
start = system_clock::now();
|
||||
for(const int e : toDelete)
|
||||
m2.erase(e);
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed2 = end - start;
|
||||
|
||||
std::cout << "deleting 10000 elements from a map of size 100000 took " << elapsed2.count() << " milliseconds" << std::endl;
|
||||
|
||||
{
|
||||
toDelete.clear();
|
||||
std::default_random_engine generator;
|
||||
std::uniform_int_distribution<int> distribution(0,999999);
|
||||
while(toDelete.size() < 10000) {
|
||||
toDelete.insert(distribution(generator));
|
||||
}
|
||||
}
|
||||
|
||||
start = system_clock::now();
|
||||
for(const int e : toDelete)
|
||||
m3.erase(e);
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed3 = end - start;
|
||||
|
||||
std::cout << "deleting 10000 elements from a map of size 1000000 took " << elapsed3.count() << " milliseconds" << std::endl;
|
||||
|
||||
{
|
||||
toDelete.clear();
|
||||
std::default_random_engine generator;
|
||||
std::uniform_int_distribution<int> distribution(0,9999999);
|
||||
while(toDelete.size() < 10000) {
|
||||
toDelete.insert(distribution(generator));
|
||||
}
|
||||
}
|
||||
|
||||
start = system_clock::now();
|
||||
for(const int e : toDelete)
|
||||
m4.erase(e);
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed4 = end - start;
|
||||
|
||||
std::cout << "deleting 10000 elements from a map of size 10000000 took " << elapsed4.count() << " milliseconds" << std::endl;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void findTest() {
|
||||
using namespace std::chrono;
|
||||
TimePoint start, end;
|
||||
T m1 = ascendingInsert<T>(10000, false);
|
||||
T m2 = ascendingInsert<T>(100000, false);
|
||||
T m3 = ascendingInsert<T>(1000000, false);
|
||||
T m4 = ascendingInsert<T>(10000000, false);
|
||||
T m11;
|
||||
T m22;
|
||||
T m33;
|
||||
T m44;
|
||||
|
||||
std::vector<int> toFind;
|
||||
for(int i = 0; i < 10000; i++) {
|
||||
toFind.push_back(i);
|
||||
}
|
||||
|
||||
start = system_clock::now();
|
||||
for(const int e : toFind) {
|
||||
auto it = m1.find(e);
|
||||
m11.insert(*it);
|
||||
}
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed1 = end - start;
|
||||
|
||||
std::cout << "Finding 10000 elements from a map of size " << m1.size() << " took " << elapsed1.count() << " milliseconds" << std::endl;
|
||||
|
||||
{
|
||||
toFind.clear();
|
||||
std::default_random_engine generator;
|
||||
std::uniform_int_distribution<int> distribution(0,99999);
|
||||
while(toFind.size() < 10000) {
|
||||
toFind.push_back(distribution(generator));
|
||||
}
|
||||
}
|
||||
|
||||
start = system_clock::now();
|
||||
for(const int e : toFind) {
|
||||
auto it = m2.find(e);
|
||||
m22.insert(*it);
|
||||
}
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed2 = end - start;
|
||||
|
||||
std::cout << "Finding 10000 elements from a map of size " << m2.size() << " took " << elapsed2.count() << " milliseconds" << std::endl;
|
||||
|
||||
{
|
||||
toFind.clear();
|
||||
std::default_random_engine generator;
|
||||
std::uniform_int_distribution<int> distribution(0,999999);
|
||||
while(toFind.size() < 10000) {
|
||||
toFind.push_back(distribution(generator));
|
||||
}
|
||||
}
|
||||
|
||||
start = system_clock::now();
|
||||
for(const int e : toFind) {
|
||||
auto it = m3.find(e);
|
||||
m33.insert(*it);
|
||||
}
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed3 = end - start;
|
||||
|
||||
std::cout << "Finding 10000 elements from a map of size " << m3.size() << " took " << elapsed3.count() << " milliseconds" << std::endl;
|
||||
|
||||
{
|
||||
toFind.clear();
|
||||
std::default_random_engine generator;
|
||||
std::uniform_int_distribution<int> distribution(0,9999999);
|
||||
while(toFind.size() < 10000) {
|
||||
toFind.push_back(distribution(generator));
|
||||
}
|
||||
}
|
||||
|
||||
start = system_clock::now();
|
||||
for(const int e : toFind) {
|
||||
auto it = m4.find(e);
|
||||
m44.insert(*it);
|
||||
}
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed4 = end - start;
|
||||
|
||||
std::cout << "Finding 10000 elements from a map of size " << m4.size() << " took " << elapsed4.count() << " milliseconds" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void iterationTest(int count) {
|
||||
using namespace std::chrono;
|
||||
T m = ascendingInsert<T>(count,false);
|
||||
|
||||
TimePoint start, end;
|
||||
|
||||
for(int j = 0; j < 3; j++) {
|
||||
start = system_clock::now();
|
||||
for(auto it = m.begin(); it != m.end(); it++) {
|
||||
if(j==2)
|
||||
(*it).second += j;
|
||||
}
|
||||
end = system_clock::now();
|
||||
}
|
||||
|
||||
Milli elapsed = end - start;
|
||||
|
||||
std::cout << "Iterating across " << count << " elements in a map of size " << count << " took " << elapsed.count() << " milliseconds time per iteration was " << elapsed.count()/double(count)*1e6 << " nanoseconds" << std::endl;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void copyTest(int count) {
|
||||
using namespace std::chrono;
|
||||
T m = ascendingInsert<T>(count,false);
|
||||
|
||||
TimePoint start, end;
|
||||
|
||||
start = system_clock::now();
|
||||
T m2(m);
|
||||
end = system_clock::now();
|
||||
|
||||
Milli elapsed = end - start;
|
||||
|
||||
std::cout << "Copy construction of a map of size " << m2.size() << " took " << elapsed.count() << " milliseconds" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
#include <assert.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
ostream &
|
||||
operator<<(ostream &os, const type_info &ti) {
|
||||
int ec;
|
||||
const char *demangled_name = abi::__cxa_demangle(ti.name(), 0, 0, &ec);
|
||||
assert(ec == 0);
|
||||
os << demangled_name;
|
||||
free((void *) demangled_name);
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void foo(T &&o) {
|
||||
//o = 2;
|
||||
cout << typeid(const int &) << endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
const int i = 1;
|
||||
foo(i);
|
||||
}
|
||||
*/
|
||||
|
||||
class comma_numpunct : public std::numpunct<char> {
|
||||
protected:
|
||||
virtual char do_thousands_sep() const { return ','; }
|
||||
virtual std::string do_grouping() const { return "\03"; }
|
||||
};
|
||||
|
||||
|
||||
int main() {
|
||||
//separate all printed numbers with commas
|
||||
std::locale comma_locale(std::locale(), new comma_numpunct());
|
||||
std::cout.imbue(comma_locale);
|
||||
|
||||
auto demangle = [](const std::type_info &ti) {
|
||||
int ec;
|
||||
return abi::__cxa_demangle(ti.name(), 0, 0, &ec);
|
||||
assert(ec == 0);
|
||||
};
|
||||
|
||||
const char *w = demangle(typeid(cs440::StdMapWrapper<int,int>));
|
||||
const char *m = demangle(typeid(cs440::Map<int,int>));
|
||||
|
||||
{
|
||||
dispTestName("Ascending insert", m);
|
||||
ascendingInsert<cs440::Map<int,int>>(1000);
|
||||
ascendingInsert<cs440::Map<int,int>>(10000);
|
||||
ascendingInsert<cs440::Map<int,int>>(100000);
|
||||
ascendingInsert<cs440::Map<int,int>>(1000000);
|
||||
ascendingInsert<cs440::Map<int,int>>(10000000);
|
||||
dispTestName("Ascending insert", w);
|
||||
ascendingInsert<cs440::StdMapWrapper<int,int>>(1000);
|
||||
ascendingInsert<cs440::StdMapWrapper<int,int>>(10000);
|
||||
ascendingInsert<cs440::StdMapWrapper<int,int>>(100000);
|
||||
ascendingInsert<cs440::StdMapWrapper<int,int>>(1000000);
|
||||
ascendingInsert<cs440::StdMapWrapper<int,int>>(10000000);
|
||||
}
|
||||
|
||||
{
|
||||
dispTestName("Descending insert", m);
|
||||
descendingInsert<cs440::Map<int,int>>(1000);
|
||||
descendingInsert<cs440::Map<int,int>>(10000);
|
||||
descendingInsert<cs440::Map<int,int>>(100000);
|
||||
descendingInsert<cs440::Map<int,int>>(1000000);
|
||||
descendingInsert<cs440::Map<int,int>>(10000000);
|
||||
dispTestName("Descending insert", w);
|
||||
descendingInsert<cs440::StdMapWrapper<int,int>>(1000);
|
||||
descendingInsert<cs440::StdMapWrapper<int,int>>(10000);
|
||||
descendingInsert<cs440::StdMapWrapper<int,int>>(100000);
|
||||
descendingInsert<cs440::StdMapWrapper<int,int>>(1000000);
|
||||
descendingInsert<cs440::StdMapWrapper<int,int>>(10000000);
|
||||
}
|
||||
|
||||
{
|
||||
dispTestName("Delete test", m);
|
||||
deleteTest<cs440::Map<int,int>>();
|
||||
dispTestName("Delete test", w);
|
||||
deleteTest<cs440::StdMapWrapper<int,int>>();
|
||||
}
|
||||
|
||||
{
|
||||
dispTestName("Find test", m);
|
||||
findTest<cs440::Map<int,int>>();
|
||||
dispTestName("Find test", w);
|
||||
findTest<cs440::StdMapWrapper<int,int>>();
|
||||
}
|
||||
|
||||
/*
|
||||
Remember that some of these maps get quite large - iteration times may be affected by things other than the scaling of your algorithm.
|
||||
How do the many levels of the memory heirarchy in a computer relate?
|
||||
How do they perform relative to one another?
|
||||
How might this have affected other performance tests?
|
||||
*/
|
||||
{
|
||||
dispTestName("Iteration test", m);
|
||||
iterationTest<cs440::Map<int,int>>(10000);
|
||||
iterationTest<cs440::Map<int,int>>(20000);
|
||||
iterationTest<cs440::Map<int,int>>(40000);
|
||||
iterationTest<cs440::Map<int,int>>(80000);
|
||||
iterationTest<cs440::Map<int,int>>(160000);
|
||||
iterationTest<cs440::Map<int,int>>(320000);
|
||||
iterationTest<cs440::Map<int,int>>(640000);
|
||||
iterationTest<cs440::Map<int,int>>(1280000);
|
||||
iterationTest<cs440::Map<int,int>>(2560000);
|
||||
iterationTest<cs440::Map<int,int>>(5120000);
|
||||
#if DO_BIG_ITERATION_TEST
|
||||
//Optional test. This is more ram than the remote machines have and will likely take a long time to run.
|
||||
iterationTest<cs440::Map<int,int>>(600000000);
|
||||
#endif
|
||||
dispTestName("Iteration test", w);
|
||||
iterationTest<cs440::StdMapWrapper<int,int>>(10000);
|
||||
iterationTest<cs440::StdMapWrapper<int,int>>(20000);
|
||||
iterationTest<cs440::StdMapWrapper<int,int>>(40000);
|
||||
iterationTest<cs440::StdMapWrapper<int,int>>(80000);
|
||||
iterationTest<cs440::StdMapWrapper<int,int>>(160000);
|
||||
iterationTest<cs440::StdMapWrapper<int,int>>(320000);
|
||||
iterationTest<cs440::StdMapWrapper<int,int>>(640000);
|
||||
iterationTest<cs440::StdMapWrapper<int,int>>(1280000);
|
||||
iterationTest<cs440::StdMapWrapper<int,int>>(5120000);
|
||||
#if DO_BIG_ITERATION_TEST
|
||||
//Optional test. This is more ram than the remote machines have and will likely take a long time to run.
|
||||
iterationTest<cs440::Map<int,int>>(600000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
//Test copy constructor scaling
|
||||
dispTestName("Copy test", m);
|
||||
copyTest<cs440::Map<int,int>>(10000);
|
||||
copyTest<cs440::Map<int,int>>(100000);
|
||||
copyTest<cs440::Map<int,int>>(1000000);
|
||||
copyTest<cs440::Map<int,int>>(10000000);
|
||||
dispTestName("Copy test", w);
|
||||
copyTest<cs440::StdMapWrapper<int,int>>(10000);
|
||||
copyTest<cs440::StdMapWrapper<int,int>>(100000);
|
||||
copyTest<cs440::StdMapWrapper<int,int>>(1000000);
|
||||
copyTest<cs440::StdMapWrapper<int,int>>(10000000);
|
||||
}
|
||||
|
||||
//Add your own indexibility scaling test here
|
||||
|
||||
// Cast, due to const-ness.
|
||||
free((void *) w);
|
||||
free((void *) m);
|
||||
}
|
140
test.cpp
Normal file
140
test.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include "Map.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
void stress(int stress_size) {
|
||||
auto seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
std::default_random_engine gen(seed);
|
||||
std::uniform_int_distribution<unsigned int> dist(0, 10000);
|
||||
|
||||
cs440::Map<int, int> m;
|
||||
|
||||
for(int i = 0; i < stress_size; ++i) {
|
||||
auto g = dist(gen);
|
||||
m.insert({g, g});
|
||||
}
|
||||
|
||||
int num_erases = gen() % m.size();
|
||||
for(int i = 0; i < num_erases; ++i) {
|
||||
//select a random element
|
||||
int choice = gen() % m.size();
|
||||
auto iter = std::begin(m);
|
||||
for (int j = 0; j < choice; ++j) {
|
||||
++iter;
|
||||
}
|
||||
|
||||
m.erase(iter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// unrealistic examples
|
||||
void access_by_key() {
|
||||
cs440::Map<int, long> m;
|
||||
m.insert({10, 10});
|
||||
m.insert({3, 3});
|
||||
m.insert({20, 20});
|
||||
m.insert({15, 15});
|
||||
|
||||
m.at(10);
|
||||
bool thrown = false;
|
||||
try {
|
||||
m.at(10000);
|
||||
} catch (std::out_of_range) {
|
||||
thrown = true;
|
||||
}
|
||||
assert(thrown); // the .at should have thrown an exception
|
||||
|
||||
const auto& m_ref = m;
|
||||
m_ref.at(10); // const .at
|
||||
|
||||
auto iter = m.find(3);
|
||||
assert((*iter).second == 3);
|
||||
|
||||
auto iter2 = m.find(100000); // not in map, should give iterator to end()
|
||||
assert(iter2 == std::end(m));
|
||||
|
||||
m[30] = 30; // should default construct
|
||||
|
||||
m.erase(10);
|
||||
assert(m.find(10) == std::end(m)); // 10 shouldn't be in the map anymore
|
||||
}
|
||||
|
||||
void count_words() {
|
||||
cs440::Map<std::string, int> words_count;
|
||||
|
||||
// just a big list of words
|
||||
auto words = {"this", "is", "a", "string", "with", "words", "some",
|
||||
"words", "in", "the", "string", "repeat", "the", "more", "they",
|
||||
"repeat", "the", "more", "they", "should", "count", "they", "more",
|
||||
"they", "count", "the", "more", "they", "will", "have", "their",
|
||||
"count", "increased"};
|
||||
|
||||
for (auto& word : words) {
|
||||
// this works because int can be default constructed, and the
|
||||
// default of int (by doing int{} ) is 0.
|
||||
words_count[word] += 1; // add 1 to the count
|
||||
}
|
||||
|
||||
// print the frequency of each word
|
||||
std::cout << "word frequency:\n";
|
||||
for (auto& count : words_count) { // uses .begin() and .end()
|
||||
std::cout << count.first << ": " << count.second << '\n';
|
||||
}
|
||||
|
||||
std::cout << "word frequency reversed order:\n";
|
||||
for (auto riter = words_count.rbegin();
|
||||
riter != words_count.rend();
|
||||
++riter) {
|
||||
std::cout << (*riter).first << ": " << (*riter).second << '\n';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// creates a mapping from the values in the range [low, high) to their cubes
|
||||
cs440::Map<int, int> cubes(int low, int high) {
|
||||
cs440::Map<int, int> cb;
|
||||
for (int i = low; i < high; ++i) {
|
||||
cb.insert({i, i*i*i});
|
||||
}
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
|
||||
int main () {
|
||||
count_words();
|
||||
|
||||
auto cube = cubes(-5, 10); // move construct returned value
|
||||
std::cout << cube.at(-2) << '\n'; // -8
|
||||
std::cout << cube.at(5) << '\n'; // 125
|
||||
const int n = 30;
|
||||
try {
|
||||
std::cout << cube.at(n) << '\n'; // 30 is not in the Map
|
||||
} catch (std::out_of_range) {
|
||||
std::cout << n << " not in cubes range\n";
|
||||
}
|
||||
|
||||
// constructors and assignment examples:
|
||||
// initializer_list example
|
||||
cs440::Map<int, double> int_double_map {{1, 1.0}, {3, 5.67}, {13, 6.9}};
|
||||
|
||||
// must support copy construction
|
||||
cs440::Map<int, double> copy_example{int_double_map};
|
||||
|
||||
cs440::Map<int, double> assign_example;
|
||||
// must support copy assignment
|
||||
assign_example = copy_example;
|
||||
|
||||
access_by_key();
|
||||
stress(10000);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue