diff --git a/libkram/json11/json11.cpp b/libkram/json11/json11.cpp index a623f24c..e0edf0f5 100644 --- a/libkram/json11/json11.cpp +++ b/libkram/json11/json11.cpp @@ -133,7 +133,138 @@ const char* JsonWriter::escapedString(const char* str) return _escapedString.c_str(); } + +void JsonWriter::pushObject(const char* key) { + if (key[0]) + { + KASSERT(isObject()); + writeCommaAndNewline(); + int indent = _stack.size(); + sprintf(*_out, "%*s\"%s\":{\n", indent, "", key); + } + else + { + _out->push_back('{'); + _out->push_back('\n'); + } + _stack.push_back('}'); + _isFirst.push_back(false); +} +void JsonWriter::pushArray(const char* key) { + if (key[0]) + { + KASSERT(isObject()); + writeCommaAndNewline(); + int indent = _stack.size(); + sprintf(*_out, "%*s\"%s\":[\n", indent, "", key); + } + else + { + _out->push_back('['); + _out->push_back('\n'); + } + _stack.push_back(']'); + _isFirst.push_back(false); +} + +void JsonWriter::pop() { + KASSERT(_stack.empty()); + char c = _stack.back(); + + _out->push_back(c); + _out->push_back('\n'); + + _stack.pop_back(); + _isFirst.pop_back(); +} +void JsonWriter::popObject() { + KASSERT(_stack.empty()); + char c = _stack.back(); + KASSERT(c == '}'); + pop(); +} +void JsonWriter::popArray() { + KASSERT(_stack.empty()); + char c = _stack.back(); + KASSERT(c == ']'); + pop(); +} + +void JsonWriter::writeString(const char* key, const char* value) { + KASSERT(isObject()); + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s\"%s\":\"%s\"", indent, "", key, escapedString(value)); +} +void JsonWriter::writeDouble(const char* key, double value) { + KASSERT(isObject()); + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s\"%s\":%f", indent, "", key, value); +} +void JsonWriter::writeInt32(const char* key, int32_t value) { + KASSERT(isObject()); + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s\"%s\":\"%d\"", indent, "", key, value); + +} +void JsonWriter::writeBool(const char* key, bool value) { + KASSERT(isObject()); + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s\"%s\":%s", indent, "", key, value ? "true" : "false"); +} +void JsonWriter::writeNull(const char* key) { + KASSERT(isObject()); + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s\"%s\":%s", indent, "", key, "null"); +} + +void JsonWriter::writeString(const char* value) { + KASSERT(isArray()); + // only if in array + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s\"%s\"", indent, "", escapedString(value)); +} +void JsonWriter::writeDouble(double value) { + KASSERT(isArray()); + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s%f", indent, "", value); +} +void JsonWriter::writeInt32(int32_t value) { + KASSERT(isArray()); + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s\"%d\"", indent, "", value); +} +void JsonWriter::writeBool(bool value) { + KASSERT(isArray()); + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s%s", indent, "", value ? "true" : "false"); +} +void JsonWriter::writeNull() { + KASSERT(isArray()); + writeCommaAndNewline(); + int indent = _stack.size(); + append_sprintf(*_out, "%*s%s", indent, "", "null"); +} + +void JsonWriter::writeCommaAndNewline() { + bool isFirst = _isFirst.back(); + if (!isFirst) + _out->push_back(','); + _out->push_back('\n'); + // vector is special + _isFirst[_isFirst.size()-1] = true; +} + + /* void JsonWriter::writeText(const char* text) { *_out += text; @@ -448,16 +579,17 @@ bool Json::iterate(const Json*& it) const { //------------------- -Json::JsonValue::JsonValue(const char* v, uint32_t count, bool allocated) : sval(v) { - if (allocated) { - // need to allocate memory here - sval = new char[count+1]; - memcpy((void*)sval, v, count+1); - } -} +//Json::JsonValue::JsonValue(const char* v, uint32_t count) : sval(v) { +// if (allocated) { +// // need to allocate memory here +// sval = new char[count+1]; +// memcpy((void*)sval, v, count+1); +// } +//} +/* This is more complex, and uneeded for writer Json::JsonValue::JsonValue(const Json::array& values, Type t) : aval(nullptr) { - /* This is more complex + assert(_data.isWriting()); Json** next = &aval; @@ -477,9 +609,9 @@ Json::JsonValue::JsonValue(const Json::array& values, Type t) : aval(nullptr) { } *next = nullptr; - */ + } - + */ ///////////////////////////////// // Parsing @@ -759,10 +891,6 @@ void JsonReader::parse_string_location(uint32_t& count) { } } -// This is not used in parsing, but will need to convert strings -// that are aliased and unescape them. - - // Parse a double. double JsonReader::parse_number() { @@ -797,7 +925,6 @@ double JsonReader::parse_number() { // TODO:: switch to from_chars, int but not fp supported from_chars(str + start_pos, str + i, value); #else - // this is locale dependent, other bad stuff value = (double)StringToInt64(str + start_pos); #endif return value; @@ -832,6 +959,7 @@ double JsonReader::parse_number() { } #if USE_CHARCONV + // this stupid call, macOS doesn't even implement from_chars(str + start_pos, str + i, value); #else value = strtod(str + start_pos, nullptr); @@ -935,7 +1063,7 @@ void JsonReader::parse_json(int depth, Json& parent, ImmutableString key) { uint32_t strCount = 0; parse_string_location(strCount); Json* json = _data->allocateJson(); - parent.addString(json, &str[strStart], strCount, Json::FlagsAliasedEncoded, key); + parent.addString(json, &str[strStart], strCount, key); return; } @@ -1043,10 +1171,9 @@ void Json::addJson(Json* json) _count++; } -void Json::addString(Json* json, const char* str, uint32_t len, Flags flags, ImmutableString key) +void Json::addString(Json* json, const char* str, uint32_t len, ImmutableString key) { - new (json) Json(str, len, false); - json->_flags = flags; + new (json) Json(str, len); if (key) json->setKey(key); addJson(json); } @@ -1085,21 +1212,21 @@ void Json::addObject(Json* json, ImmutableString key) { //------------------------ -Json::Json(const Json::array &values, Json::Type t) - : _type(t), _count(values.size()), _value(values) { - assert(t == TypeObject || t == TypeArray); -} +//Json::Json(const Json::array &values, Json::Type t) +// : _type(t), _count(values.size()), _value(values) { +// assert(t == TypeObject || t == TypeArray); +//} -Json::~Json() { - switch(_type) { - case TypeString: - if (_flags == FlagsAllocatedUnencoded) { - delete [] _value.sval; - //_data.trackMemory(-_count); - _value.sval = nullptr; - _count = 0; - } - break; +//Json::~Json() { +// switch(_type) { +// case TypeString: +// if (_flags == FlagsAllocatedUnencoded) { +// delete [] _value.sval; +// //_data.trackMemory(-_count); +// _value.sval = nullptr; +// _count = 0; +// } +// break; // case TypeArray: // case TypeObject: @@ -1108,9 +1235,9 @@ Json::~Json() { // _value.aval = nullptr; // _count = 0; // break; - default: break; - } -} +// default: break; +// } +//} void Json::trackMemory(int32_t size) { @@ -1160,16 +1287,16 @@ const char* Json::string_value(string& str) const { if (!is_string()) return ""; - if (_flags == FlagsAliasedEncoded) { + //if (_flags == FlagsAliasedEncoded) { // This string length is the encoded length, so decoded should be shorter if (!decode_string(_value.sval, _count, str)) { return ""; } return str.c_str(); - } + //} // already not-encoded, so can return. When written this goes through encode. - return _value.sval; + //return _value.sval; } diff --git a/libkram/json11/json11.h b/libkram/json11/json11.h index a4be7b4d..d0c66bfb 100644 --- a/libkram/json11/json11.h +++ b/libkram/json11/json11.h @@ -93,6 +93,7 @@ class JsonWriter final { }; */ +// This code is part of kram, not json11. Will move out. // Write json nodes out to a string. String data is encoded. // This is way simpler than building up stl DOM to then write it out. // And keys go out in the order added. @@ -100,96 +101,36 @@ class JsonWriter final { public: JsonWriter(string* str) : _out(str) {} - void pushObject(const char* key = "") { - if (key[0]) - { - sprintf(*_out, "{\"%s\":\n", key); - } - else - { - _out->push_back('{'); - _out->push_back('\n'); - } - _stack.push_back('}'); - _isFirst.push_back(false); - } - void pushArray(const char* key = "") { - if (key[0]) - sprintf(*_out, "[\"%s\":\n", key); - else - { - _out->push_back('['); - _out->push_back('\n'); - } - _stack.push_back(']'); - _isFirst.push_back(false); - } + void pushObject(const char* key = ""); + void popObject(); - // can call pop() or variants to check pairing - void pop() { - KASSERT(_stack.empty()); - char c = _stack.back(); - - _out->push_back(c); - _out->push_back('\n'); - - _stack.pop_back(); - _isFirst.pop_back(); - } - void popObject() { - KASSERT(_stack.empty()); - char c = _stack.back(); - KASSERT(c == '}'); - pop(); - } - void popArray() { - KASSERT(_stack.empty()); - char c = _stack.back(); - KASSERT(c == ']'); - pop(); - } + void pushArray(const char* key = ""); + void popArray(); - void writeString(const char* key, const char* value) { - writeCommaAndNewline(); - int indent = _stack.size(); - append_sprintf(*_out, "%*s\"%s\":\"%s\"", indent, "", key, escapedString(value)); - } - void writeDouble(const char* key, double value) { - writeCommaAndNewline(); - int indent = _stack.size(); - append_sprintf(*_out, "%*s\"%s\":\"%f\"", indent, "", key, value); - } - void writeInt32(const char* key, int32_t value) { - writeCommaAndNewline(); - int indent = _stack.size(); - append_sprintf(*_out, "%*s\"%s\":\"%d\"", indent, "", key, value); - - } - void writeBool(const char* key, bool value) { - writeCommaAndNewline(); - int indent = _stack.size(); - append_sprintf(*_out, "%*s\"%s\":\"%s\"", indent, "", key, value ? "true" : "false"); - } - void writeNull(const char* key) { - writeCommaAndNewline(); - int indent = _stack.size(); - append_sprintf(*_out, "%*s\"%s\":\"%s\"", indent, "", key, "null"); - } + // keys for adding to object + void writeString(const char* key, const char* value); + void writeDouble(const char* key, double value); + void writeInt32(const char* key, int32_t value); + void writeBool(const char* key, bool value); + void writeNull(const char* key); + + // These are keyless for adding to an array + void writeString(const char* value); + void writeDouble(double value); + void writeInt32(int32_t value); + void writeBool(bool value); + void writeNull(); private: - void writeCommaAndNewline() - { - bool isFirst = _isFirst.back(); - if (!isFirst) - _out->push_back(','); - _out->push_back('\n'); - - // vector is special - _isFirst[_isFirst.size()-1] = true; - } + bool isArray() const { return _stack.back() == ']'; } + bool isObject() const { return _stack.back() == '}'; } + + void pop(); + + void writeCommaAndNewline(); const char* escapedString(const char* str); - vector _isFirst; + vector _isFirst; // could store counts string* _out = nullptr; string _stack; string _escapedString; @@ -302,59 +243,16 @@ class Json final { }; // Flags for additional data on a type - enum Flags : uint8_t { - FlagsNone = 0, - FlagsAliasedEncoded, // needs decode on read - FlagsAllocatedUnencoded, // needs encode on write - }; - - // Array/object can pass in for writer, but converted to linked nodes - using array = vector; - - // Constructors for the various types of JSON value. - Json() noexcept {} - Json(nullptr_t) noexcept {} - Json(double value) : _type(TypeNumber), _value(value) {} - Json(int value) : Json((double)value) {} - Json(bool value) : _type(TypeBoolean), _value(value) {} - - Json(const string& value) : Json(value.c_str(), value.size()) {} - Json(const char* value, uint32_t count_, bool allocated = true) - : _type(TypeString), _flags(allocated ? FlagsAllocatedUnencoded : FlagsAliasedEncoded), _count(count_), - _value(value, count_, allocated) - { - // if (allocated) trackMemory(_count); - } +// enum Flags : uint8_t { +// FlagsNone = 0, +// FlagsAliasedEncoded, // needs decode on read +// FlagsAllocatedUnencoded, // needs encode on write +// }; + + // Only public for use by sNullValue + Json() noexcept {} + //~Json(); - // This prevents Json(some_pointer) from accidentally producing a bool. Use - // Json(bool(some_pointer)) if that behavior is desired. - Json(void *) = delete; - - // has to recursively copy the entire tree of nodes, TODO: - Json(const array& values, Type type = TypeArray); - - ~Json(); - - /* Don't know if these can work - // Implicit constructor: anything with a to_json() function. - template - Json(const T & t) : Json(t.to_json()) {} - - // Implicit constructor: map-like objects (map, unordered_map, etc) - // TODO: revisit, but flatten objects to arrays -// template ().begin()->first)>::value -// && is_constructible().begin()->second)>::value, -// int>::type = 0> -// Json(const M & m) : Json(object(m.begin(), m.end())) {} - - // Implicit constructor: vector-like objects (list, vector, set, etc) - template ().begin())>::value, - int>::type = 0> - Json(const V & v) : Json(array(v.begin(), v.end())) {} - */ - // Accessors Type type() const { return _type; } @@ -386,7 +284,7 @@ class Json final { // distinguish between integer and non-integer numbers - number_value() and int_value() // can both be applied to a NUMBER-typed object. double number_value() const { return is_number() ? _value.dval : 0.0; } - float double_value() const { return number_value(); } + double double_value() const { return number_value(); } float float_value() const { return (float)number_value(); } int int_value() const { return (int)number_value(); } @@ -395,36 +293,29 @@ class Json final { // Return the enclosed string if this is a string, empty string otherwise const char* string_value(string& str) const; - // TODO: do we really need these comparisons?, typically just doing a key search - // only have to implement 2 operators - //bool operator== (const Json &rhs) const; - //bool operator< (const Json &rhs) const; - //bool operator!= (const Json &rhs) const { return !(*this == rhs); } -// bool operator<= (const Json &rhs) const { return !(rhs < *this); } -// bool operator> (const Json &rhs) const { return (rhs < *this); } -// bool operator>= (const Json &rhs) const { return !(*this < rhs); } - - // Return true if this is a JSON object and, for each item in types, has a field of - // the given type. If not, return false and set err to a descriptive message. - // typedef std::initializer_list> shape; - // bool has_shape(const shape & types, string & err) const; - // quickly find a node using immutable string - const Json & find(ImmutableString key) const; - - // useful for deleting allocated string values in block allocated nodes - // so it does a placement delete - // void deleteJsonTree(); - + const Json& find(ImmutableString key) const; + private: friend class JsonReader; // Doesn't seem to work with namespaced class void createRoot(); - // TODO: make need to expose to build up a json hierarchy for dumping + // Constructors for the various types of JSON value. + Json(nullptr_t) noexcept {} + Json(double value) : _type(TypeNumber), _value(value) {} + Json(bool value) : _type(TypeBoolean), _value(value) {} + + // only works for aliased string + Json(const char* value, uint32_t count_) + : _type(TypeString), _count(count_), _value(value) + { + } + + // Only for JsonReader void addJson(Json* json); - void addString(Json* json, const char* str, uint32_t len, Flags flags, ImmutableString key = nullptr); + void addString(Json* json, const char* str, uint32_t len, ImmutableString key = nullptr); void addNull(Json* json, ImmutableString key = nullptr); void addBoolean(Json* json, bool b, ImmutableString key = nullptr); void addNumber(Json* json, double number, ImmutableString key = nullptr); @@ -443,13 +334,11 @@ class Json final { // 2B, but needs lookup table then //uint16_t _key = 0; uint16_t _padding = 0; + uint8_t _padding1 = 0; - // 1B - really 3 bits + // 1B - really 3 bits (could pack into ptr, but check immutable align) Type _type = TypeNull; - // 1B - really 1-2 bits - Flags _flags = FlagsNone; - // 4B - count used by array/object, also by string uint32_t _count = 0; @@ -458,8 +347,8 @@ class Json final { JsonValue() : aval(nullptr) { } JsonValue(double v) : dval(v) {} JsonValue(bool v) : bval(v) {} - JsonValue(const char* v, uint32_t count, bool allocate); - JsonValue(const Json::array& value, Type t = TypeArray); + JsonValue(const char* v) : sval(v) {} + //JsonValue(const Json::array& value, Type t = TypeArray); // allocated strings deleted by Json dtor which knows type // the rest are all just block allocated