committing more tests

This commit is contained in:
Pagwin 2024-11-24 22:25:54 -05:00
parent 9271042e78
commit 315a200c9b
No known key found for this signature in database
GPG key ID: 81137023740CA260
6 changed files with 1604 additions and 0 deletions

122
minimal.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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;
}