#include "JSONSerializer.hpp" #include "../common/compat.hpp" #include <cmath> #include <stdlib.h> #ifndef SPRAWL_STRICT_JSON # define SPRAWL_STRICT_JSON 0 #endif #ifdef _WIN32 # define snprintf _snprintf #endif namespace sprawl { namespace serialization { JSONToken JSONToken::staticEmpty(JSONToken::JSONType::Empty); JSONToken const& JSONToken::operator[](sprawl::String const& key) const { if( m_holder->m_type != JSONType::Object ) { return staticEmpty; } StringData keyData(key.c_str(), key.length()); auto it = m_holder->m_objectChildren->find( keyData ); if( it == m_holder->m_objectChildren->end() ) { return staticEmpty; } return it.Value(); } JSONToken const& JSONToken::operator[](ssize_t index) const { if( m_holder->m_type != JSONType::Array || index >= m_holder->m_arrayChildren.Size() ) { return staticEmpty; } return m_holder->m_arrayChildren[index]; } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::operator[](sprawl::String const& key) { StringData keyData(key.c_str(), key.length()); if( m_holder->m_type != JSONType::Object ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } auto it = m_holder->m_objectChildren->find( keyData ); if( it == m_holder->m_objectChildren->end() ) { keyData.CommitStorage(); auto it = m_holder->m_objectChildren->Insert( JSONToken( keyData, JSONType::Empty ) ); return it.Value(); } return it.Value(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::operator[](ssize_t index) { if( m_holder->m_type != JSONType::Array || index >= m_holder->m_arrayChildren.Size() ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } return m_holder->m_arrayChildren[index]; } size_t JSONToken::Size() { switch( m_holder->m_type ) { case JSONType::Object: { return m_holder->m_objectChildren->Size(); } case JSONType::Array: { return size_t(m_holder->m_arrayChildren.Size()); } case JSONType::Null: case JSONType::Empty: { return 0; } case JSONType::Boolean: case JSONType::Double: case JSONType::Integer: case JSONType::String: default: { return 1; } } } sprawl::String JSONToken::ToJSONString(bool pretty) { sprawl::StringBuilder outString; BuildJSONString(outString, pretty, 1); return outString.Str(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::PushBack(JSONToken const& token) { if( m_holder->m_type != JSONType::Array ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } m_holder->m_arrayChildren.EmplaceBack( token ); return m_holder->m_arrayChildren.Back(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::PushBack(unsigned long long value) { if( m_holder->m_type != JSONType::Array ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } m_holder->m_arrayChildren.EmplaceBack( JSONType::Integer, value ); return m_holder->m_arrayChildren.Back(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::PushBack(long long value) { if( m_holder->m_type != JSONType::Array ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } m_holder->m_arrayChildren.EmplaceBack( JSONType::Integer, value ); return m_holder->m_arrayChildren.Back(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::PushBack(long double value) { if( m_holder->m_type != JSONType::Array ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } m_holder->m_arrayChildren.EmplaceBack( JSONType::Double, value ); return m_holder->m_arrayChildren.Back(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::PushBack(bool value) { if( m_holder->m_type != JSONType::Array ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } m_holder->m_arrayChildren.EmplaceBack( JSONType::Boolean, value ); return m_holder->m_arrayChildren.Back(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::PushBack(const char* const value) { if( m_holder->m_type != JSONType::Array ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } m_holder->m_arrayChildren.EmplaceBack( JSONType::String, sprawl::String(value) ); return m_holder->m_arrayChildren.Back(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::PushBack(const char* const value, size_t length) { if( m_holder->m_type != JSONType::Array ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } m_holder->m_arrayChildren.EmplaceBack( JSONType::String, sprawl::String(value, length) ); return m_holder->m_arrayChildren.Back(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::PushBack(sprawl::String const& value) { if( m_holder->m_type != JSONType::Array ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } m_holder->m_arrayChildren.EmplaceBack( JSONType::String, value ); return m_holder->m_arrayChildren.Back(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::Insert(sprawl::String const& name, JSONToken const& token) { if( m_holder->m_type != JSONType::Object ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } StringData nameData(name.c_str(), name.length()); nameData.CommitStorage(); auto it = m_holder->m_objectChildren->Insert( JSONToken(nameData, token) ); return it.Value(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::Insert(sprawl::String const& name, unsigned long long value) { if( m_holder->m_type != JSONType::Object ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } StringData nameData(name.c_str(), name.length()); nameData.CommitStorage(); auto it = m_holder->m_objectChildren->Insert( JSONToken(nameData, JSONType::Integer, value) ); return it.Value(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::Insert(sprawl::String const& name, long long value) { if( m_holder->m_type != JSONType::Object ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } StringData nameData(name.c_str(), name.length()); nameData.CommitStorage(); auto it = m_holder->m_objectChildren->Insert( JSONToken(nameData, JSONType::Integer, value) ); return it.Value(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::Insert(sprawl::String const& name, long double value) { if( m_holder->m_type != JSONType::Object ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } StringData nameData(name.c_str(), name.length()); nameData.CommitStorage(); auto it = m_holder->m_objectChildren->Insert( JSONToken(nameData, JSONType::Double, value) ); return it.Value(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::Insert(sprawl::String const& name, bool value) { if( m_holder->m_type != JSONType::Object ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } StringData nameData(name.c_str(), name.length()); nameData.CommitStorage(); auto it = m_holder->m_objectChildren->Insert( JSONToken(nameData, JSONType::Boolean, value) ); return it.Value(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::Insert(sprawl::String const& name, const char* const value) { if( m_holder->m_type != JSONType::Object ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } StringData nameData(name.c_str(), name.length()); nameData.CommitStorage(); auto it = m_holder->m_objectChildren->Insert( JSONToken(nameData, JSONType::String, sprawl::String(value)) ); return it.Value(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::Insert(sprawl::String const& name, const char* const value, size_t length) { if( m_holder->m_type != JSONType::Object ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } StringData nameData(name.c_str(), name.length()); nameData.CommitStorage(); auto it = m_holder->m_objectChildren->Insert( JSONToken(nameData, JSONType::String, sprawl::String(value, length)) ); return it.Value(); } SPRAWL_WARN_UNUSED_RESULT ErrorState<JSONToken&> JSONToken::Insert(sprawl::String const& name, sprawl::String const& value) { if( m_holder->m_type != JSONType::Object ) { SPRAWL_THROW_EXCEPTION(sprawl::InvalidJsonData()); } StringData nameData(name.c_str(), name.length()); nameData.CommitStorage(); auto it = m_holder->m_objectChildren->Insert( JSONToken(nameData, JSONType::String, value) ); return it.Value(); } JSONToken::JSONToken(JSONToken::JSONType statedType, sprawl::String const& data) : m_holder(Holder::Create()) , m_key(nullptr, 0) { ::new(m_holder) Holder(statedType); m_holder->m_data = StringData(data.c_str(), data.length()); m_holder->m_data.CommitStorage(); } JSONToken::JSONToken(JSONToken::JSONType statedType, bool data) : m_holder(Holder::Create()) , m_key(nullptr, 0) { ::new(m_holder) Holder(statedType); if(data) { m_holder->m_data = StringData( "true", 4 ); } else { m_holder->m_data = StringData( "false", 5 ); } } JSONToken::JSONToken(JSONToken::JSONType statedType) : m_holder(Holder::Create()) , m_key(nullptr, 0) { ::new(m_holder) Holder(statedType); } JSONToken::JSONToken(JSONToken::JSONType statedType, long long data) : m_holder(Holder::Create()) , m_key(nullptr, 0) { ::new(m_holder) Holder(statedType); char buf[128]; snprintf( buf, 128, "%lld", data ); m_holder->m_data = StringData( buf, strlen( buf ) ); m_holder->m_data.CommitStorage(); } JSONToken::JSONToken(JSONToken::JSONType statedType, unsigned long long data) : m_holder(Holder::Create()) , m_key(nullptr, 0) { ::new(m_holder) Holder(statedType); char buf[128]; snprintf( buf, 128, "%llu", data ); m_holder->m_data = StringData( buf, strlen( buf ) ); m_holder->m_data.CommitStorage(); } JSONToken::JSONToken(JSONToken::JSONType statedType, long double data) : m_holder(Holder::Create()) , m_key(nullptr, 0) { ::new(m_holder) Holder(statedType); char buf[128]; snprintf( buf, 128, "%.20Lg", data ); m_holder->m_data = StringData( buf, strlen( buf ) ); m_holder->m_data.CommitStorage(); } JSONToken::JSONToken(StringData const& myKey, JSONToken::JSONType statedType, sprawl::String const& data) : m_holder(Holder::Create()) , m_key(myKey) { m_key.CommitStorage(); ::new(m_holder) Holder(statedType); m_holder->m_data = StringData(data.c_str(), data.length()); m_holder->m_data.CommitStorage(); } JSONToken::JSONToken(StringData const& myKey, JSONToken::JSONType statedType, bool data) : m_holder(Holder::Create()) , m_key(myKey) { m_key.CommitStorage(); ::new(m_holder) Holder(statedType); if(data) { m_holder->m_data = StringData( "true", 4 ); } else { m_holder->m_data = StringData( "false", 5 ); } } JSONToken::JSONToken(StringData const& myKey, JSONToken::JSONType statedType) : m_holder(Holder::Create()) , m_key(myKey) { m_key.CommitStorage(); ::new(m_holder) Holder(statedType); } JSONToken::JSONToken(StringData const& myKey, JSONToken::JSONType statedType, long long data) : m_holder(Holder::Create()) , m_key(myKey) { m_key.CommitStorage(); ::new(m_holder) Holder(statedType); char buf[128]; snprintf( buf, 128, "%lld", data ); m_holder->m_data = StringData( buf, strlen( buf ) ); m_holder->m_data.CommitStorage(); } JSONToken::JSONToken(StringData const& myKey, JSONToken::JSONType statedType, unsigned long long data) : m_holder(Holder::Create()) , m_key(myKey) { m_key.CommitStorage(); ::new(m_holder) Holder(statedType); char buf[128]; snprintf( buf, 128, "%llu", data ); m_holder->m_data = StringData( buf, strlen( buf ) ); m_holder->m_data.CommitStorage(); } JSONToken::JSONToken(StringData const& myKey, JSONToken::JSONType statedType, long double data) : m_holder(Holder::Create()) , m_key(myKey) { m_key.CommitStorage(); ::new(m_holder) Holder(statedType); char buf[128]; snprintf( buf, 128, "%.20Lg", data ); m_holder->m_data = StringData( buf, strlen( buf ) ); m_holder->m_data.CommitStorage(); } JSONToken* JSONToken::Create() { typedef memory::PoolAllocator<sizeof(JSONToken)> allocator; return (JSONToken*)allocator::alloc(); } void JSONToken::Free(JSONToken* token) { typedef memory::PoolAllocator<sizeof(JSONToken)> allocator; token->~JSONToken(); allocator::free(token); } void JSONToken::BuildJSONString(StringBuilder& outString, bool pretty, int tabDepth) { if( m_holder->m_type == JSONType::Object ) { outString << "{"; if( pretty ) { outString << "\n"; } else { outString << " "; } bool first = true; for( auto kvp : *m_holder->m_objectChildren ) { if(kvp.Value().IsEmpty()) { continue; } if( !first ) { outString << ","; if( pretty ) { outString << "\n"; } else { outString << " "; } } if( pretty ) { for( int i = 0; i < tabDepth; ++i ) { outString << "\t"; } } outString << "\""; outString << sprawl::String( sprawl::StringRef( kvp.Key().c_str(), kvp.Key().length() ) ); outString << "\" : "; kvp.Value().BuildJSONString( outString, pretty, tabDepth + 1 ); first = false; } if( pretty ) { outString << "\n"; for( int i = 0; i < tabDepth - 1; ++i ) { outString << "\t"; } } else { outString << " "; } outString << "}"; } else if( m_holder->m_type == JSONType::Array ) { outString << "["; if( pretty ) { outString << "\n"; } else { outString << " "; } bool first = true; for( auto& it : m_holder->m_arrayChildren ) { if(it.IsEmpty()) { continue; } if( !first ) { outString << ","; if( pretty ) { outString << "\n"; } else { outString << " "; } } if( pretty ) { for( int i = 0; i < tabDepth; ++i ) { outString << "\t"; } } it.BuildJSONString( outString, pretty, tabDepth + 1 ); first = false; } if( pretty ) { outString << "\n"; for( int i = 0; i < tabDepth - 1; ++i ) { outString << "\t"; } } else { outString << " "; } outString << "]"; } else if( m_holder->m_type == JSONType::Null ) { outString << "null"; } else if(m_holder->m_type == JSONType::String) { outString << "\""; outString << EscapeString(m_holder->m_data); outString << "\""; } else { outString << sprawl::String( sprawl::StringRef( m_holder->m_data.c_str(), m_holder->m_data.length() ) ); } } /// TODO PERFORMANCE: Replace sprawl::String here with a non-ref-counted string class that will simply store a pointer and a length with no allocations void JSONToken::SkipWhitespace(char const*& data) { while(*data == ' ' || *data == '\t' || *data == '\n' || *data == '\r') ++data; } void JSONToken::CollectString(char const*& data) { ++data; while(*data != '\"') { if(SPRAWL_UNLIKELY(*data == '\\')) { ++data; } ++data; } ++data; } void JSONToken::ParseString(char const*& data) { char const* startPoint = data + 1; CollectString(data); m_holder->m_data = StringData(startPoint, data - startPoint - 1); } void JSONToken::ParseNumber(char const*& data) { char const* startPoint = data; for(;;) { switch( *data ) { case '-': case '+': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { ++data; break; } case '.': case 'e': case 'E': { if( m_holder->m_type == JSONType::Integer ) { m_holder->m_type = JSONType::Double; } ++data; break; } default: { m_holder->m_data = StringData(startPoint, data - startPoint); return; } } } } void JSONToken::ParseBool(char const*& data) { if( *data == 't' #if SPRAWL_STRICT_JSON && *(data + 1) == 'r' && *(data + 2) == 'u' && *(data + 3) == 'e' #endif ) { m_holder->m_data = StringData(data, 4); data += 4; } else if( *data == 'f' #if SPRAWL_STRICT_JSON && *(data + 1) == 'a' && *(data + 2) == 'l' && *(data + 3) == 's' && *(data + 4) == 'e' #endif ) { m_holder->m_data = StringData(data, 5); data += 5; } #if SPRAWL_STRICT_JSON else { SPRAWL_THROW_EXCEPTION_OR_ABORT(sprawl::InvalidJsonData()); } #endif return; } void JSONToken::ParseArray(char const*& data) { ++data; for(;;) { SkipWhitespace(data); if(*data == ']') { ++data; return; } switch(*data) { case '{': { m_holder->m_arrayChildren.EmplaceBack( StringData(nullptr, 0), data, JSONType::Object ); break; } case '[': { m_holder->m_arrayChildren.EmplaceBack( StringData(nullptr, 0), data, JSONType::Array ); break; } case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { m_holder->m_arrayChildren.EmplaceBack( StringData(nullptr, 0), data, JSONType::Integer ); break; } case '\"': { m_holder->m_arrayChildren.EmplaceBack( StringData(nullptr, 0), data, JSONType::String ); break; } case 't': case 'f': { m_holder->m_arrayChildren.EmplaceBack( StringData(nullptr, 0), data, JSONType::Boolean ); break; } case 'n': { m_holder->m_arrayChildren.EmplaceBack( JSONType::Null ); data += 4; break; } #if SPRAWL_STRICT_JSON default: { SPRAWL_THROW_EXCEPTION_OR_ABORT(sprawl::InvalidJsonData()); } #endif } SkipWhitespace(data); #if SPRAWL_STRICT_JSON if(*data != ',' && *data != ']') { SPRAWL_THROW_EXCEPTION_OR_ABORT(sprawl::InvalidJsonData()); } #endif if(*data == ']') { ++data; break; } ++data; } } void JSONToken::ParseObject(char const*& data) { ++data; StringData key(nullptr, 0); for(;;) { SkipWhitespace(data); if(*data == '}') { ++data; return; } #if SPRAWL_STRICT_JSON if(*data != '\"') { SPRAWL_THROW_EXCEPTION_OR_ABORT(sprawl::InvalidJsonData()); } #endif char const* keyStart = nullptr; char const* keyEnd = nullptr; keyStart = data + 1; CollectString(data); keyEnd = data - 1; key = StringData( keyStart, keyEnd - keyStart ); SkipWhitespace(data); #if SPRAWL_STRICT_JSON if(*data != ':') { SPRAWL_THROW_EXCEPTION_OR_ABORT(sprawl::InvalidJsonData()); } #endif ++data; SkipWhitespace(data); switch(*data) { case '{': { m_holder->m_objectChildren->Insert( JSONToken( key, data, JSONType::Object ) ); break; } case '[': { m_holder->m_objectChildren->Insert( JSONToken( key, data, JSONType::Array ) ); break; } case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { m_holder->m_objectChildren->Insert( JSONToken( key, data, JSONType::Integer ) ); break; } case '\"': { m_holder->m_objectChildren->Insert( JSONToken( key, data, JSONType::String ) ); break; } case 't': case 'f': { m_holder->m_objectChildren->Insert( JSONToken( key, data, JSONType::Boolean ) ); break; } case 'n': { m_holder->m_objectChildren->Insert( JSONToken( JSONType::Null ) ); #if SPRAWL_STRICT_JSON if(*(data + 1) != 'u' || *(data + 2) != 'l' || *(data + 3) != 'l') { SPRAWL_THROW_EXCEPTION_OR_ABORT(sprawl::InvalidJsonData()); } #endif data += 4; break; } #if SPRAWL_STRICT_JSON default: { SPRAWL_THROW_EXCEPTION_OR_ABORT(sprawl::InvalidJsonData()); } #endif } SkipWhitespace(data); #if SPRAWL_STRICT_JSON if(*data != ',' && *data != '}') { SPRAWL_THROW_EXCEPTION_OR_ABORT(sprawl::InvalidJsonData()); } #endif if(*data == '}') { ++data; break; } ++data; } } JSONToken::JSONToken(StringData const& myKey, char const*& data, JSONToken::JSONType expectedType) : m_holder(Holder::Create()) , m_key(myKey) { ::new(m_holder) Holder(expectedType); switch(expectedType) { case JSONType::Boolean: ParseBool(data); break; case JSONType::Integer: ParseNumber(data); break; case JSONType::String: ParseString(data); break; case JSONType::Array: ParseArray(data); break; case JSONType::Object: ParseObject(data); break; // "Empty" and "Null" have no content to parse. // "Double" will never actually show up here - it will begin its life as "Integer" and grow into "Double" later! case JSONType::Empty: case JSONType::Double: case JSONType::Null: default: break; } } JSONToken::~JSONToken() { DecRef(); } JSONToken::JSONToken() : m_holder(Holder::Create()) , m_key(nullptr, 0) { ::new(m_holder) Holder(JSONType::Empty); } JSONToken::JSONToken(JSONToken const& other) : m_holder(other.m_holder) , m_key(other.m_key) { IncRef(); } JSONToken::JSONToken(StringData const& myKey, JSONToken const& other) : m_holder(other.m_holder) , m_key(myKey) { IncRef(); } JSONToken JSONToken::ShallowCopy() { JSONToken ret(m_key, m_holder->m_type); Holder* newHolder = ret.m_holder; //We do not want to copy object children directly. They need cleanup work. newHolder->m_data = m_holder->m_data; if(newHolder->m_type == JSONType::Array) { newHolder->m_arrayChildren = m_holder->m_arrayChildren; } if(newHolder->m_type == JSONType::Object) { for(auto kvp = m_holder->m_objectChildren->begin(); kvp; ++kvp) { newHolder->m_objectChildren->Insert( JSONToken(kvp.Key(), kvp.Value()) ); } } return std::move(ret); } JSONToken JSONToken::DeepCopy() { JSONToken ret(m_key, m_holder->m_type); Holder* newHolder = ret.m_holder; //We do not want to copy object children directly. They need cleanup work. newHolder->m_data = m_holder->m_data; if(newHolder->m_type == JSONType::Array) { for(int i = 0; i < m_holder->m_arrayChildren.Size(); ++i) { newHolder->m_arrayChildren.EmplaceBack(std::move(m_holder->m_arrayChildren[i].DeepCopy())); } } if(newHolder->m_type == JSONType::Object) { for(auto kvp = m_holder->m_objectChildren->begin(); kvp; ++kvp) { newHolder->m_objectChildren->Insert( kvp.Value().DeepCopy() ); } } return std::move(ret); } JSONToken& JSONToken::operator=(JSONToken const& other) { DecRef(); m_holder = other.m_holder; IncRef(); return *this; } JSONToken::iterator JSONToken::begin() { if(m_holder->m_type == JSONType::Array) { return iterator(m_holder->m_arrayChildren.begin()); } else if(m_holder->m_type == JSONType::Object) { return iterator(m_holder->m_objectChildren->begin()); } return iterator(nullptr); } JSONToken::iterator JSONToken::end() { if(m_holder->m_type == JSONType::Array) { return iterator(m_holder->m_arrayChildren.end()); } else if(m_holder->m_type == JSONType::Object) { return iterator(m_holder->m_objectChildren->end()); } return iterator(nullptr); } long long JSONToken::ToInt(StringData const& str) { long long result = 0; size_t index = 0; bool negative = false; char const* const data = str.c_str(); size_t const length = str.length(); if( *data == '-' ) { negative = true; ++index; } for( ; index < length; ++index ) { result *= 10; result += ( (int)( data[index] ) - 48 ); } if( negative ) { result *= -1; } return result; } unsigned long long JSONToken::ToUInt(StringData const& str) { unsigned long long result = 0; size_t index = 0; char const* const data = str.c_str(); size_t const length = str.length(); for( ; index < length; ++index ) { result *= 10; result += ( (int)( data[index] ) - 48 ); } return result; } long double JSONToken::ToDouble(StringData const& str) { long double result = 0; size_t index = 0; bool negative = false; double fractionSize = 1.0; bool inFraction = false; char const* const data = str.c_str(); size_t const length = str.length(); bool exp = false; double expVal = 0; bool expNegative = false; if( *data == '-' ) { negative = true; ++index; } for( ; index < length; ++index ) { char c = data[index]; if( c == '.' ) { inFraction = true; continue; } if(c == 'e' || c == 'E') { exp = true; if(index != length - 1) { if(data[index+1] == '-') { ++index; expNegative = true; } else if(data[index+1] == '+') { ++index; } continue; } continue; } if(exp) { expVal *= 10; expVal += ( (int)( data[index] ) - 48 ); } else { result *= 10; result += ( (int)( data[index] ) - 48 ); if( inFraction ) { fractionSize *= 10.0; } } } if( negative ) { result *= -1; } result /= fractionSize; if(exp) { double mult = pow(10.0, expVal); if(expNegative) { result /= mult; } else { result *= mult; } } return result; } bool JSONToken::ToBool(StringData const& str) { char const* const data = str.c_str(); size_t const length = str.length(); if( length == 4 && data[0] == 't' && data[1] == 'r' && data[2] == 'u' && data[3] == 'e' ) { return true; } return false; } sprawl::String JSONToken::EscapeString(StringData const& str) { sprawl::StringBuilder builder; const char* data = str.c_str(); const size_t length = str.length(); for(size_t index = 0; index < length; ++index) { switch(data[index]) { case '\"': builder << "\\\""; break; case '\\': builder << "\\\\"; break; case '\b': builder << "\\b"; break; case '\f': builder << "\\f"; break; case '\n': builder << "\\n"; break; case '\r': builder << "\\r"; break; case '\t': builder << "\\t"; break; default: builder << data[index]; break; } } return builder.Str(); } sprawl::String JSONToken::UnescapeString(StringData const& str) { sprawl::StringBuilder builder; bool inEscape = false; const char* data = str.c_str(); const size_t length = str.length(); for(size_t index = 0; index < length; ++index) { if(inEscape) { switch(data[index]) { case '\"': builder << '\"'; break; case '\\' : builder << '\\'; break; case '/' : builder << '/'; break; case 'b': builder << '\b'; break; case 'f': builder << '\f'; break; case 'n': builder << '\n'; break; case 'r': builder << '\r'; break; case 't': builder << '\t'; break; case 'u': { ++index; char digits[5]; memcpy(digits, &data[index], 5); digits[4] = '\0'; union UnicodeChar { int32_t asInt; char asChar[4]; } ch; ch.asInt= strtol(digits, nullptr, 16); if (ch.asInt < 0x80) { builder << ch.asChar[0]; } else if (ch.asInt < 0x800) { builder << char((ch.asInt>>6) | 0xC0); builder << char((ch.asInt & 0x3F) | 0x80); } else if (ch.asInt < 0x10000) { builder << char((ch.asInt>>12) | 0xE0); builder << char(((ch.asInt>>6) & 0x3F) | 0x80); builder << char((ch.asInt & 0x3F) | 0x80); } else if (ch.asInt < 0x110000) { builder << char((ch.asInt>>18) | 0xF0); builder << char(((ch.asInt>>12) & 0x3F) | 0x80); builder << char(((ch.asInt>>6) & 0x3F) | 0x80); builder << char((ch.asInt & 0x3F) | 0x80); } index += 3; break; } default: builder << '\\' << data[index]; break; } inEscape = false; } else { if(data[index] == '\\') { inEscape = true; } else { builder << data[index]; } } } return builder.Str(); } JSONToken::Holder* JSONToken::Holder::Create() { typedef memory::PoolAllocator<sizeof(JSONToken::Holder)> holderAlloc; return (JSONToken::Holder*)holderAlloc::alloc(); } void JSONToken::Holder::Free(JSONToken::Holder* holder) { typedef memory::PoolAllocator<sizeof(JSONToken::Holder)> holderAlloc; holder->~Holder(); holderAlloc::free(holder); } JSONToken::Holder::Holder(JSONType forType) : m_data(nullptr, 0) , m_type(forType) , m_objectChildren(nullptr) , m_arrayChildren(sprawl::collections::Capacity(0)) , refCount(1) { typedef memory::PoolAllocator<sizeof(JSONToken::TokenMap)> mapAlloc; if(forType == JSONType::Array) { //Give the array a little starting space so we have fewer reallocs of it. m_arrayChildren.Reserve(16); } else if(forType == JSONType::Object) { m_objectChildren = (TokenMap*)mapAlloc::alloc(); ::new(m_objectChildren) TokenMap(64); } } JSONToken::Holder::~Holder() { typedef memory::PoolAllocator<sizeof(JSONToken::TokenMap)> mapAlloc; if(m_objectChildren) { m_objectChildren->~TokenMap(); mapAlloc::free(m_objectChildren); } } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 18645 | brandon_m_bare | Integrated latest version of libsprawl. | ||
#1 | 15089 | brandon_m_bare | First integration of sprawl. | ||
//guest/ShadauxCat/Sprawl/Mainline/serialization/JSONSerializer.cpp | |||||
#4 | 14783 | ShadauxCat |
Style corrections (placement of const) #review-14784 |
||
#3 | 14163 | ShadauxCat |
-Renamed HashMap functions to follow coding style. Only begin, end, find, and variants are left lowercase, in keeping with C++ algorithm and range-based for support. -Fixed some accounting issues with list and forwardlist; size wasn't properly being maintained. -Made a small pedantic change to ThreadManager to ensure that m_numThreadsSynced got reset to 0 before the NotifyAll() to eliminate the miniscule potential for deadlock it would cause if it happened after another thread had already woken up. #review-14164 |
||
#2 | 14066 | ShadauxCat |
-Improved iterating in hashmap - range-based for now gives the ability to access both key and value instead of just value -Slightly improved some of the template aliases -Mega-deprecated VC11 support. Probably doesn't compile anymore. Maintaining it is too much of a headache. #review-14067 |
||
#1 | 11496 | ShadauxCat | Initial checkin: Current states for csbuild and libSprawl |