// ============================================================================ // // = LIBRARY // ULib - c++ library // // = FILENAME // value.h - Represents a JSON (JavaScript Object Notation) value // // = AUTHOR // Stefano Casazza // // ============================================================================ #ifndef ULIB_VALUE_H #define ULIB_VALUE_H 1 #include #include /** * \brief Represents a JSON value. * * This class is a discriminated union wrapper that can represents a: * * - 'null' * - boolean * - signed integer * - unsigned integer * - double * - UTF-8 string * - list of UValue * - collection of name/value pairs (javascript object) * * We stores values using NaN-boxing technique. By [IEEE-754](http://en.wikipedia.org/wiki/IEEE_floating_point) * standard we have 2^52-1 variants for encoding double's [NaN](http://en.wikipedia.org/wiki/NaN). So let's use * this to store value type and payload: * * sign * | exponent * | | * [0][11111111111][yyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] * | | * tag | * payload * * 48 bits payload [enough](http://en.wikipedia.org/wiki/X86-64#Virtual_address_space_details) for store any pointer on x64. * double use zero tag, so infinity and nan are accessible. * * The type of the held value is represented by a #ValueType and can be obtained using method getTag(). * Values of an #OBJECT_VALUE or #ARRAY_VALUE can be accessed using operator[]() methods. * It is possible to iterate over the list of a #OBJECT_VALUE values using the getMemberNames() method */ #define U_JSON_VALUE_TAG_MASK 0xF #define U_JSON_VALUE_TAG_SHIFT 47 #define U_JSON_VALUE_NAN_MASK 0x7FF8000000000000ULL #define U_JSON_VALUE_PAYLOAD_MASK 0x00007FFFFFFFFFFFULL #define U_JFIND(json,str,result) UValue::jfind(json,str,U_CONSTANT_SIZE(str),result) class UTokenizer; class UValueIter; class U_EXPORT UValue { public: // Check for memory error U_MEMORY_TEST // Allocator e Deallocator U_MEMORY_ALLOCATOR U_MEMORY_DEALLOCATOR union jval { int sint; unsigned int uint; uint64_t ival; double real; }; typedef enum ValueType { REAL_VALUE = 0, // double value INT_VALUE = 1, // signed integer value UINT_VALUE = 2, // unsigned integer value TRUE_VALUE = 3, // bool value FALSE_VALUE = 4, // bool value STRING_VALUE = 5, // string value UTF_VALUE = 6, // string value (need to be emitted) ARRAY_VALUE = 7, // array value (ordered list) OBJECT_VALUE = 8, // object value (collection of name/value pairs) NULL_VALUE = 9 // null value } ValueType; static int jsonParseFlags; // Constructors explicit UValue(double fval = 0.0) { U_TRACE_REGISTER_OBJECT(0, UValue, "%g", fval) // coverity[uninit_ctor] # ifdef U_COVERITY_FALSE_POSITIVE next = 0; pkey.ival = 0ULL; # endif value.real = fval; U_INTERNAL_DUMP("this = %p", this) } explicit UValue(ValueType tag, void* payload) { U_TRACE_REGISTER_OBJECT(0, UValue, "%d,%p", tag, payload) // coverity[uninit_ctor] # ifdef U_COVERITY_FALSE_POSITIVE next = 0; pkey.ival = 0ULL; # endif value.ival = getJsonValue(tag, payload); U_INTERNAL_DUMP("this = %p", this) } UValue(const UString& key, const UString& val) { U_TRACE_REGISTER_OBJECT(0, UValue, "%V,%V", key.rep, val.rep) UValue* node; U_NEW(UValue, node, UValue((UValue*)0)); value.ival = getJsonValue(OBJECT_VALUE, node); key.hold(); val.hold(); node->pkey.ival = getJsonValue(STRING_VALUE, key.rep); node->value.ival = getJsonValue(STRING_VALUE, val.rep); U_INTERNAL_DUMP("this = %p", this) } ~UValue(); // ASSIGNMENT void set(const UValue& v) { U_TRACE(0, "UValue::set(%p)", &v) next = v.next; pkey.ival = v.pkey.ival; value.ival = v.value.ival; } UValue(const UValue& v) { U_TRACE_REGISTER_OBJECT(0, UValue, "%p", &v) U_MEMORY_TEST_COPY(v) set(v); } UValue& operator=(const UValue& v) { U_TRACE(0, "UValue::operator=(%p)", &v) U_MEMORY_TEST_COPY(v) set(v); return *this; } #ifdef U_COMPILER_RVALUE_REFS UValue& operator=(UValue && v) { U_TRACE_NO_PARAM(0, "UValue::operator=(move)") UValue* tmpn = next; uint64_t tmpk = pkey.ival, tmpv = value.ival; next = v.next; v.next = tmpn; pkey.ival = v.pkey.ival; v.pkey.ival = tmpk; value.ival = v.value.ival; v.value.ival = tmpv; return *this; } # if (!defined(__GNUC__) || GCC_VERSION_NUM > 50300) // GCC has problems dealing with move constructor, so turn the feature on for 5.3.1 and above, only UValue(UValue && v) { U_TRACE_NO_PARAM(0, "UValue::UValue(move)") set(v); v.value.ival = 0ULL; } # endif #endif // OPERATOR bool operator==(const UValue& v) const __pure { U_TRACE(0, "UValue::operator==(%p)", &v) if (value.ival == v.value.ival) U_RETURN(true); U_RETURN(false); } bool operator!=(const UValue& v) const { return ! operator==(v); } // SERVICES void clear(); static int getTag(uint64_t val) { U_TRACE(0, "UValue::getTag(0x%x)", val) if ((int64_t)val <= (int64_t)U_JSON_VALUE_NAN_MASK) U_RETURN(REAL_VALUE); int type = (val >> U_JSON_VALUE_TAG_SHIFT) & U_JSON_VALUE_TAG_MASK; U_RETURN(type); } bool empty() const { U_TRACE_NO_PARAM(0, "UValue::empty()") if (value.ival == 0ULL) U_RETURN(true); U_RETURN(false); } bool isNull() const { U_TRACE_NO_PARAM(0+256, "UValue::isNull()") if (getTag() == NULL_VALUE) U_RETURN(true); U_RETURN(false); } bool isBool() const { U_TRACE_NO_PARAM(0+256, "UValue::isBool()") int type = getTag(); if (type == TRUE_VALUE || type == FALSE_VALUE) { U_RETURN(true); } U_RETURN(false); } bool isInt() const { U_TRACE_NO_PARAM(0, "UValue::isInt()") if (getTag() == INT_VALUE) U_RETURN(true); U_RETURN(false); } bool isUInt() const { U_TRACE_NO_PARAM(0+256, "UValue::isUInt()") if (getTag() == UINT_VALUE) U_RETURN(true); U_RETURN(false); } bool isDouble() const { U_TRACE_NO_PARAM(0, "UValue::isDouble()") if (value.ival <= (int64_t)U_JSON_VALUE_NAN_MASK) U_RETURN(true); U_RETURN(false); } bool isNumeric() const { U_TRACE_NO_PARAM(0+256, "UValue::isNumeric()") if (getTag() <= UINT_VALUE) U_RETURN(true); U_RETURN(false); } bool isString() const { U_TRACE_NO_PARAM(0+256, "UValue::isString()") if (getTag() == STRING_VALUE) U_RETURN(true); U_RETURN(false); } bool isArray() const { U_TRACE_NO_PARAM(0+256, "UValue::isArray()") if (getTag() == ARRAY_VALUE) U_RETURN(true); U_RETURN(false); } bool isObject() const { U_TRACE_NO_PARAM(0+256, "UValue::isObject()") if (getTag() == OBJECT_VALUE) U_RETURN(true); U_RETURN(false); } union jval getKey() const { return pkey; } union jval getValue() const { return value; } int getInt() const { return value.sint; } unsigned int getUInt() const { return value.uint; } UString getString() { return getString(value.ival); } int getTag() const { return getTag(value.ival); } bool getBool() const { return (getTag() == TRUE_VALUE); } double getDouble() const { return value.real; } bool isStringUTF() const { return isStringUTF(value.ival); } bool isStringOrUTF() const { return isStringOrUTF(value.ival); } bool isArrayOrObject() const { return isArrayOrObject(value.ival); } static uint32_t getStringSize(const union jval value) { return getString(value.ival).size(); } long long getNumber() const { return (isDouble() ? llrint(value.real) : (long long)(long)getPayload()); } // manage values in array or object UValue* at(uint32_t pos) const __pure; UValue* at(const char* key, uint32_t key_len) const __pure; UValue* at(const UString& key) const { return at(U_STRING_TO_PARAM(key)); } UValue& operator[](uint32_t pos) const { return *at(pos); } UValue& operator[](const UString& key) const { return *at(U_STRING_TO_PARAM(key)); } UValue& operator[](const UStringRep* key) const { return *at(U_STRING_TO_PARAM(*key)); } bool isMemberExist(const UString& key) const { return (at(U_STRING_TO_PARAM(key)) != 0); } bool isMemberExist(const UStringRep* key) const { return (at(U_STRING_TO_PARAM(*key)) != 0); } bool isMemberExist(const char* key, uint32_t key_len) const { return (at(key, key_len) != 0); } /** * \brief Return a list of the member names. * * \pre getTag() is OBJECT_VALUE * \post if getTag() was NULL_VALUE, it remains NULL_VALUE */ uint32_t getMemberNames(UVector& members) const; /** * \brief Read a UValue from a JSON document. * * \param document UTF-8 encoded string containing the document to read. * * \return \c true if the document was successfully parsed, \c false if an error occurred */ bool parse(const UString& document); /** * \brief Outputs a UValue in JSON format without formatting (not human friendly). * * The JSON document is written in a single line. It is not intended for 'human' consumption, * but may be usefull to support feature such as RPC where bandwith is limited */ UString output() const { U_TRACE_NO_PARAM(0, "UValue::output()") UString result(size+100U); pstringify = result.data(); // buffer to stringify json stringify(); result.size_adjust(pstringify); U_RETURN_STRING(result); } UString prettify() const { U_TRACE_NO_PARAM(0, "UValue::prettify()") UString result(size*2+800U); pstringify = result.data(); // buffer to stringify json prettify(0); *pstringify++ = '\n'; result.size_adjust(pstringify); U_RETURN_STRING(result); } static void stringify(UString& result, const UValue& json) { U_TRACE(0, "UValue::stringify(%V,%p)", result.rep, &json) (void) result.reserve(json.size+100U); pstringify = result.pend(); // buffer to stringify json json.stringify(); result.size_adjust(pstringify); U_INTERNAL_DUMP("result(%u) = %V", result.size(), result.rep) } template void toJSON(const UString& name, UJsonTypeHandler member) { U_TRACE(0, "UValue::toJSON(%V,%p)", name.rep, &member) addJSON(name, member); U_INTERNAL_DUMP("pnode = %p", pnode) if (pnode->toNode() == 0) { int tag = pnode->getTag(); if (tag == ARRAY_VALUE || tag == OBJECT_VALUE) { U_INTERNAL_DUMP("pnode->next = %p", pnode->next) pnode->value.ival = UValue::getJsonValue(tag, pnode->next); pnode->next = 0; } } } template void fromJSON(const UString& name, UJsonTypeHandler member) { U_TRACE(0, "UValue::fromJSON(%V,%p)", name.rep, &member) UValue* node = at(name); if (node) member.fromJSON(*node); else member.clear(); } // ======================================================================================================================= // An in-place JSON element reader (@see http://www.codeproject.com/Articles/885389/jRead-an-in-place-JSON-element-reader) // ======================================================================================================================= static int jread_error; static uint32_t jread_elements, jread_pos; static int jread(const UString& json, const UString& query, UString& result, uint32_t* queryParams = 0); static bool jfind(const UString& json, const char* query, uint32_t query_len, UString& result); static bool jfind(const UString& json, const char* query, uint32_t query_len, bool& result) { U_TRACE(0, "UValue::jfind(%V,%.*S,%u,%p)", json.rep, query_len, query, query_len, &result) UString x; if (jfind(json, query, query_len, x)) { result = x.strtob(); U_RETURN(true); } U_RETURN(false); } static bool jfind(const UString& json, const char* query, uint32_t query_len, int& result) { U_TRACE(0, "UValue::jfind(%V,%.*S,%u,%p)", json.rep, query_len, query, query_len, &result) UString x; if (jfind(json, query, query_len, x)) { result = u_strtol(x.data(), x.pend()); U_RETURN(true); } U_RETURN(false); } static bool jfind(const UString& json, const char* query, uint32_t query_len, unsigned int& result) { U_TRACE(0, "UValue::jfind(%V,%.*S,%u,%p)", json.rep, query_len, query, query_len, &result) UString x; if (jfind(json, query, query_len, x)) { result = u_strtoul(x.data(), x.pend()); U_RETURN(true); } U_RETURN(false); } static bool jfind(const UString& json, const char* query, uint32_t query_len, int64_t& result) { U_TRACE(0, "UValue::jfind(%V,%.*S,%u,%p)", json.rep, query_len, query, query_len, &result) UString x; if (jfind(json, query, query_len, x)) { result = u_strtoll(x.data(), x.pend()); U_RETURN(true); } U_RETURN(false); } static bool jfind(const UString& json, const char* query, uint32_t query_len, uint64_t& result) { U_TRACE(0, "UValue::jfind(%V,%.*S,%u,%p)", json.rep, query_len, query, query_len, &result) UString x; if (jfind(json, query, query_len, x)) { result = u_strtoull(x.data(), x.pend()); U_RETURN(true); } U_RETURN(false); } static bool jfind(const UString& json, const char* query, uint32_t query_len, double& result) { U_TRACE(0, "UValue::jfind(%V,%.*S,%u,%p)", json.rep, query_len, query, query_len, &result) UString x; if (jfind(json, query, query_len, x)) { result = x.strtod(); U_RETURN(true); } U_RETURN(false); } static bool jfind(const UString& json, const UString& query, UString& result) { return jfind(json, U_STRING_TO_PARAM(query), result); } static bool jfind(const UString& json, const UString& query, bool& result) { return jfind(json, U_STRING_TO_PARAM(query), result); } static bool jfind(const UString& json, const UString& query, int& result) { return jfind(json, U_STRING_TO_PARAM(query), result); } static bool jfind(const UString& json, const UString& query, unsigned int& result) { return jfind(json, U_STRING_TO_PARAM(query), result); } static bool jfind(const UString& json, const UString& query, int64_t& result) { return jfind(json, U_STRING_TO_PARAM(query), result); } static bool jfind(const UString& json, const UString& query, uint64_t& result) { return jfind(json, U_STRING_TO_PARAM(query), result); } static bool jfind(const UString& json, const UString& query, double& result) { return jfind(json, U_STRING_TO_PARAM(query), result); } // reads one value from an array static void jreadArrayStepInit() { jread_pos = 0; } static int jreadArrayStep(const UString& jarray, UString& result); // assumes jarray points at the start of an array or array element #ifdef DEBUG const char* dump(bool _reset) const; static const char* getJReadErrorDescription(); static const char* getDataTypeDescription(int type); #else static const char* getJReadErrorDescription() { return ""; } static const char* getDataTypeDescription(int) { return ""; } #endif protected: UValue* next; // only if binded to an object or array union jval pkey, // only if binded to an object value; static UValue* pnode; static uint32_t size; static char* pstringify; // buffer to stringify json #ifdef DEBUG static uint32_t cnt_real, cnt_mreal; #endif explicit UValue(uint64_t val) { U_TRACE_REGISTER_OBJECT(0, UValue, "0x%x", val) next = this; // coverity[uninit_ctor] # ifdef U_COVERITY_FALSE_POSITIVE pkey.ival = 0ULL; # endif value.ival = val; U_INTERNAL_DUMP("this = %p", this) } explicit UValue(UValue* node) { U_TRACE_REGISTER_OBJECT(0, UValue, "%p", node) next = node; // coverity[uninit_ctor] # ifdef U_COVERITY_FALSE_POSITIVE pkey.ival = 0ULL; # endif value.ival = 0ULL; U_INTERNAL_DUMP("this = %p", this) } explicit UValue(uint64_t val, UValue* node) { U_TRACE_REGISTER_OBJECT(0, UValue, "0x%x,%p", val, node) next = node; // coverity[uninit_ctor] # ifdef U_COVERITY_FALSE_POSITIVE pkey.ival = 0ULL; # endif value.ival = val; U_INTERNAL_DUMP("this = %p", this) } void emitUTF(UStringRep* rep) const; void emitString(UStringRep* rep) const { U_TRACE(0, "UValue::emitString(%p)", rep) U_INTERNAL_DUMP("rep = %V", rep) *pstringify++ = '"'; if (rep != UStringRep::string_rep_null) { uint32_t sz = rep->size(); U_MEMCPY(pstringify, rep->data(), sz); pstringify += sz; } *pstringify++ = '"'; } void emitKey() const { U_TRACE_NO_PARAM(0, "UValue::emitKey()") int type = getTag(pkey.ival); if (type == STRING_VALUE) emitString((UStringRep*)getPayload(pkey.ival)); else { U_INTERNAL_ASSERT_EQUALS(type, UTF_VALUE) emitUTF((UStringRep*)getPayload(pkey.ival)); } } void setTag(int tag) { U_TRACE(0, "UValue::setTag(%d)", tag) value.ival = getJsonValue(tag, (void*)getPayload()); } void stringify() const; void prettify(uint32_t indent) const; UValue* toNode() const { return toNode(value.ival); } uint64_t getPayload() const { return getPayload(value.ival); } static UValue* toNode(uint64_t val) { U_TRACE(0, "UValue::toNode(0x%x)", val) UValue* ptr = (UValue*)getPayload(val); U_RETURN_POINTER(ptr, UValue); } static uint64_t getPayload(uint64_t val) { U_TRACE(0, "UValue::getPayload(0x%x)", val) return ((uint64_t)(val & U_JSON_VALUE_PAYLOAD_MASK)); } static bool isStringUTF(uint64_t value) { U_TRACE(0+256, "UValue::isStringUTF(0x%x)", value) if (getTag(value) == UTF_VALUE) U_RETURN(true); U_RETURN(false); } static bool isStringOrUTF(uint64_t value) { U_TRACE(0+256, "UValue::isStringOrUTF(0x%x)", value) int type = getTag(value); if (type == STRING_VALUE || type == UTF_VALUE) { U_RETURN(true); } U_RETURN(false); } static bool isArrayOrObject(uint64_t value) { U_TRACE(0+256, "UValue::isArrayOrObject(0x%x)", value) int type = getTag(value); if (type == ARRAY_VALUE || type == OBJECT_VALUE) { U_RETURN(true); } U_RETURN(false); } static uint64_t getJsonValue(int tag, void* payload) { U_TRACE(0, "UValue::getJsonValue(%d,%p)", tag, payload) U_INTERNAL_ASSERT(payload <= (void*)U_JSON_VALUE_PAYLOAD_MASK) return U_JSON_VALUE_NAN_MASK | ((uint64_t)tag << U_JSON_VALUE_TAG_SHIFT) | (uint64_t)payload; } static uint64_t listToValue(ValueType tag, UValue* tail) { U_TRACE(0, "UValue::listToValue(%d,%p)", tag, tail) if (tail) { UValue* head = tail->next; tail->next = 0; return getJsonValue(tag, head); } return getJsonValue(tag, 0); } static UValue* insertAfter(UValue* tail, uint64_t value) { U_TRACE(0, "UValue::insertAfter(%p,0x%x)", tail, value) UValue* node; if (tail) { U_NEW(UValue, node, UValue(value, tail->next)); tail->next = node; } else { U_NEW(UValue, node, UValue(value)); } U_RETURN_POINTER(node, UValue); } void setString(UStringRep* rep) { U_TRACE(0, "UValue::setString(%p)", rep) U_INTERNAL_DUMP("rep = %V", rep) rep->hold(); value.ival = getJsonValue(STRING_VALUE, rep); } static UString getString(uint64_t value); template void addJSON(UJsonTypeHandler member) { U_TRACE(0, "UValue::addJSON(%p)", &member) UValue* node; U_NEW(UValue, node, UValue((UValue*)0)); U_INTERNAL_DUMP("pnode = %p", pnode) if (pnode) pnode->next = node; else { value.ival = UValue::getJsonValue(isArray() ? UValue::ARRAY_VALUE : UValue::OBJECT_VALUE, node); } member.toJSON(*(pnode = node)); pnode = node; } template void addJSON(const UString& name, UJsonTypeHandler member) { U_TRACE(0, "UValue::addJSON(%V,%p)", name.rep, &member) name.hold(); addJSON(member); pnode->pkey.ival = getJsonValue(STRING_VALUE, name.rep); } private: static int jread_skip(UTokenizer& tok) U_NO_EXPORT; static int jreadFindToken(UTokenizer& tok) U_NO_EXPORT; static UString jread_string(UTokenizer& tok) U_NO_EXPORT; static UString jread_object(UTokenizer& tok) U_NO_EXPORT; static UString jread_object(UTokenizer& tok, uint32_t keyIndex) U_NO_EXPORT; friend class UValueIter; friend class UTokenizer; friend UValueIter begin(const union jval); template friend class UVector; template friend class UHashMap; template friend class UJsonTypeHandler; template friend void JSON_stringify(UString&, UValue&, T&); }; #if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX11) class UValueIter { // this class is to make work Range-based for loop: for ( auto i : UValue ) loop_statement public: explicit UValueIter(const UValue* p) : _p(p) {} // these three methods form the basis of an iterator for use with a range-based for loop bool operator!=(const UValueIter& other) const { return (_p != other._p); } const UValue& operator*() const { return *_p; } const UValueIter& operator++() { _p = _p->next; // although not strictly necessary for a range-based for loop // following the normal convention of returning a value from // operator++ is a good idea return *this; } private: const UValue* _p; }; inline UValueIter end( const union UValue::jval) { return UValueIter(0); } inline UValueIter begin(const union UValue::jval v) { return UValueIter(UValue::toNode(v.ival)); } #endif class U_EXPORT UJsonTypeHandler_Base { public: // Check for memory error U_MEMORY_TEST // Allocator e Deallocator U_MEMORY_ALLOCATOR U_MEMORY_DEALLOCATOR UJsonTypeHandler_Base(const void* ptr) : pval((void*)ptr) { U_TRACE_REGISTER_OBJECT(0, UJsonTypeHandler_Base, "%p", ptr) U_INTERNAL_ASSERT_POINTER(pval) } ~UJsonTypeHandler_Base() { U_TRACE_UNREGISTER_OBJECT(0, UJsonTypeHandler_Base) U_INTERNAL_ASSERT_POINTER(pval) } #ifdef DEBUG const char* dump(bool _reset) const; #endif protected: void* pval; private: U_DISALLOW_ASSIGN(UJsonTypeHandler_Base) }; #define U_JSON_METHOD_HANDLER(name_object_member, type_object_member) \ U_STRING_FROM_CONSTANT(#name_object_member), UJsonTypeHandler(name_object_member) #define U_JSON_TYPE_HANDLER(class_name, name_object_member, type_object_member) \ U_STRING_FROM_CONSTANT(#name_object_member), UJsonTypeHandler(((class_name*)pval)->name_object_member) /** * Provide template specializations to support your own complex types * * Take as example the following (simplified) class: * * class Person { * public: * int age; * UString lastName; * UString firstName; * }; * * The UJsonTypeHandler must provide a custom toJSON and fromJSON method: * * template <> class UJsonTypeHandler : public UJsonTypeHandler_Base { * public: * explicit UJsonTypeHandler(Person& val) : UJsonTypeHandler_Base(&val) * * void toJSON(UValue& json) * { * json.toJSON(U_JSON_TYPE_HANDLER(Person, age, int)); * json.toJSON(U_JSON_TYPE_HANDLER(Person, lastName, UString)); * json.toJSON(U_JSON_TYPE_HANDLER(Person, firstName, UString)); * } * * void fromJSON(UValue& json) * { * json.fromJSON(U_JSON_TYPE_HANDLER(Person, age, int)); * json.fromJSON(U_JSON_TYPE_HANDLER(Person, lastName, UString)); * json.fromJSON(U_JSON_TYPE_HANDLER(Person, firstName, UString)); * } * }; * * or in alternative add this methods to the (simplified) class: * * void Person::clear() * { * age = 0; * lastName.clear(); * firstName.clear(); * } * * void Person::toJSON(UValue& json) * { * json.toJSON(U_JSON_METHOD_HANDLER(age, int)); * json.toJSON(U_JSON_METHOD_HANDLER( lastName, UString)); * json.toJSON(U_JSON_METHOD_HANDLER(firstName, UString)); * } * * void Person::fromJSON(UValue& json) * { * json.fromJSON(U_JSON_METHOD_HANDLER(age, int)); * json.fromJSON(U_JSON_METHOD_HANDLER( lastName, UString)); * json.fromJSON(U_JSON_METHOD_HANDLER(firstName, UString)); * } */ template class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(T* val) : UJsonTypeHandler_Base( val) {} explicit UJsonTypeHandler(T& val) : UJsonTypeHandler_Base(&val) {} // SERVICES void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") ((T*)pval)->clear(); // method alternative } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.setTag(UValue::OBJECT_VALUE); ((T*)pval)->toJSON(json); // method alternative } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) ((T*)pval)->fromJSON(json); // method alternative } private: U_DISALLOW_ASSIGN(UJsonTypeHandler) }; // manage object <=> JSON representation template bool JSON_parse(const UString& str, T& obj) { U_TRACE(0, "JSON_parse(%p,%p)", &str, &obj) UValue json; if (json.parse(str)) { UJsonTypeHandler(obj).fromJSON(json); U_RETURN(true); } U_RETURN(false); } template void JSON_stringify(UString& result, UValue& json, T& obj) { U_TRACE(0, "JSON_stringify(%V,%p,%p)", result.rep, &json, &obj) U_ASSERT(json.empty()) UValue::pnode = 0; UJsonTypeHandler(obj).toJSON(json); UValue::stringify(result, json); } // TEMPLATE SPECIALIZATIONS template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(null&) : UJsonTypeHandler_Base(0) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(UValue::NULL_VALUE, 0); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) U_VAR_UNUSED(json) } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(bool& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(bool*)pval = false; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(*(bool*)pval ? UValue::TRUE_VALUE : UValue::FALSE_VALUE, 0); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(bool*)pval = json.getBool(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(char& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(char*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(UValue::UINT_VALUE, (void*)(*(char*)pval & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(char*)pval = json.getUInt(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(unsigned char& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(unsigned char*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(UValue::UINT_VALUE, (void*)(*(unsigned char*)pval & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(unsigned char*)pval = json.getUInt(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(short& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(short*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(UValue::UINT_VALUE, (void*)(*(short*)pval & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(short*)pval = json.getUInt(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(unsigned short& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(unsigned short*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(UValue::UINT_VALUE, (void*)(*(unsigned short*)pval & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(unsigned short*)pval = json.getUInt(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(int& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(int*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(UValue::INT_VALUE, (void*)(*(int*)pval & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(int*)pval = json.getInt(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(unsigned int& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(unsigned int*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(UValue::UINT_VALUE, (void*)(*(unsigned int*)pval & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(unsigned int*)pval = json.getUInt(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(long& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(long*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) long l = *(long*)pval; int type = (l > (long)UINT_MAX || l < (long)INT_MAX ? UValue::REAL_VALUE : l > 0 ? UValue::UINT_VALUE : UValue::INT_VALUE); json.value.ival = UValue::getJsonValue(type, (void*)(l & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(long*)pval = json.getNumber(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(unsigned long& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(unsigned long*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) unsigned long l = *(unsigned long*)pval; json.value.ival = UValue::getJsonValue(l > UINT_MAX ? UValue::REAL_VALUE : UValue::UINT_VALUE, (void*)(l & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(unsigned long*)pval = json.getNumber(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(long long& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(long long*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) long long l = *(long long*)pval; int type = (l > UINT_MAX || l < INT_MAX ? UValue::REAL_VALUE : l > 0 ? UValue::UINT_VALUE : UValue::INT_VALUE); json.value.ival = UValue::getJsonValue(type, (void*)(l & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(long long*)pval = json.getNumber(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(unsigned long long& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(unsigned long long*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) unsigned long long l = *(unsigned long long*)pval; json.value.ival = UValue::getJsonValue(l > UINT_MAX ? UValue::REAL_VALUE : UValue::UINT_VALUE, (void*)(l & 0x00000000FFFFFFFFULL)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(unsigned long long*)pval = json.getNumber(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(float& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(float*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(UValue::REAL_VALUE, (void*)lrintf(*(float*)pval)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(float*)pval = json.getDouble(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(double& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(double*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.value.ival = UValue::getJsonValue(UValue::REAL_VALUE, (void*)lrint(*(double*)pval)); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(double*)pval = json.getDouble(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(long double& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") *(long double*)pval = 0; } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) # ifdef HAVE_LRINTL json.value.ival = UValue::getJsonValue(UValue::REAL_VALUE, (void*)lrintl(*(long double*)pval)); # else json.value.ival = UValue::getJsonValue(UValue::REAL_VALUE, (void*)lrint(*(double*)pval)); # endif } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) *(long double*)pval = json.getDouble(); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(UStringRep& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") U_ERROR("UJsonTypeHandler::fromJSON(): sorry, we cannot use UStringRep type from JSON type handler..."); } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.setString((UStringRep*)pval); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) U_VAR_UNUSED(json) U_ASSERT(json.isString()) U_INTERNAL_DUMP("pval(%p) = %p rep(%p) = %V", pval, pval, json.getPayload(), json.getPayload()) U_ERROR("UJsonTypeHandler::fromJSON(): sorry, we cannot use UStringRep type from JSON type handler..."); } }; template <> class U_EXPORT UJsonTypeHandler : public UJsonTypeHandler_Base { public: explicit UJsonTypeHandler(UString& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") U_INTERNAL_DUMP("pval(%p) = %V", pval, ((UString*)pval)->rep, ((UString*)pval)->rep) ((UString*)pval)->clear(); } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.setString(((UString*)pval)->rep); } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) U_ASSERT(json.isString()) UStringRep* rep = (UStringRep*)json.getPayload(); U_INTERNAL_DUMP("pval(%p) = %p rep(%p) = %V", pval, ((UString*)pval)->rep, rep, rep) ((UString*)pval)->_assign(rep); U_INTERNAL_ASSERT(((UString*)pval)->invariant()) } }; // TEMPLATE SPECIALIZATIONS FOR CONTAINERS template class U_EXPORT UJsonTypeHandler > : public UJsonTypeHandler_Base { public: typedef UVector uvector; explicit UJsonTypeHandler(uvector& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") ((uvector*)pval)->clear(); } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.setTag(UValue::ARRAY_VALUE); uvector* pvec = (uvector*)pval; if (pvec->_length) { const void** ptr = pvec->vec; const void** end = pvec->vec + pvec->_length; # ifndef HAVE_OLD_IOSTREAM do { json.addJSON(UJsonTypeHandler(*(T*)(*ptr))); } while (++ptr < end); # endif } } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) U_ASSERT(((uvector*)pval)->empty()) UValue* pelement = json.toNode(); while (pelement) { T* pitem; U_NEW(T, pitem, T); U_DUMP("pelement = %p pelement->next = %p pelement->type = (%d,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(*pitem).fromJSON(*pelement); ((UVector*)pval)->push_back(pitem); pelement = pelement->next; } } }; template <> class U_EXPORT UJsonTypeHandler > : public UJsonTypeHandler > { public: typedef UVector uvectorbase; explicit UJsonTypeHandler(UVector& val) : UJsonTypeHandler(*((uvector*)&val)) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler>::clear()") ((UVector*)pval)->clear(); } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler>::toJSON(%p)", &json) json.setTag(UValue::ARRAY_VALUE); uvectorbase* pvec = (uvectorbase*)pval; if (pvec->_length) { const void** ptr = pvec->vec; const void** end = pvec->vec + pvec->_length; do { UString item((const UStringRep*)(*ptr)); json.addJSON(UJsonTypeHandler(item)); } while (++ptr < end); } } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler>::fromJSON(%p)", &json) U_ASSERT(((UVector*)pval)->empty()) UValue* pelement = json.toNode(); while (pelement) { UString item; U_DUMP("pelement = %p pelement->next = %p pelement->type = (%d,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(item).fromJSON(*pelement); ((UVector*)pval)->push_back(item); pelement = pelement->next; } } }; template class U_EXPORT UJsonTypeHandler > : public UJsonTypeHandler_Base { public: typedef UHashMap uhashmap; explicit UJsonTypeHandler(uhashmap& map) : UJsonTypeHandler_Base(&map) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") ((uhashmap*)pval)->clear(); } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.setTag(UValue::OBJECT_VALUE); uhashmap* pmap = (uhashmap*)pval; if (pmap->first()) { do { # ifndef HAVE_OLD_IOSTREAM json.addJSON(pmap->getKey(), UJsonTypeHandler(*(pmap->elem()))); # endif } while (pmap->next()); } } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) U_ASSERT(((uhashmap*)pval)->empty()) UValue* pelement = json.toNode(); while (pelement) { T* pitem; U_NEW(T, pitem, T); U_DUMP("pelement = %p pelement->next = %p pelement->type = (%d,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(*pitem).fromJSON(*pelement); UStringRep* rep = (UStringRep*)UValue::getPayload(pelement->pkey.ival); U_INTERNAL_DUMP("pelement->pkey(%p) = %V", rep, rep) ((uhashmap*)pval)->lookup(rep); ((uhashmap*)pval)->insertAfterFind(rep, pitem); pelement = pelement->next; } } }; template <> class U_EXPORT UJsonTypeHandler > : public UJsonTypeHandler > { public: typedef UHashMap uhashmapbase; explicit UJsonTypeHandler(UHashMap& val) : UJsonTypeHandler(*((uhashmap*)&val)) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler>::clear()") ((UHashMap*)pval)->clear(); } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler>::toJSON(%p)", &json) json.setTag(UValue::OBJECT_VALUE); UHashMap* pmap = (UHashMap*)pval; if (pmap->first()) { do { UString item((const UStringRep*)pmap->elem()); json.addJSON(pmap->getKey(), UJsonTypeHandler(item)); } while (pmap->next()); } } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler>::fromJSON(%p)", &json) U_ASSERT(((UHashMap*)pval)->empty()) UValue* pelement = json.toNode(); while (pelement) { UString item; U_DUMP("pelement = %p pelement->next = %p pelement->type = (%d,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(item).fromJSON(*pelement); UStringRep* rep = (UStringRep*)UValue::getPayload(pelement->pkey.ival); U_INTERNAL_DUMP("pelement->pkey(%p) = %V", rep, rep) ((UHashMap*)pval)->lookup(rep); ((uhashmapbase*)pval)->insertAfterFind(rep, item.rep); pelement = pelement->next; } } }; #if defined(U_STDCPP_ENABLE) # include template class U_EXPORT UJsonTypeHandler > : public UJsonTypeHandler_Base { public: typedef std::vector stdvector; explicit UJsonTypeHandler(stdvector& val) : UJsonTypeHandler_Base(&val) {} void clear() { U_TRACE_NO_PARAM(0, "UJsonTypeHandler::clear()") // TODO } void toJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::toJSON(%p)", &json) json.setTag(UValue::ARRAY_VALUE); stdvector* pvec = (stdvector*)pval; # ifndef HAVE_OLD_IOSTREAM for (uint32_t i = 0, n = pvec->size(); i < n; ++i) json.addJSON(UJsonTypeHandler(pvec->at(i))); # endif } void fromJSON(UValue& json) { U_TRACE(0, "UJsonTypeHandler::fromJSON(%p)", &json) // U_ASSERT(((stdvector*)pval)->empty()) UValue* pelement = json.toNode(); while (pelement) { T item; U_DUMP("pelement = %p pelement->next = %p pelement->type = (%d,%S)", pelement, pelement->next, pelement->getTag(), UValue::getDataTypeDescription(pelement->getTag())) UJsonTypeHandler(item).fromJSON(*pelement); ((stdvector*)pval)->push_back(item); pelement = pelement->next; } } }; #endif #endif