#include <iostream>
#include <chrono>
#include <map>
#include <unordered_map>
#include <string>
#include <random>
#include <algorithm>
template <class T, class ValueType>
class StrongType
{
public:
inline explicit operator ValueType() const { return _value;}
inline bool operator == (const StrongType &other) const
{
return _value == other._value;
}
inline bool operator != (const StrongType &other) const
{
return _value != other._value;
}
inline bool operator < (const StrongType &other) const
{
return _value < other._value;;
}
inline bool operator > (const StrongType &other) const
{
return _value > other._value;
}
inline bool operator <= (const StrongType &other) const
{
return _value <= other._value;
}
inline bool operator >= (const StrongType &other) const
{
return _value >= other._value;
}
protected:
explicit StrongType(ValueType value):_value(value) {}
private:
ValueType _value;
};
template <class T, class ValueType = int>
class StringCache
{
public:
static_assert(std::is_integral<ValueType>::value, "not integral type");
class Type: public StrongType<T,ValueType>
{
friend class StringCache;
public:
explicit operator bool() const { return static_cast<ValueType>(*this)!=0; }
private:
explicit Type(ValueType value):StrongType<T,ValueType>(value){}
};
static Type get(const std::string &value)
{
return Type(_values.insert(std::make_pair(value, _values.size() + 1)).first->second);
}
static Type find(const std::string &value)
{
std::map<std::string,int>::const_iterator it =_values.find(value);
if(it == _values.end())
return Type(0);
else
return Type(it->second);
}
static const std::string& to_string(const Type &type)
{
static const std::string empty;
if(static_cast<ValueType>(type)>=_values.size())
return empty;
for(const auto &it:_values)
if(it.second == static_cast<ValueType>(type))
return it.first;
return empty;
}
private:
static std::map<std::string,int> _values;
};
template <class T, class ValueType>
std::map<std::string,int> StringCache<T,ValueType>::_values;
class EventType:public StringCache<EventType>{};
class Script
{
public:
Script(int val):_value(val)
{
}
int execute() const
{
return _value;
}
private:
int _value;
};
class Object
{
public:
int execute(const std::string &id) const
{
auto it = _events.find(id);
if(it!=_events.end())
{
return it->second.execute();
}
return 0;
}
void addevent(const std::string &event, const Script &script)
{
_events.insert(std::make_pair(event, script));
}
private:
std::map<std::string, Script> _events;
};
class HashObject
{
public:
int execute(const std::string &id) const
{
auto it = _events.find(id);
if(it!=_events.end())
{
return it->second.execute();
}
return 0;
}
void addevent(const std::string &event, const Script &script)
{
_events.insert(std::make_pair(event, script));
}
private:
std::unordered_map<std::string, Script> _events;
};
class FastObject
{
public:
int execute(EventType::Type id) const
{
auto it = _events.find(id);
if(it!=_events.end())
{
return it->second.execute();
}
return 0;
}
void addevent(EventType::Type event, const Script &script)
{
_events.insert(std::make_pair(event, script));
}
private:
std::map<EventType::Type, Script> _events;
};
struct event_descriptor
{
std::string str;
size_t hash;
bool operator ==(const event_descriptor&other) const
{
return other.hash == hash && other.str == str;
}
bool operator <(const event_descriptor&other) const
{
return (hash==other.hash)?str<other.str:(hash<other.hash);
}
};
struct descriptor_hasher
{
size_t operator()(const event_descriptor& desc) const { return desc.hash; };
};
event_descriptor make_descriptor(const std::string &arg)
{
auto hash = std::hash<std::string>()(arg);
return event_descriptor{arg, hash};
}
class HashObject2
{
public:
int execute(const event_descriptor &id) const
{
auto it = _events.find(id);
if(it!=_events.end())
{
return it->second.execute();
}
return 0;
}
void addevent(const event_descriptor &event, const Script &script)
{
_events.insert(std::make_pair(event, script));
}
private:
std::unordered_map<event_descriptor, Script, descriptor_hasher> _events;
};
class HashObject3
{
public:
int execute(const event_descriptor &id) const
{
auto it = _events.find(id);
if(it!=_events.end())
{
return it->second.execute();
}
return 0;
}
void addevent(const event_descriptor &event, const Script &script)
{
_events.insert(std::make_pair(event, script));
}
private:
std::map<event_descriptor, Script> _events;
};
std::vector<std::string> eventIds= {
"event00",
"event01",
"event02",
"event03",
"event04",
"event05",
"event06",
"event07",
"event08",
"event09",
"event00",
"event11",
"event12",
"event13",
"event14",
"event15",
"event16",
"event17",
"event18",
"event19",
"event20",
"event21",
"event22",
"event23",
"event24",
"event25"
};
int main(int argc, const char * argv[])
{
std::random_device rd;
std::default_random_engine engine(rd());
std::vector<int> ids{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
std::vector<Object> objects;
std::vector<FastObject> fast_objects;
std::vector<HashObject> hash_objects;
std::vector<HashObject2> hash_objects2;
std::vector<HashObject3> hash_objects3;
const static int max_objects = 1000;
const static int iter_count = 100;
const static int repeat_count = 1;
objects.reserve(max_objects);
fast_objects.reserve(max_objects);
hash_objects.reserve(max_objects);
hash_objects2.reserve(max_objects);
for(int i=0;i<max_objects;++i)
{
std::shuffle(ids.begin(), ids.end(), engine);
Object obj1;
HashObject obj2;
FastObject obj3;
HashObject2 obj4;
HashObject3 obj5;
for(int j=0;j<10;++j) //add first 10 elemtnts not all object has all events
{
obj1.addevent(eventIds[ids[j]], Script(j));
obj2.addevent(eventIds[ids[j]], Script(j));
obj3.addevent(EventType::get(eventIds[ids[j]]), Script(j));
obj4.addevent(make_descriptor(eventIds[ids[j]]), Script(j));
obj5.addevent(make_descriptor(eventIds[ids[j]]), Script(j));
}
objects.push_back(obj1);
hash_objects.push_back(obj2);
fast_objects.push_back(obj3);
hash_objects2.push_back(obj4);
hash_objects3.push_back(obj5);
}
std::vector<std::string> events;
events.reserve(eventIds.size()*iter_count);
for(int i=0;i<iter_count;++i)
for(const auto &it:eventIds)
{
events.push_back(it);
}
int ret1 = 0;
int ret2 = 0;
int ret3 = 0;
int ret4 = 0;
int ret5 = 0;
std::chrono::high_resolution_clock::time_point t = std::chrono::high_resolution_clock::now();
for(int i=0;i<repeat_count;++i)
for(const auto &event:events)
{
for(const auto &object:objects)
{
ret1 += object.execute(event);
}
}
auto duration = std::chrono::high_resolution_clock::now() - t;
std::cout << "map: " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << ":" << ret1 << std::endl;
t = std::chrono::high_resolution_clock::now();
for(int i=0;i<repeat_count;++i)
for(const auto &event:events)
{
for(const auto &object:hash_objects)
{
ret2 += object.execute(event);
}
}
duration = std::chrono::high_resolution_clock::now() - t;
std::cout << "unodered_map: " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << ":" << ret2 << std::endl;
t = std::chrono::high_resolution_clock::now();
for(int i=0;i<repeat_count;++i)
for(const auto &event:events)
{
EventType::Type eventId = EventType::find(event);
if(eventId) //possible that no one has this id
for(const auto &object:fast_objects)
{
ret3 += object.execute(eventId);
}
}
duration = std::chrono::high_resolution_clock::now() - t;
std::cout << "map+EventType: " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << ":" << ret3 << std::endl;
t = std::chrono::high_resolution_clock::now();
for(int i=0;i<repeat_count;++i)
for(const auto &event:events)
{
event_descriptor eventId1 = make_descriptor(event);
for(const auto &object:hash_objects2)
{
ret4 += object.execute(eventId1);
}
}
duration = std::chrono::high_resolution_clock::now() - t;
std::cout << "unordered_map+event_descriptor: " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << ":" << ret4 << std::endl;
t = std::chrono::high_resolution_clock::now();
for(int i=0;i<repeat_count;++i)
for(const auto &event:events)
{
event_descriptor eventId2 = make_descriptor(event);
for(const auto &object:hash_objects3)
{
ret5 += object.execute(eventId2);
}
}
duration = std::chrono::high_resolution_clock::now() - t;
std::cout << "map+event_descriptor: " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << ":" << ret5 << std::endl;
return 0;
}