struct DTree; 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(to_hex((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; } 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) { *this = 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 json_encode(DTree t) { string result = ""; if(t.is_array()) { result += "{"; u32 count = 0; t.each([&] (DTree item, string key) { if(count > 0) result += ", "; count += 1; result += json_escape(key) + ": " + json_encode(item); }); result += "}"; } else { result = t.to_json(); } return(result); } // https://i.stack.imgur.com/SHLOB.gif string json_decode_string(string s, u32& i) { string result; while(i < s.length()) { char c = s[i]; if(c == '"') { i += 1; return(result); } else if(c == '\\') { i += 1; c = s[i]; switch(c) { case('t'): result.append('\t', 1); break; case('n'): result.append('\n', 1); break; case('r'): result.append('\r', 1); break; case('\\'): result.append('\\', 1); break; case('b'): result.append('\b', 1); break; case('f'): result.append('\f', 1); break; case('u'): // todo decode break; default: result.append(c, 1); break; } } else { result.append(c, 1); } i += 1; } return(result); } DTree json_decode_map(string s, u32& i); void json_consume_space(string s, u32& i) { while(i < s.length() && isspace(s[i])) i += 1; } string json_decode_keyword(string s, u32& i) { string result; json_consume_space(s, i); while(i < s.length()) { char c = s[i]; if(isalnum(c)) { result.append(c, 1); } else { return(result); } i += 1; } return(result); } string json_decode_number(string s, u32& i) { string result; json_consume_space(s, i); while(i < s.length()) { char c = s[i]; if(isdigit(c) || c == '.') { result.append(c, 1); } else { return(result); } i += 1; } return(result); } DTree json_decode_value(string s, u32& i) { DTree result; string value = ""; json_consume_space(s, i); char c = s[i]; result.set("CHAR_"); result._string.append(to_string(c)); return(result); if(c == '"') // string value { result.type = 'S'; i += 1; result._string = json_decode_string(s, i); return(result); } else if(isdigit(c)) { result.type = 'S'; result._string = json_decode_number(s, i); //result._float = stod(json_decode_number(s, i)); return(result); } else if(c == '{') { i += 1; return(json_decode_map(s, i)); } else { value = json_decode_keyword(s, i); if(value == "true") result.set_bool(true); else if(value == "false") result.set_bool(false); else if(value == "null") result.set(""); return(result); } return(result); } DTree json_decode_map(string s, u32& i) { DTree result; string key = ""; while(i < s.length()) { json_consume_space(s, i); char c = s[i]; if(c == '}') { return(result); } else if(c == ',') { } else if(c == '"') { i += 1; key = json_decode_string(s, i); json_consume_space(s, i); if(s[i] != ':') return(result); // malformed result[key] = json_decode_value(s, i); } else { // malformed return(result); } i += 1; } return(result); } DTree json_decode(string s) { u32 i = 0; return(json_decode_value(s, i)); } 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); }