mirror of
https://github.com/korenkonder/ReDIVA.git
synced 2026-10-12 00:58:20 +03:00
1246 lines
30 KiB
C++
1246 lines
30 KiB
C++
/*
|
|
by korenkonder
|
|
GitHub/GitLab: korenkonder
|
|
*/
|
|
|
|
#include "key_val.hpp"
|
|
#include "io/file_stream.hpp"
|
|
#include "io/path.hpp"
|
|
#include "hash.hpp"
|
|
#include "str_utils.hpp"
|
|
|
|
static int64_t key_val_find_first_key(key_val* kv, int64_t low, int64_t high,
|
|
const char* s, size_t s_len, size_t offset);
|
|
static int64_t key_val_find_last_key(key_val* kv, int64_t low, int64_t high,
|
|
const char* s, size_t s_len, size_t offset);
|
|
static int64_t key_val_get_key_index(key_val* kv, const char* key);
|
|
static int64_t key_val_get_key_index(key_val* kv, std::string& key);
|
|
static int64_t key_val_get_key_index(key_val* kv, const char* str, size_t size);
|
|
static void key_val_sort(key_val* kv);
|
|
|
|
key_val_scope::key_val_scope() : index(), count() {
|
|
|
|
}
|
|
|
|
key_val_scope::~key_val_scope() {
|
|
|
|
}
|
|
|
|
key_val::key_val() : curr_scope(), buf(), scope_size() {
|
|
|
|
}
|
|
|
|
key_val::~key_val() {
|
|
free_def(buf);
|
|
}
|
|
|
|
void key_val::close_scope() {
|
|
if (scope_size <= 0)
|
|
return;
|
|
|
|
curr_scope->key.clear();
|
|
curr_scope->index = 0;
|
|
curr_scope->count = 0;
|
|
curr_scope->key_hash_index.clear();
|
|
|
|
scope_size--;
|
|
curr_scope = &scope[scope_size];
|
|
}
|
|
|
|
void key_val::file_read(const char* path) {
|
|
if (!path || !path_check_file_exists(path))
|
|
return;
|
|
|
|
file_stream s;
|
|
s.open(path, "rb");
|
|
if (s.check_not_null()) {
|
|
char* d = force_malloc<char>(s.length);
|
|
s.read(d, s.length);
|
|
parse((uint8_t*)d, s.length);
|
|
free_def(d);
|
|
}
|
|
}
|
|
|
|
void key_val::file_read(const wchar_t* path) {
|
|
if (!path || !path_check_file_exists(path))
|
|
return;
|
|
|
|
file_stream s;
|
|
s.open(path, L"rb");
|
|
if (s.check_not_null()) {
|
|
char* d = force_malloc<char>(s.length);
|
|
s.read(d, s.length);
|
|
parse((uint8_t*)d, s.length);
|
|
free_def(d);
|
|
}
|
|
}
|
|
|
|
bool key_val::has_key(const char* str) {
|
|
size_t offset = curr_scope->key.size();
|
|
if (offset)
|
|
offset++;
|
|
|
|
const char* s = str;
|
|
size_t s_len = utf8_length(str);
|
|
|
|
int64_t index = key_val_find_first_key(this, curr_scope->index,
|
|
curr_scope->index + curr_scope->count - 1, s, s_len, offset);
|
|
return index != -1;
|
|
}
|
|
|
|
bool key_val::has_key(std::string& str) {
|
|
size_t offset = curr_scope->key.size();
|
|
if (offset)
|
|
offset++;
|
|
|
|
const char* s = str.c_str();
|
|
size_t s_len = str.size();
|
|
|
|
int64_t index = key_val_find_first_key(this, curr_scope->index,
|
|
curr_scope->index + curr_scope->count - 1, s, s_len, offset);
|
|
return index != -1;
|
|
}
|
|
|
|
bool key_val::open_scope(const char* str) {
|
|
if (!str || !*str) {
|
|
scope_size++;
|
|
if ((size_t)scope_size >= scope.size())
|
|
scope.resize(scope_size + (scope_size >> 1) + 1);
|
|
|
|
curr_scope = &scope[scope_size];
|
|
key_val_scope* prev_scope = curr_scope - 1;
|
|
curr_scope->key.assign(prev_scope->key);
|
|
curr_scope->index = prev_scope->index;
|
|
curr_scope->count = prev_scope->count;
|
|
curr_scope->key_hash_index.resize(prev_scope->key_hash_index.size());
|
|
memmove(curr_scope->key_hash_index.data(), prev_scope->key_hash_index.data(),
|
|
sizeof(std::pair<uint64_t, size_t>) * prev_scope->key_hash_index.size());
|
|
return true;
|
|
}
|
|
|
|
size_t offset = curr_scope->key.size();
|
|
if (offset)
|
|
offset++;
|
|
|
|
const char* s = str;
|
|
size_t s_len = utf8_length(str);
|
|
|
|
int64_t first_idx = key_val_find_first_key(this, curr_scope->index,
|
|
curr_scope->index + curr_scope->count - 1, s, s_len, offset);
|
|
if (first_idx == -1)
|
|
return false;
|
|
|
|
int64_t last_idx = key_val_find_last_key(this, first_idx,
|
|
curr_scope->index + curr_scope->count - 1, s, s_len, offset);
|
|
if (last_idx == -1)
|
|
return false;
|
|
|
|
scope_size++;
|
|
if ((size_t)scope_size >= scope.size())
|
|
scope.resize(scope_size + (scope_size >> 1) + 1);
|
|
|
|
curr_scope = &scope[scope_size];
|
|
if (curr_scope[-1].key.size()) {
|
|
std::string& new_key = curr_scope->key;
|
|
new_key.clear();
|
|
new_key.reserve(curr_scope[-1].key.size() + s_len + 1);
|
|
new_key.assign(curr_scope[-1].key);
|
|
new_key.append(1, '.');
|
|
new_key.append(str, s_len);
|
|
}
|
|
else
|
|
curr_scope->key.assign(str, s_len);
|
|
curr_scope->index = first_idx;
|
|
curr_scope->count = last_idx - first_idx + 1;
|
|
curr_scope->key_hash_index.clear();
|
|
|
|
key_val_sort(this);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::open_scope(std::string& str) {
|
|
if (!str.size()) {
|
|
scope_size++;
|
|
if ((size_t)scope_size >= scope.size())
|
|
scope.resize(scope_size + (scope_size >> 1) + 1);
|
|
|
|
curr_scope = &scope[scope_size];
|
|
key_val_scope* prev_scope = curr_scope - 1;
|
|
curr_scope->key.assign(prev_scope->key);
|
|
curr_scope->index = prev_scope->index;
|
|
curr_scope->count = prev_scope->count;
|
|
curr_scope->key_hash_index.resize(prev_scope->key_hash_index.size());
|
|
memmove(curr_scope->key_hash_index.data(), prev_scope->key_hash_index.data(),
|
|
sizeof(std::pair<uint64_t, size_t>) * prev_scope->key_hash_index.size());
|
|
return true;
|
|
}
|
|
|
|
size_t offset = curr_scope->key.size();
|
|
if (offset)
|
|
offset++;
|
|
|
|
const char* s = str.c_str();
|
|
size_t s_len = str.size();
|
|
|
|
int64_t first_idx = key_val_find_first_key(this, curr_scope->index,
|
|
curr_scope->index + curr_scope->count - 1, s, s_len, offset);
|
|
if (first_idx == -1)
|
|
return false;
|
|
|
|
int64_t last_idx = key_val_find_last_key(this, first_idx,
|
|
curr_scope->index + curr_scope->count - 1, s, s_len, offset);
|
|
if (last_idx == -1)
|
|
return false;
|
|
|
|
scope_size++;
|
|
if ((size_t)scope_size >= scope.size())
|
|
scope.resize(scope_size + (scope_size >> 1) + 1);
|
|
|
|
curr_scope = &scope[scope_size];
|
|
if (curr_scope[-1].key.size()) {
|
|
std::string& new_key = curr_scope->key;
|
|
new_key.clear();
|
|
new_key.reserve(curr_scope[-1].key.size() + str.size() + 1);
|
|
new_key.assign(curr_scope[-1].key);
|
|
new_key.append(1, '.');
|
|
new_key.append(str);
|
|
}
|
|
else
|
|
curr_scope->key.assign(str);
|
|
curr_scope->index = first_idx;
|
|
curr_scope->count = last_idx - first_idx + 1;
|
|
curr_scope->key_hash_index.clear();
|
|
|
|
key_val_sort(this);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::open_scope_fmt(int32_t i) {
|
|
char buf[0x200];
|
|
sprintf_s(buf, sizeof(buf), "%d", i);
|
|
return open_scope(buf);
|
|
}
|
|
|
|
bool key_val::open_scope_fmt(uint32_t i) {
|
|
char buf[0x200];
|
|
sprintf_s(buf, sizeof(buf), "%u", i);
|
|
return open_scope(buf);
|
|
}
|
|
|
|
bool key_val::open_scope_fmt(_In_z_ _Printf_format_string_ const char* const fmt, ...) {
|
|
char buf[0x200];
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vsprintf_s(buf, sizeof(buf), fmt, args);
|
|
va_end(args);
|
|
return open_scope(buf);
|
|
}
|
|
|
|
void key_val::parse(const void* data, size_t size) {
|
|
if (!data || !size)
|
|
return;
|
|
|
|
curr_scope = 0;
|
|
scope.clear();
|
|
|
|
char** lines;
|
|
size_t count;
|
|
if (!str_utils_text_file_parse(data, size, buf, lines, count))
|
|
return;
|
|
|
|
key.reserve(count);
|
|
val.reserve(count);
|
|
|
|
for (size_t i = 0, j = 0; i < count; i++) {
|
|
char* s = lines[i];
|
|
if (*s == '!' || *s == '#')
|
|
continue;
|
|
|
|
size_t len = utf8_length(s);
|
|
char* c = (char*)memchr(s, '=', len);
|
|
if (!c)
|
|
continue;
|
|
|
|
*c = 0;
|
|
|
|
char* key_str_data = s;
|
|
char* val_str_data = c + 1;
|
|
|
|
size_t key_length = c - s;
|
|
size_t val_length = len - (key_length + 1);
|
|
|
|
uint64_t key_hash = hash_xxh3_64bits(key_str_data, key_length);
|
|
|
|
key.push_back({ key_str_data, key_length });
|
|
val.push_back({ val_str_data, val_length });
|
|
j++;
|
|
}
|
|
|
|
scope.resize(1);
|
|
curr_scope = &scope[0];
|
|
curr_scope->key.clear();
|
|
curr_scope->index = 0;
|
|
curr_scope->count = key.size();
|
|
|
|
key_val_sort(this);
|
|
free_def(lines);
|
|
}
|
|
|
|
bool key_val::read(bool& value) {
|
|
int64_t index = curr_scope->index;
|
|
if (index == -1) {
|
|
value = false;
|
|
return false;
|
|
}
|
|
value = atoi(val[index].first) ? true : false;
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(float_t& value) {
|
|
int64_t index = curr_scope->index;
|
|
if (index == -1) {
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
value = (float_t)atof(val[index].first);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(int32_t& value) {
|
|
int64_t index = curr_scope->index;
|
|
if (index == -1) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
value = atoi(val[index].first);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(uint32_t& value) {
|
|
int64_t index = curr_scope->index;
|
|
if (index == -1) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
value = (uint32_t)atoll(val[index].first);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(const char*& value) {
|
|
int64_t index = curr_scope->index;
|
|
if (index == -1) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
value = val[index].first;
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(std::string& value) {
|
|
int64_t index = curr_scope->index;
|
|
if (index == -1) {
|
|
value.clear();
|
|
return false;
|
|
}
|
|
value.assign(val[index].first, val[index].second);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(vec3& value) {
|
|
read("x", value.x);
|
|
read("y", value.y);
|
|
read("z", value.z);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(const char* key, bool& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = false;
|
|
return false;
|
|
}
|
|
value = atoi(val[index].first) ? true : false;
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(std::string& key, bool& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = false;
|
|
return false;
|
|
}
|
|
value = atoi(val[index].first) ? true : false;
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(const char* key, float_t& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
value = (float_t)atof(val[index].first);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(std::string& key, float_t& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
value = (float_t)atof(val[index].first);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(const char* key, int32_t& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
value = atoi(val[index].first);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(std::string& key, int32_t& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
value = atoi(val[index].first);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(const char* key, uint32_t& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
value = (uint32_t)atoll(val[index].first);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(std::string& key, uint32_t& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
value = (uint32_t)atoll(val[index].first);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(const char* key, const char*& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
value = val[index].first;
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(std::string& key, const char*& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
value = val[index].first;
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(const char* key, std::string& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value.clear();
|
|
return false;
|
|
}
|
|
value.assign(val[index].first, val[index].second);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(std::string& key, std::string& value) {
|
|
int64_t index = key_val_get_key_index(this, key);
|
|
if (index == -1) {
|
|
value.clear();
|
|
return false;
|
|
}
|
|
value.assign(val[index].first, val[index].second);
|
|
return true;
|
|
}
|
|
|
|
bool key_val::read(const char* key, vec3& value) {
|
|
if (open_scope(key)) {
|
|
read("x", value.x);
|
|
read("y", value.y);
|
|
read("z", value.z);
|
|
close_scope();
|
|
return true;
|
|
}
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(std::string& key, vec3& value) {
|
|
if (open_scope(key)) {
|
|
read("x", value.x);
|
|
read("y", value.y);
|
|
read("z", value.z);
|
|
close_scope();
|
|
return true;
|
|
}
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(std::string& key0, std::string& key1, bool& value) {
|
|
if (!open_scope(key0)) {
|
|
value = false;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(const char* key0, const char* key1, bool& value) {
|
|
if (!open_scope(key0)) {
|
|
value = false;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(std::string& key0, std::string& key1, float_t& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(const char* key0, const char* key1, float_t& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(std::string& key0, std::string& key1, int32_t& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(const char* key0, const char* key1, int32_t& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(std::string& key0, std::string& key1, uint32_t& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(const char* key0, const char* key1, uint32_t& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(std::string& key0, std::string& key1, const char*& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(const char* key0, const char* key1, const char*& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(std::string& key0, std::string& key1, std::string& value) {
|
|
if (!open_scope(key0)) {
|
|
value.clear();
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(const char* key0, const char* key1, std::string& value) {
|
|
if (!open_scope(key0)) {
|
|
value.clear();
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(std::string& key0, std::string& key1, vec3& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::read(const char* key0, const char* key1, vec3& value) {
|
|
if (!open_scope(key0)) {
|
|
value = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
if (read(key1, value))
|
|
return true;
|
|
|
|
close_scope();
|
|
return false;
|
|
}
|
|
|
|
bool key_val::load_file(void* data, const char* dir, const char* file, uint32_t hash) {
|
|
std::string path(dir);
|
|
path.append(file);
|
|
|
|
key_val* kv = (key_val*)data;
|
|
kv->file_read(path.c_str());
|
|
|
|
return kv->buf ? true : false;
|
|
}
|
|
|
|
key_val_out::key_val_out() : curr_scope() {
|
|
scope.push_back("");
|
|
curr_scope = &scope[scope.size() - 1];
|
|
}
|
|
|
|
key_val_out::~key_val_out() {
|
|
|
|
}
|
|
|
|
void key_val_out::close_scope() {
|
|
if (scope.size() <= 1)
|
|
return;
|
|
|
|
scope.pop_back();
|
|
curr_scope = &scope[scope.size() - 1];
|
|
}
|
|
|
|
void key_val_out::open_scope(std::string& str) {
|
|
if (!str.size()) {
|
|
scope.push_back(*curr_scope);
|
|
curr_scope = &scope[scope.size() - 1];
|
|
return;
|
|
}
|
|
|
|
if (curr_scope->size()) {
|
|
temp_key.clear();
|
|
temp_key.reserve(curr_scope->size() + str.size() + 1);
|
|
temp_key.assign(*curr_scope);
|
|
temp_key.push_back('.');
|
|
temp_key.append(str);
|
|
scope.push_back(temp_key);
|
|
}
|
|
else
|
|
scope.push_back(str);
|
|
curr_scope = &scope[scope.size() - 1];
|
|
}
|
|
|
|
void key_val_out::open_scope(const char* str) {
|
|
if (!str || !*str) {
|
|
scope.push_back(*curr_scope);
|
|
curr_scope = &scope[scope.size() - 1];
|
|
return;
|
|
}
|
|
|
|
if (curr_scope->size()) {
|
|
size_t str_len = utf8_length(str);
|
|
temp_key.clear();
|
|
temp_key.reserve(curr_scope->size() + str_len + 1);
|
|
temp_key.assign(*curr_scope);
|
|
temp_key.push_back('.');
|
|
temp_key.append(str, str_len);
|
|
scope.push_back(temp_key);
|
|
}
|
|
else
|
|
scope.push_back(str);
|
|
curr_scope = &scope[scope.size() - 1];
|
|
}
|
|
|
|
void key_val_out::open_scope_fmt(int32_t i) {
|
|
char buf[0x100];
|
|
sprintf_s(buf, sizeof(buf), "%d", i);
|
|
open_scope(buf);
|
|
}
|
|
|
|
void key_val_out::open_scope_fmt(uint32_t i) {
|
|
char buf[0x100];
|
|
sprintf_s(buf, sizeof(buf), "%u", i);
|
|
open_scope(buf);
|
|
}
|
|
|
|
void key_val_out::write(stream& s, bool value) {
|
|
if (!value)
|
|
return;
|
|
|
|
s.write_string(*curr_scope);
|
|
s.write("=1\n", 3);
|
|
}
|
|
|
|
void key_val_out::write(stream& s, float_t value) {
|
|
char val_buf[0x100];
|
|
sprintf_s(val_buf, 0x100, "%g", value);
|
|
|
|
s.write_string(*curr_scope);
|
|
s.write_char('=');
|
|
s.write_utf8_string(val_buf);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, int32_t value) {
|
|
char val_buf[0x100];
|
|
sprintf_s(val_buf, 0x100, "%d", value);
|
|
|
|
s.write_string(*curr_scope);
|
|
s.write_char('=');
|
|
s.write_utf8_string(val_buf);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, uint32_t value) {
|
|
char val_buf[0x100];
|
|
sprintf_s(val_buf, 0x100, "%u", value);
|
|
|
|
s.write_string(*curr_scope);
|
|
s.write_char('=');
|
|
s.write_utf8_string(val_buf);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const char* value) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('=');
|
|
s.write_utf8_string(value);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const std::string& value) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('=');
|
|
s.write_string(value);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const vec3& value) {
|
|
write(s, "x", value.x);
|
|
write(s, "y", value.y);
|
|
write(s, "z", value.z);
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const char* key, bool value) {
|
|
if (!value)
|
|
return;
|
|
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_utf8_string(key);
|
|
s.write("=1\n", 3);
|
|
}
|
|
|
|
void key_val_out::write(stream& s, std::string& key, bool value) {
|
|
if (!value)
|
|
return;
|
|
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_string(key);
|
|
s.write("=1\n", 3);
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const char* key, float_t value, const char* fmt) {
|
|
char val_buf[0x100];
|
|
sprintf_s(val_buf, 0x100, fmt, value);
|
|
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_utf8_string(key);
|
|
s.write_char('=');
|
|
s.write_utf8_string(val_buf);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, std::string& key, float_t value, const char* fmt) {
|
|
char val_buf[0x100];
|
|
sprintf_s(val_buf, 0x100, fmt, value);
|
|
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_string(key);
|
|
s.write_char('=');
|
|
s.write_utf8_string(val_buf);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const char* key, int32_t value) {
|
|
char val_buf[0x100];
|
|
sprintf_s(val_buf, 0x100, "%d", value);
|
|
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_utf8_string(key);
|
|
s.write_char('=');
|
|
s.write_utf8_string(val_buf);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, std::string& key, int32_t value) {
|
|
char val_buf[0x100];
|
|
sprintf_s(val_buf, 0x100, "%d", value);
|
|
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_string(key);
|
|
s.write_char('=');
|
|
s.write_utf8_string(val_buf);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const char* key, uint32_t value) {
|
|
char val_buf[0x100];
|
|
sprintf_s(val_buf, 0x100, "%u", value);
|
|
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_utf8_string(key);
|
|
s.write_char('=');
|
|
s.write_utf8_string(val_buf);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, std::string& key, uint32_t value) {
|
|
char val_buf[0x100];
|
|
sprintf_s(val_buf, 0x100, "%u", value);
|
|
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_string(key);
|
|
s.write_char('=');
|
|
s.write_utf8_string(val_buf);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const char* key, const char* value) {
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_utf8_string(key);
|
|
s.write_char('=');
|
|
s.write_utf8_string(value);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, std::string& key, const char* value) {
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_string(key);
|
|
s.write_char('=');
|
|
s.write_utf8_string(value);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const char* key, const std::string& value) {
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_utf8_string(key);
|
|
s.write_char('=');
|
|
s.write_string(value);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, std::string& key, const std::string& value) {
|
|
if (curr_scope->size()) {
|
|
s.write_string(*curr_scope);
|
|
s.write_char('.');
|
|
}
|
|
s.write_string(key);
|
|
s.write_char('=');
|
|
s.write_string(value);
|
|
s.write_char('\n');
|
|
}
|
|
|
|
void key_val_out::write(stream& s, const char* key, const vec3& value) {
|
|
open_scope(key);
|
|
write(s, "x", value.x);
|
|
write(s, "y", value.y);
|
|
write(s, "z", value.z);
|
|
close_scope();
|
|
}
|
|
|
|
void key_val_out::write(stream& s, std::string& key, const vec3& value) {
|
|
open_scope(key);
|
|
write(s, "x", value.x);
|
|
write(s, "y", value.y);
|
|
write(s, "z", value.z);
|
|
close_scope();
|
|
}
|
|
|
|
void key_val_out::get_lexicographic_order(std::vector<int32_t>& vec, int32_t length) {
|
|
vec.clear();
|
|
|
|
int32_t i, j, m;
|
|
|
|
if (length < 1)
|
|
return;
|
|
|
|
vec.reserve(length);
|
|
|
|
j = 0;
|
|
vec.push_back(j);
|
|
i = 1;
|
|
j = 1;
|
|
|
|
m = 1;
|
|
while (m < length)
|
|
m *= 10;
|
|
|
|
while (i < length) {
|
|
if (j * 10 < m) {
|
|
vec.push_back(j);
|
|
i++;
|
|
j *= 10;
|
|
}
|
|
else if (j >= length) {
|
|
m /= 10;
|
|
j /= 10;
|
|
while (j % 10 == 9)
|
|
j /= 10;
|
|
j++;
|
|
}
|
|
else if (j % 10 != 9) {
|
|
vec.push_back(j);
|
|
i++;
|
|
j++;
|
|
}
|
|
|
|
if (i < length)
|
|
if (j == length && j % 10 != 9) {
|
|
m /= 10;
|
|
j /= 10;
|
|
while (j % 10 == 9)
|
|
j /= 10;
|
|
j++;
|
|
}
|
|
else if (j < length && j % 10 == 9) {
|
|
vec.push_back(j);
|
|
i++;
|
|
while (j % 10 == 9)
|
|
j /= 10;
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int64_t key_val_find_first_key(key_val* kv, int64_t low, int64_t high,
|
|
const char* s, size_t s_len, size_t offset) {
|
|
auto* k = kv->key.data();
|
|
|
|
int64_t first_idx = -1;
|
|
int64_t mid;
|
|
int32_t res;
|
|
bool full;
|
|
while (low <= high) {
|
|
auto* l = &k[mid = (low + high) / 2];
|
|
if (l->second > offset && s_len <= l->second - offset) {
|
|
res = memcmp(s, l->first + offset, s_len);
|
|
if (!res && l->first[offset + s_len] && l->first[offset + s_len] != '.')
|
|
res = -1;
|
|
full = true;
|
|
}
|
|
else {
|
|
if (l->second >= offset) {
|
|
res = str_utils_compare_length(s, s_len, l->first + offset, l->second - offset);
|
|
if (!res && s[l->second - offset])
|
|
res = 1;
|
|
}
|
|
else
|
|
res = 1;
|
|
full = false;
|
|
}
|
|
|
|
if (res > 0)
|
|
low = mid + 1;
|
|
else if (res < 0)
|
|
high = mid - 1;
|
|
else {
|
|
if (full)
|
|
first_idx = mid;
|
|
high = mid - 1;
|
|
}
|
|
}
|
|
return first_idx;
|
|
}
|
|
|
|
static int64_t key_val_find_last_key(key_val* kv, int64_t low, int64_t high,
|
|
const char* s, size_t s_len, size_t offset) {
|
|
auto* k = kv->key.data();
|
|
|
|
int64_t last_idx = -1;
|
|
int64_t mid;
|
|
int32_t res;
|
|
bool full;
|
|
while (low <= high) {
|
|
auto* l = &k[mid = (low + high) / 2];
|
|
if (l->second > offset && s_len <= l->second - offset) {
|
|
res = memcmp(s, l->first + offset, s_len);
|
|
if (!res && l->first[offset + s_len] && l->first[offset + s_len] != '.')
|
|
res = -1;
|
|
full = true;
|
|
}
|
|
else {
|
|
if (l->second >= offset) {
|
|
res = str_utils_compare_length(s, s_len, l->first + offset, l->second - offset);
|
|
if (!res && s[l->second - offset])
|
|
res = 1;
|
|
}
|
|
else
|
|
res = 1;
|
|
full = false;
|
|
}
|
|
|
|
if (res > 0)
|
|
low = mid + 1;
|
|
else if (res < 0)
|
|
high = mid - 1;
|
|
else {
|
|
if (full)
|
|
last_idx = mid;
|
|
low = mid + 1;
|
|
}
|
|
}
|
|
return last_idx;
|
|
}
|
|
|
|
static int64_t key_val_get_key_index(key_val* kv, const char* key) {
|
|
size_t str_len = utf8_length(key);
|
|
if (kv->curr_scope->key.size()) {
|
|
kv->temp_key.clear();
|
|
kv->temp_key.reserve(kv->curr_scope->key.size() + str_len + 1);
|
|
kv->temp_key.assign(kv->curr_scope->key);
|
|
kv->temp_key.push_back('.');
|
|
kv->temp_key.append(key, str_len);
|
|
return key_val_get_key_index(kv, kv->temp_key.c_str(), kv->temp_key.size());
|
|
}
|
|
else
|
|
return key_val_get_key_index(kv, key, str_len);
|
|
}
|
|
|
|
static int64_t key_val_get_key_index(key_val* kv, std::string& key) {
|
|
if (kv->curr_scope->key.size()) {
|
|
kv->temp_key.clear();
|
|
kv->temp_key.reserve(kv->curr_scope->key.size() + key.size() + 1);
|
|
kv->temp_key.assign(kv->curr_scope->key);
|
|
kv->temp_key.push_back('.');
|
|
kv->temp_key.append(key);
|
|
return key_val_get_key_index(kv, kv->temp_key.c_str(), kv->temp_key.size());
|
|
}
|
|
else
|
|
return key_val_get_key_index(kv, key.c_str(), key.size());
|
|
}
|
|
|
|
static int64_t key_val_get_key_index(key_val* kv, const char* str, size_t size) {
|
|
key_val_scope* curr_scope = kv->curr_scope;
|
|
|
|
if (curr_scope->key_hash_index.size() < 1)
|
|
return -1;
|
|
|
|
uint64_t hash = hash_xxh3_64bits(str, size);
|
|
|
|
auto* key = curr_scope->key_hash_index.data();
|
|
size_t len = curr_scope->count;
|
|
size_t temp;
|
|
while (len > 0) {
|
|
if (hash < key[temp = len / 2].first)
|
|
len = temp;
|
|
else {
|
|
key += temp + 1;
|
|
len -= temp + 1;
|
|
}
|
|
}
|
|
|
|
if (key == curr_scope->key_hash_index.data())
|
|
if (key[0].first == hash)
|
|
return key[0].second;
|
|
else
|
|
return -1;
|
|
else if (key[-1].first == hash)
|
|
return key[-1].second;
|
|
else if (key == curr_scope->key_hash_index.data() + curr_scope->key_hash_index.size())
|
|
return -1;
|
|
else if (key[0].first == hash)
|
|
return key[0].second;
|
|
return -1;
|
|
}
|
|
|
|
#define RADIX_BASE 4
|
|
#define RADIX (1 << RADIX_BASE)
|
|
|
|
static void key_val_sort(key_val* kv) {
|
|
if (!kv->key.size())
|
|
return;
|
|
|
|
key_val_scope* curr_scope = kv->curr_scope;
|
|
|
|
size_t index = curr_scope->index;
|
|
size_t count = curr_scope->count;
|
|
|
|
curr_scope->key_hash_index.clear();
|
|
curr_scope->key_hash_index.resize(count);
|
|
|
|
auto* key = kv->key.data() + index;
|
|
auto* key_hash_index = curr_scope->key_hash_index.data();
|
|
for (size_t i = 0; i < count; i++) {
|
|
key_hash_index->second = index + i;
|
|
key_hash_index->first = hash_xxh3_64bits(key->first, key->second);
|
|
key++;
|
|
key_hash_index++;
|
|
}
|
|
|
|
if (count < 2)
|
|
return;
|
|
|
|
size_t c[RADIX];
|
|
kv->temp_key_hash_index.clear();
|
|
kv->temp_key_hash_index.reserve(count);
|
|
auto* o_key_hash_index = kv->temp_key_hash_index.data();
|
|
auto* arr_key_hash_index = curr_scope->key_hash_index.data();
|
|
auto* org_arr = arr_key_hash_index;
|
|
|
|
for (size_t shift = 0, s = 0; shift < sizeof(uint64_t) * 8 / RADIX_BASE; shift++, s += RADIX_BASE) {
|
|
memset(c, 0, sizeof(size_t) * RADIX);
|
|
|
|
for (size_t i = 0; i < count; i++)
|
|
c[(arr_key_hash_index[i].first >> s) & (RADIX - 1)]++;
|
|
|
|
for (size_t i = 1; i < RADIX; i++)
|
|
c[i] += c[i - 1];
|
|
|
|
for (int64_t i = count - 1; i >= 0; i--) {
|
|
size_t index = --c[(arr_key_hash_index[i].first >> s) & (RADIX - 1)];
|
|
o_key_hash_index[index] = arr_key_hash_index[i];
|
|
}
|
|
|
|
auto* t_key_hash = arr_key_hash_index;
|
|
arr_key_hash_index = o_key_hash_index;
|
|
o_key_hash_index = t_key_hash;
|
|
}
|
|
|
|
if (org_arr == o_key_hash_index) {
|
|
auto* t_key_hash_index = arr_key_hash_index;
|
|
arr_key_hash_index = o_key_hash_index;
|
|
o_key_hash_index = t_key_hash_index;
|
|
|
|
memmove(arr_key_hash_index, o_key_hash_index, sizeof(*o_key_hash_index) * count);
|
|
}
|
|
}
|