Created
May 20, 2016 16:44
-
-
Save oilandrust/e8b4202ce8786ce85a58ee075defc851 to your computer and use it in GitHub Desktop.
Bistsui DataComponent
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cassert> | |
#include <chrono> | |
#include <cstdio> | |
#include <iostream> | |
#include <map> | |
#include <string> | |
#include <vector> | |
enum class DataType { | |
BOOL, | |
FLOAT, | |
STRING, | |
OBJECT, | |
ARRAY | |
}; | |
struct StdDataValue { | |
~StdDataValue() | |
{ | |
if (type == DataType::OBJECT) { | |
delete o; | |
return; | |
} | |
if (type == DataType::ARRAY) { | |
delete a; | |
return; | |
} | |
if (type == DataType::STRING) { | |
delete s; | |
return; | |
} | |
} | |
StdDataValue() | |
: type(DataType::BOOL) | |
, b(false) | |
{ | |
} | |
StdDataValue& operator=(const StdDataValue& other) | |
{ | |
if (&other == this) | |
return *this; | |
type = other.type; | |
switch (type) { | |
case DataType::OBJECT: | |
o = new std::map<std::string, StdDataValue>(*(other.o)); | |
break; | |
case DataType::ARRAY: | |
a = new std::vector<float>(*(other.a)); | |
break; | |
case DataType::STRING: | |
s = new std::string(*(other.s)); | |
break; | |
case DataType::FLOAT: | |
f = other.f; | |
break; | |
case DataType::BOOL: | |
b = other.b; | |
break; | |
} | |
return *this; | |
} | |
StdDataValue(const StdDataValue& other) | |
: type(other.type) | |
{ | |
switch (type) { | |
case DataType::OBJECT: | |
o = new std::map<std::string, StdDataValue>(*(other.o)); | |
break; | |
case DataType::ARRAY: | |
a = new std::vector<float>(*(other.a)); | |
break; | |
case DataType::STRING: | |
s = new std::string(*(other.s)); | |
break; | |
case DataType::FLOAT: | |
f = other.f; | |
break; | |
case DataType::BOOL: | |
b = other.b; | |
break; | |
} | |
} | |
StdDataValue(DataType _type) | |
{ | |
type = _type; | |
switch (type) { | |
case DataType::OBJECT: | |
o = new std::map<std::string, StdDataValue>; | |
break; | |
case DataType::ARRAY: | |
a = new std::vector<float>; | |
break; | |
case DataType::STRING: | |
s = new std::string; | |
break; | |
default: | |
f = 0.0f; | |
} | |
} | |
StdDataValue(float val) | |
: type(DataType::FLOAT) | |
, f(val) | |
{ | |
} | |
StdDataValue(bool val) | |
: type(DataType::BOOL) | |
, b(val) | |
{ | |
} | |
StdDataValue(const std::string& val) | |
: type(DataType::STRING) | |
, s(new std::string(val)) | |
{ | |
} | |
operator bool() const { return b; } | |
operator float() const { return f; } | |
operator std::string() const { return *s; } | |
void insert(const std::string& key, const StdDataValue& value) | |
{ | |
assert(type == DataType::OBJECT); | |
(*o)[key] = value; | |
} | |
StdDataValue& insertObject(const std::string& key) | |
{ | |
assert(type == DataType::OBJECT); | |
auto pit = o->emplace(key, DataType::OBJECT); | |
return pit.first->second; | |
} | |
StdDataValue& get(const std::string& key) | |
{ | |
auto it = o->find(key); | |
assert(it != o->end()); | |
return it->second; | |
} | |
std::string& getString(const std::string& key) | |
{ | |
auto it = o->find(key); | |
assert(it != o->end()); | |
return *(it->second).s; | |
} | |
DataType type; | |
union { | |
bool b; | |
float f; | |
std::string* s; | |
std::map<std::string, StdDataValue>* o; | |
std::vector<float>* a; | |
}; | |
}; | |
struct Value { | |
union { | |
bool b; | |
float f; | |
std::string* s; | |
std::vector<float>* array; | |
}; | |
operator bool() const { return b; } | |
operator float() const { return f; } | |
operator std::string() const { return *s; } | |
}; | |
unsigned int hash(const char* key) { | |
static std::hash<std::string> hashFun; | |
return hashFun(key); | |
} | |
struct Object1 { | |
std::vector<unsigned> keys; | |
std::vector<DataType> types; | |
std::vector<Value> values; | |
Value get(const char* key) | |
{ | |
auto h = hash(key); | |
for (size_t i = 0; i < keys.size(); i++) { | |
if (keys[i] == h) { | |
return values[i]; | |
} | |
} | |
return{}; | |
} | |
void insert(const char* key, DataType type, Value value) { | |
keys.push_back(hash(key)); | |
types.push_back(type); | |
values.push_back(value); | |
} | |
void insert(const char* key, float value) { | |
Value val; | |
val.f = value; | |
insert(key, DataType::FLOAT, val); | |
} | |
void insert(const char* key, bool value) { | |
Value val; | |
val.b = value; | |
insert(key, DataType::BOOL, val); | |
} | |
void insert(const char* key, const char* value) { | |
Value val; | |
val.s = new std::string(value); | |
insert(key, DataType::STRING, val); | |
} | |
}; | |
struct Object2 { | |
int capacity; | |
int size; | |
unsigned* keys; | |
DataType* types; | |
Value* values; | |
Object2() { | |
capacity = 50; | |
size = 0; | |
void* buffer = malloc(capacity * (sizeof(unsigned) + sizeof(DataType) + sizeof(Value))); | |
keys = (unsigned*)buffer; | |
types = (DataType*)(keys + capacity); | |
values = (Value*)(types + capacity); | |
} | |
~Object2() { | |
free(keys); | |
} | |
Value get(const char* key) | |
{ | |
auto h = hash(key); | |
for (size_t i = 0; i < size; i++) { | |
if (keys[i] == h) { | |
return values[i]; | |
} | |
} | |
return{}; | |
} | |
void insert(const char* key, DataType type, Value value) { | |
if (size < capacity) { | |
keys[size] = hash(key); | |
types[size] = type; | |
values[size] = value; | |
} | |
size++; | |
} | |
void insert(const char* key, float value) { | |
Value val; | |
val.f = value; | |
insert(key, DataType::FLOAT, val); | |
} | |
void insert(const char* key, bool value) { | |
Value val; | |
val.b = value; | |
insert(key, DataType::BOOL, val); | |
} | |
void insert(const char* key, const char* value) { | |
Value val; | |
val.s = new std::string(value); | |
insert(key, DataType::STRING, val); | |
} | |
}; | |
struct value_buffer | |
{ | |
char *p; | |
unsigned capacity; | |
unsigned size; | |
}; | |
void *allocate_memory(value_buffer &vb, unsigned size) | |
{ | |
if (vb.size + size > vb.capacity) | |
return nullptr; | |
auto res = vb.p - vb.size - size; | |
vb.size += size; | |
return res; | |
} | |
struct Data { | |
uint16_t offset; | |
uint16_t size; | |
}; | |
struct Array { | |
int size; | |
float *data; | |
}; | |
struct Value3 { | |
union { | |
bool b; | |
float f; | |
char* s; | |
}; | |
operator bool() const { return b; } | |
operator float() const { return f; } | |
operator char*() const { return s; } | |
}; | |
struct Object3 { | |
int capacity; | |
int size; | |
unsigned* keys; | |
DataType* types; | |
Value3* values; | |
value_buffer buffer; | |
char * buff; | |
Object3() { | |
capacity = 50; | |
size = 0; | |
buffer.size = 0; | |
buffer.capacity = 300; | |
auto allocSize = capacity * (sizeof(unsigned) + sizeof(DataType) + sizeof(Value3)) + buffer.capacity; | |
buff = (char*)malloc(allocSize); | |
keys = (unsigned*)buff; | |
types = (DataType*)(keys + capacity); | |
values = (Value3*)(types + capacity); | |
buffer.p = (char*)buff + allocSize; | |
} | |
~Object3() { | |
free(buff); | |
} | |
Value3 get(const char* key) | |
{ | |
auto h = hash(key); | |
for (size_t i = 0; i < size; i++) { | |
if (keys[i] == h) { | |
return values[i]; | |
} | |
} | |
return{}; | |
} | |
void insert(const char* key, DataType type, Value3 value) { | |
if (size < capacity) { | |
keys[size] = hash(key); | |
types[size] = type; | |
values[size] = value; | |
} | |
size++; | |
} | |
void insert(const char* key, float value) { | |
Value3 val; | |
val.f = value; | |
insert(key, DataType::FLOAT, val); | |
} | |
void insert(const char* key, bool value) { | |
Value3 val; | |
val.b = value; | |
insert(key, DataType::BOOL, val); | |
} | |
void insert(const char* key, const char* value) { | |
Value3 val; | |
auto len = strlen(value)+1; | |
val.s = (char*)allocate_memory(buffer, len); | |
memcpy(val.s, value, len); | |
insert(key, DataType::STRING, val); | |
} | |
}; | |
struct Timer { | |
Timer(const char* name) | |
: name(name) | |
{ | |
begin = std::chrono::high_resolution_clock::now(); | |
} | |
~Timer() | |
{ | |
auto end = std::chrono::high_resolution_clock::now(); | |
std::cout << name << ": " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << "ms" << std::endl; | |
} | |
std::chrono::high_resolution_clock::time_point begin; | |
const char* name; | |
}; | |
int main() | |
{ | |
int count = 1000000; | |
{ | |
{ | |
Timer time("std"); | |
for (int i = 0; i < count; i++) { | |
StdDataValue object(DataType::OBJECT); | |
auto& stats = object.insertObject("stats"); | |
stats.insert("health", 100.f); | |
stats.insert("mana", 200.f); | |
stats.insert("name", "name"); | |
auto& status_effect = object.insertObject("status_effect"); | |
status_effect.insert("drunk", true); | |
status_effect.insert("delirious", false); | |
status_effect.insert("name", "name"); | |
auto& attack = object.insertObject("attack"); | |
attack.insert("punch", 10.f); | |
attack.insert("kick", 20.f); | |
attack.insert("name", "name"); | |
object.insert("name", "the one"); | |
auto& o = object.get("stats"); | |
o.get("health"); | |
o.get("mana"); | |
auto& o1 = object.get("status_effect"); | |
o1.get("drunk"); | |
o1.get("delirious"); | |
auto& o2 = object.get("attack"); | |
o2.get("punch"); | |
o2.get("kick"); | |
} | |
} | |
Timer time("std query"); | |
StdDataValue object(DataType::OBJECT); | |
auto& stats = object.insertObject("stats"); | |
stats.insert("health", 100.f); | |
stats.insert("mana", 200.f); | |
stats.insert("name", "name"); | |
auto& status_effect = object.insertObject("status_effect"); | |
status_effect.insert("drunk", true); | |
status_effect.insert("delirious", false); | |
status_effect.insert("name", "name"); | |
auto& attack = object.insertObject("attack"); | |
attack.insert("punch", 10.f); | |
attack.insert("kick", 20.f); | |
attack.insert("name", "name"); | |
object.insert("name", "the one"); | |
for (int i = 0; i < count; i++) { | |
auto& o = object.get("stats"); | |
o.get("health"); | |
o.get("mana"); | |
auto& o1 = object.get("status_effect"); | |
o1.get("drunk"); | |
o1.get("delirious"); | |
auto& o2 = object.get("attack"); | |
o2.get("punch"); | |
o2.get("kick"); | |
} | |
} | |
{ | |
Timer time("dod1"); | |
for (int i = 0; i < count; i++) { | |
Object1 object; | |
object.insert("name", "the one"); | |
object.insert("stats.health", 100.f); | |
object.insert("stats.mana", 200.f); | |
object.insert("stats.name", "statsname"); | |
object.insert("status_effect.drunk", true); | |
object.insert("status_effect.delirious", false); | |
object.insert("status_effect.name", "statsname"); | |
object.insert("attack.kick", 10.f); | |
object.insert("attack.punch", 20.f); | |
object.insert("attack.name", "statsname"); | |
object.get("stats.health"); | |
object.get("stats.mana"); | |
object.get("status.drunk"); | |
object.get("status.delirious"); | |
object.get("attack.kick"); | |
object.get("attack.puch"); | |
} | |
} | |
{ | |
Timer time("dod2"); | |
for (int i = 0; i < count; i++) { | |
Object2 object; | |
object.insert("name", "the one"); | |
object.insert("stats.health", 100.f); | |
object.insert("stats.mana", 200.f); | |
object.insert("stats.name", "statsname"); | |
object.insert("status_effect.drunk", true); | |
object.insert("status_effect.delirious", false); | |
object.insert("status_effect.name", "statsname"); | |
object.insert("attack.kick", 10.f); | |
object.insert("attack.punch", 20.f); | |
object.insert("attack.name", "statsname"); | |
object.get("stats.health"); | |
object.get("stats.mana"); | |
object.get("status.drunk"); | |
object.get("status.delirious"); | |
object.get("attack.kick"); | |
object.get("attack.puch"); | |
} | |
} | |
{ | |
{ | |
Timer time("dod3"); | |
for (int i = 0; i < count; i++) { | |
Object3 object; | |
object.insert("name", "the one"); | |
object.insert("stats.health", 100.f); | |
object.insert("stats.mana", 200.f); | |
object.insert("stats.name", "statsname"); | |
object.insert("status_effect.drunk", true); | |
object.insert("status_effect.delirious", false); | |
object.insert("status_effect.name", "statsname"); | |
object.insert("attack.kick", 10.f); | |
object.insert("attack.punch", 20.f); | |
object.insert("attack.name", "statsname"); | |
object.get("stats.health"); | |
object.get("stats.mana"); | |
object.get("status.drunk"); | |
object.get("status.delirious"); | |
object.get("attack.kick"); | |
object.get("attack.puch"); | |
} | |
} | |
Timer time("dod3 query"); | |
Object3 object; | |
object.insert("name", "the one"); | |
object.insert("stats.health", 100.f); | |
object.insert("stats.mana", 200.f); | |
object.insert("stats.name", "statsname"); | |
object.insert("status_effect.drunk", true); | |
object.insert("status_effect.delirious", false); | |
object.insert("status_effect.name", "statsname"); | |
object.insert("attack.kick", 10.f); | |
object.insert("attack.punch", 20.f); | |
object.insert("attack.name", "statsname"); | |
for (int i = 0; i < count; i++) { | |
object.get("stats.health"); | |
object.get("stats.mana"); | |
object.get("status.drunk"); | |
object.get("status.delirious"); | |
object.get("attack.kick"); | |
object.get("attack.puch"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment