Skip to content

Instantly share code, notes, and snippets.

@oilandrust
Created May 20, 2016 16:44
Show Gist options
  • Save oilandrust/e8b4202ce8786ce85a58ee075defc851 to your computer and use it in GitHub Desktop.
Save oilandrust/e8b4202ce8786ce85a58ee075defc851 to your computer and use it in GitHub Desktop.
Bistsui DataComponent
#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