struct DTree; string json_escape(string s) { //return(string("\"")+s+"\""); string result; u32 i = 0; result.append(1, '"'); while(i < s.length()) { char c = s[i]; switch(c) { case('\t'): result.append("\\t"); break; case('\n'): result.append("\\n"); break; case('"'): result.append("\\\""); break; case('\r'): result.append("\\r"); break; case('\\'): result.append("\\\\"); break; case('\b'): result.append("\\b"); break; case('\f'): result.append("\\f"); break; default: result.append(1, c); break; } i += 1; } result.append(1, '"'); return(result); } struct DTree { char type = 'S'; string _string; f64 _float; bool _bool; void* _ptr; std::map _map; void each(std::function f) { switch(type) { case('M'): for (auto it = _map.begin(); it != _map.end(); ++it) { f(it->second, it->first); } break; default: f(*this, ""); break; } } bool is_array() { return(type == 'M'); } string to_string() { switch(type) { case('S'): return(_string); break; case('F'): return(std::to_string(_float)); break; case('B'): return(_bool ? "(true)" : "(false)"); break; case('M'): return("(array)"); break; case('P'): return(std::to_string((u64)_ptr)); break; } } string to_json() { switch(type) { case('S'): return(json_escape(_string)); break; case('F'): return(std::to_string(_float)); break; case('B'): return(_bool ? "true" : "false"); break; case('M'): return("\"(array)\""); break; case('P'): return("\"(pointer)\""); break; } } string get_type_name() { switch(type) { case('S'): return("string"); break; case('F'): return("f64"); break; case('B'): return("bool"); break; case('M'): return("array"); break; case('P'): return("pointer"); break; } } void set(string s) { if(type == 'M') _map.clear(); type = 'S'; _string = s; } void set(void* p) { if(type == 'M') _map.clear(); type = 'P'; _ptr = p; } void set(f64 f) { if(type == 'M') _map.clear(); type = 'F'; _float = f; } void set_bool(bool b) { if(type == 'M') _map.clear(); type = 'B'; _bool = b; } void set(DTree source) { type = source.type; switch(type) { case('S'): _string = source._string; break; case('F'): _float = source._float; break; case('B'): _bool = source._bool; break; case('M'): _map = source._map; break; case('P'): _ptr = source._ptr; break; } } void set(StringMap source) { type = 'M'; _map.clear(); for (auto it = source.begin(); it != source.end(); ++it) { (*this)[it->first] = it->second; } } DTree* key(string s) { type = 'M'; return(&_map[s]); } DTree& operator [] (string s) { type = 'M'; return(_map[s]); } void operator = (string v) { set(v); } void operator = (f64 v) { set(v); } void operator = (void* v) { set(v); } void operator = (DTree v) { set(v); } void operator = (StringMap v) { set(v); } void remove(string s) { type = 'M'; _map.erase(s); } void clear() { type = 'M'; _map.clear(); } }; string to_string(DTree t) { return(t.to_string()); } string var_dump(DTree map, string prefix = "", string postfix = "\n") { string result = ""; if(!map.is_array()) return(map.to_string()); map.each([&] (DTree item, string key) { result += prefix + key + ": " + item.to_string() + postfix; if(item.is_array()) result += var_dump(item, prefix + "\t"); }); return(result); }