diff options
author | 2015-07-20 08:11:41 +0200 | |
---|---|---|
committer | 2015-07-20 08:11:41 +0200 | |
commit | 4bcb0c13f50ddb1cd3fd0341b4bb31d9c3c7fc7a (patch) | |
tree | 55eccacfca0e69435d0d4e6615205310ca11f271 /3rdparty/jsoncpp/src/lib_json/json_value.cpp | |
parent | d132946c6f45aa8d271c6180e86f72dd08243048 (diff) | |
parent | 229785f695b26c702c8490792611f59d0366a933 (diff) |
Merge pull request #5 from mamedev/master
Sync to base master
Diffstat (limited to '3rdparty/jsoncpp/src/lib_json/json_value.cpp')
-rw-r--r-- | 3rdparty/jsoncpp/src/lib_json/json_value.cpp | 662 |
1 files changed, 364 insertions, 298 deletions
diff --git a/3rdparty/jsoncpp/src/lib_json/json_value.cpp b/3rdparty/jsoncpp/src/lib_json/json_value.cpp index b73deac1725..cc7d4d3d8ba 100644 --- a/3rdparty/jsoncpp/src/lib_json/json_value.cpp +++ b/3rdparty/jsoncpp/src/lib_json/json_value.cpp @@ -7,9 +7,6 @@ #include <json/assertions.h> #include <json/value.h> #include <json/writer.h> -#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -#include "json_batchallocator.h" -#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #endif // if !defined(JSON_IS_AMALGAMATION) #include <math.h> #include <sstream> @@ -20,6 +17,7 @@ #include <cpptl/conststring.h> #endif #include <cstddef> // size_t +#include <algorithm> // min() #define JSON_ASSERT_UNREACHABLE assert(false) @@ -36,6 +34,7 @@ namespace Json { static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; const unsigned char& kNullRef = kNull[0]; const Value& Value::null = reinterpret_cast<const Value&>(kNullRef); +const Value& Value::nullRef = null; const Int Value::minInt = Int(~(UInt(-1) / 2)); const Int Value::maxInt = Int(UInt(-1) / 2); @@ -53,9 +52,6 @@ const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); const LargestUInt Value::maxLargestUInt = LargestUInt(-1); -/// Unknown size marker -static const unsigned int unknown = (unsigned)-1; - #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) template <typename T, typename U> static inline bool InRange(double d, T min, U max) { @@ -84,25 +80,59 @@ static inline bool InRange(double d, T min, U max) { * @return Pointer on the duplicate instance of string. */ static inline char* duplicateStringValue(const char* value, - unsigned int length = unknown) { - if (length == unknown) - length = (unsigned int)strlen(value); - + size_t length) { // Avoid an integer overflow in the call to malloc below by limiting length // to a sane value. - if (length >= (unsigned)Value::maxInt) + if (length >= (size_t)Value::maxInt) length = Value::maxInt - 1; char* newString = static_cast<char*>(malloc(length + 1)); - JSON_ASSERT_MESSAGE(newString != 0, - "in Json::Value::duplicateStringValue(): " - "Failed to allocate string value buffer"); + if (newString == NULL) { + throwRuntimeError( + "in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } memcpy(newString, value, length); newString[length] = 0; return newString; } -/** Free the string duplicated by duplicateStringValue(). +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue( + const char* value, + unsigned int length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + sizeof(unsigned) + 1U; + char* newString = static_cast<char*>(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError( + "in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast<unsigned*>(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString( + bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) +{ + if (!isPrefixed) { + *length = static_cast<unsigned>(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast<unsigned const*>(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). */ static inline void releaseStringValue(char* value) { free(value); } @@ -116,16 +146,53 @@ static inline void releaseStringValue(char* value) { free(value); } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// #if !defined(JSON_IS_AMALGAMATION) -#ifdef JSON_VALUE_USE_INTERNAL_MAP -#include "json_internalarray.inl" -#include "json_internalmap.inl" -#endif // JSON_VALUE_USE_INTERNAL_MAP #include "json_valueiterator.inl" #endif // if !defined(JSON_IS_AMALGAMATION) namespace Json { +class JSON_API Exception : public std::exception { +public: + Exception(std::string const& msg); + virtual ~Exception() throw(); + virtual char const* what() const throw(); +protected: + std::string const msg_; +}; +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(std::string const& msg); +}; +class JSON_API LogicError : public Exception { +public: + LogicError(std::string const& msg); +}; + +Exception::Exception(std::string const& msg) + : msg_(msg) +{} +Exception::~Exception() throw() +{} +char const* Exception::what() const throw() +{ + return msg_.c_str(); +} +RuntimeError::RuntimeError(std::string const& msg) + : Exception(msg) +{} +LogicError::LogicError(std::string const& msg) + : Exception(msg) +{} +void throwRuntimeError(std::string const& msg) +{ + throw RuntimeError(msg); +} +void throwLogicError(std::string const& msg) +{ + throw LogicError(msg); +} + // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// @@ -141,15 +208,17 @@ Value::CommentInfo::~CommentInfo() { releaseStringValue(comment_); } -void Value::CommentInfo::setComment(const char* text) { - if (comment_) +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { releaseStringValue(comment_); + comment_ = 0; + } JSON_ASSERT(text != 0); JSON_ASSERT_MESSAGE( text[0] == '\0' || text[0] == '/', "in Json::Value::setComment(): Comments must start with /"); // It seems that /**/ style comments are acceptable as well. - comment_ = duplicateStringValue(text); + comment_ = duplicateStringValue(text, len); } // ////////////////////////////////////////////////////////////////// @@ -159,28 +228,34 @@ void Value::CommentInfo::setComment(const char* text) { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -#ifndef JSON_VALUE_USE_INTERNAL_MAP -// Notes: index_ indicates if the string was allocated when +// Notes: policy_ indicates if the string was allocated when // a string is stored. Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {} -Value::CZString::CZString(const char* cstr, DuplicationPolicy allocate) - : cstr_(allocate == duplicate ? duplicateStringValue(cstr) : cstr), - index_(allocate) {} +Value::CZString::CZString(char const* str, unsigned length, DuplicationPolicy allocate) + : cstr_(str) +{ + // allocate != duplicate + storage_.policy_ = allocate; + storage_.length_ = length; +} Value::CZString::CZString(const CZString& other) - : cstr_(other.index_ != noDuplication && other.cstr_ != 0 - ? duplicateStringValue(other.cstr_) - : other.cstr_), - index_(other.cstr_ - ? static_cast<ArrayIndex>(other.index_ == noDuplication + : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_) +{ + storage_.policy_ = (other.cstr_ + ? (other.storage_.policy_ == noDuplication ? noDuplication : duplicate) - : other.index_) {} + : other.storage_.policy_); + storage_.length_ = other.storage_.length_; +} Value::CZString::~CZString() { - if (cstr_ && index_ == duplicate) + if (cstr_ && storage_.policy_ == duplicate) releaseStringValue(const_cast<char*>(cstr_)); } @@ -195,24 +270,35 @@ Value::CZString& Value::CZString::operator=(CZString other) { } bool Value::CZString::operator<(const CZString& other) const { - if (cstr_) - return strcmp(cstr_, other.cstr_) < 0; - return index_ < other.index_; + if (!cstr_) return index_ < other.index_; + //return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); } bool Value::CZString::operator==(const CZString& other) const { - if (cstr_) - return strcmp(cstr_, other.cstr_) == 0; - return index_ == other.index_; + if (!cstr_) return index_ == other.index_; + //return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) return false; + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; } ArrayIndex Value::CZString::index() const { return index_; } -const char* Value::CZString::c_str() const { return cstr_; } - -bool Value::CZString::isStaticString() const { return index_ == noDuplication; } - -#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP +//const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// @@ -241,19 +327,10 @@ Value::Value(ValueType type) { case stringValue: value_.string_ = 0; break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_ = new ObjectValues(); break; -#else - case arrayValue: - value_.array_ = arrayAllocator()->newArray(); - break; - case objectValue: - value_.map_ = mapAllocator()->newMap(); - break; -#endif case booleanValue: value_.bool_ = false; break; @@ -289,19 +366,19 @@ Value::Value(double value) { Value::Value(const char* value) { initBasic(stringValue, true); - value_.string_ = duplicateStringValue(value); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value))); } Value::Value(const char* beginValue, const char* endValue) { initBasic(stringValue, true); value_.string_ = - duplicateStringValue(beginValue, (unsigned int)(endValue - beginValue)); + duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue)); } Value::Value(const std::string& value) { initBasic(stringValue, true); value_.string_ = - duplicateStringValue(value.c_str(), (unsigned int)value.length()); + duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length())); } Value::Value(const StaticString& value) { @@ -312,7 +389,7 @@ Value::Value(const StaticString& value) { #ifdef JSON_USE_CPPTL Value::Value(const CppTL::ConstString& value) { initBasic(stringValue, true); - value_.string_ = duplicateStringValue(value, value.length()); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length())); } #endif @@ -321,14 +398,11 @@ Value::Value(bool value) { value_.bool_ = value; } -Value::Value(const Value& other) +Value::Value(Value const& other) : type_(other.type_), allocated_(false) -#ifdef JSON_VALUE_USE_INTERNAL_MAP , - itemIsUsed_(0) -#endif - , - comments_(0), start_(other.start_), limit_(other.limit_) { + comments_(0), start_(other.start_), limit_(other.limit_) +{ switch (type_) { case nullValue: case intValue: @@ -338,27 +412,22 @@ Value::Value(const Value& other) value_ = other.value_; break; case stringValue: - if (other.value_.string_) { - value_.string_ = duplicateStringValue(other.value_.string_); + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, + &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); allocated_ = true; } else { - value_.string_ = 0; + value_.string_ = other.value_.string_; allocated_ = false; } break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_ = new ObjectValues(*other.value_.map_); break; -#else - case arrayValue: - value_.array_ = arrayAllocator()->newArrayCopy(*other.value_.array_); - break; - case objectValue: - value_.map_ = mapAllocator()->newMapCopy(*other.value_.map_); - break; -#endif default: JSON_ASSERT_UNREACHABLE; } @@ -367,7 +436,8 @@ Value::Value(const Value& other) for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { const CommentInfo& otherComment = other.comments_[comment]; if (otherComment.comment_) - comments_[comment].setComment(otherComment.comment_); + comments_[comment].setComment( + otherComment.comment_, strlen(otherComment.comment_)); } } } @@ -384,19 +454,10 @@ Value::~Value() { if (allocated_) releaseStringValue(value_.string_); break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: delete value_.map_; break; -#else - case arrayValue: - arrayAllocator()->destructArray(value_.array_); - break; - case objectValue: - mapAllocator()->destructMap(value_.map_); - break; -#endif default: JSON_ASSERT_UNREACHABLE; } @@ -410,7 +471,7 @@ Value& Value::operator=(Value other) { return *this; } -void Value::swap(Value& other) { +void Value::swapPayload(Value& other) { ValueType temp = type_; type_ = other.type_; other.type_ = temp; @@ -418,6 +479,11 @@ void Value::swap(Value& other) { int temp2 = allocated_; allocated_ = other.allocated_; other.allocated_ = temp2; +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); std::swap(start_, other.start_); std::swap(limit_, other.limit_); } @@ -448,10 +514,23 @@ bool Value::operator<(const Value& other) const { case booleanValue: return value_.bool_ < other.value_.bool_; case stringValue: - return (value_.string_ == 0 && other.value_.string_) || - (other.value_.string_ && value_.string_ && - strcmp(value_.string_, other.value_.string_) < 0); -#ifndef JSON_VALUE_USE_INTERNAL_MAP + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) return true; + else return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + unsigned min_len = std::min(this_len, other_len); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); + } case arrayValue: case objectValue: { int delta = int(value_.map_->size() - other.value_.map_->size()); @@ -459,12 +538,6 @@ bool Value::operator<(const Value& other) const { return delta < 0; return (*value_.map_) < (*other.value_.map_); } -#else - case arrayValue: - return value_.array_->compare(*(other.value_.array_)) < 0; - case objectValue: - return value_.map_->compare(*(other.value_.map_)) < 0; -#endif default: JSON_ASSERT_UNREACHABLE; } @@ -497,20 +570,24 @@ bool Value::operator==(const Value& other) const { case booleanValue: return value_.bool_ == other.value_.bool_; case stringValue: - return (value_.string_ == other.value_.string_) || - (other.value_.string_ && value_.string_ && - strcmp(value_.string_, other.value_.string_) == 0); -#ifndef JSON_VALUE_USE_INTERNAL_MAP + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + if (this_len != other_len) return false; + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } case arrayValue: case objectValue: return value_.map_->size() == other.value_.map_->size() && (*value_.map_) == (*other.value_.map_); -#else - case arrayValue: - return value_.array_->compare(*(other.value_.array_)) == 0; - case objectValue: - return value_.map_->compare(*(other.value_.map_)) == 0; -#endif default: JSON_ASSERT_UNREACHABLE; } @@ -522,7 +599,20 @@ bool Value::operator!=(const Value& other) const { return !(*this == other); } const char* Value::asCString() const { JSON_ASSERT_MESSAGE(type_ == stringValue, "in Json::Value::asCString(): requires stringValue"); - return value_.string_; + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_str; +} + +bool Value::getString(char const** str, char const** end) const { + if (type_ != stringValue) return false; + if (value_.string_ == 0) return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, str); + *end = *str + length; + return true; } std::string Value::asString() const { @@ -530,7 +620,13 @@ std::string Value::asString() const { case nullValue: return ""; case stringValue: - return value_.string_ ? value_.string_ : ""; + { + if (value_.string_ == 0) return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return std::string(this_str, this_len); + } case booleanValue: return value_.bool_ ? "true" : "false"; case intValue: @@ -546,7 +642,11 @@ std::string Value::asString() const { #ifdef JSON_USE_CPPTL CppTL::ConstString Value::asConstString() const { - return CppTL::ConstString(asString().c_str()); + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, + &len, &str); + return CppTL::ConstString(str, len); } #endif @@ -760,7 +860,6 @@ ArrayIndex Value::size() const { case booleanValue: case stringValue: return 0; -#ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: // size of the array is highest index + 1 if (!value_.map_->empty()) { ObjectValues::const_iterator itLast = value_.map_->end(); @@ -770,12 +869,6 @@ ArrayIndex Value::size() const { return 0; case objectValue: return ArrayIndex(value_.map_->size()); -#else - case arrayValue: - return Int(value_.array_->size()); - case objectValue: - return Int(value_.map_->size()); -#endif } JSON_ASSERT_UNREACHABLE; return 0; // unreachable; @@ -797,19 +890,10 @@ void Value::clear() { start_ = 0; limit_ = 0; switch (type_) { -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_->clear(); - break; -#else case arrayValue: - value_.array_->clear(); - break; case objectValue: value_.map_->clear(); break; -#endif default: break; } @@ -820,7 +904,6 @@ void Value::resize(ArrayIndex newSize) { "in Json::Value::resize(): requires arrayValue"); if (type_ == nullValue) *this = Value(arrayValue); -#ifndef JSON_VALUE_USE_INTERNAL_MAP ArrayIndex oldSize = size(); if (newSize == 0) clear(); @@ -832,9 +915,6 @@ void Value::resize(ArrayIndex newSize) { } assert(size() == newSize); } -#else - value_.array_->resize(newSize); -#endif } Value& Value::operator[](ArrayIndex index) { @@ -843,18 +923,14 @@ Value& Value::operator[](ArrayIndex index) { "in Json::Value::operator[](ArrayIndex): requires arrayValue"); if (type_ == nullValue) *this = Value(arrayValue); -#ifndef JSON_VALUE_USE_INTERNAL_MAP CZString key(index); ObjectValues::iterator it = value_.map_->lower_bound(key); if (it != value_.map_->end() && (*it).first == key) return (*it).second; - ObjectValues::value_type defaultValue(key, null); + ObjectValues::value_type defaultValue(key, nullRef); it = value_.map_->insert(it, defaultValue); return (*it).second; -#else - return value_.array_->resolveReference(index); -#endif } Value& Value::operator[](int index) { @@ -869,17 +945,12 @@ const Value& Value::operator[](ArrayIndex index) const { type_ == nullValue || type_ == arrayValue, "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); if (type_ == nullValue) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP + return nullRef; CZString key(index); ObjectValues::const_iterator it = value_.map_->find(key); if (it == value_.map_->end()) - return null; + return nullRef; return (*it).second; -#else - Value* value = value_.array_->find(index); - return value ? *value : null; -#endif } const Value& Value::operator[](int index) const { @@ -889,149 +960,211 @@ const Value& Value::operator[](int index) const { return (*this)[ArrayIndex(index)]; } -Value& Value::operator[](const char* key) { - return resolveReference(key, false); -} - void Value::initBasic(ValueType type, bool allocated) { type_ = type; allocated_ = allocated; -#ifdef JSON_VALUE_USE_INTERNAL_MAP - itemIsUsed_ = 0; -#endif comments_ = 0; start_ = 0; limit_ = 0; } -Value& Value::resolveReference(const char* key, bool isStatic) { +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, "in Json::Value::resolveReference(): requires objectValue"); if (type_ == nullValue) *this = Value(objectValue); -#ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey( - key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy); + key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE! ObjectValues::iterator it = value_.map_->lower_bound(actualKey); if (it != value_.map_->end() && (*it).first == actualKey) return (*it).second; - ObjectValues::value_type defaultValue(actualKey, null); + ObjectValues::value_type defaultValue(actualKey, nullRef); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* end) +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast<unsigned>(end-key), CZString::duplicateOnCopy); + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullRef); it = value_.map_->insert(it, defaultValue); Value& value = (*it).second; return value; -#else - return value_.map_->resolveReference(key, isStatic); -#endif } Value Value::get(ArrayIndex index, const Value& defaultValue) const { const Value* value = &((*this)[index]); - return value == &null ? defaultValue : *value; + return value == &nullRef ? defaultValue : *value; } bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } -const Value& Value::operator[](const char* key) const { +Value const* Value::find(char const* key, char const* end) const +{ JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == objectValue, - "in Json::Value::operator[](char const*)const: requires objectValue"); - if (type_ == nullValue) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey(key, CZString::noDuplication); + "in Json::Value::find(key, end, found): requires objectValue or nullValue"); + if (type_ == nullValue) return NULL; + CZString actualKey(key, static_cast<unsigned>(end-key), CZString::noDuplication); ObjectValues::const_iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return null; - return (*it).second; -#else - const Value* value = value_.map_->find(key); - return value ? *value : null; -#endif + if (it == value_.map_->end()) return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const +{ + Value const* found = find(key, key + strlen(key)); + if (!found) return nullRef; + return *found; +} +Value const& Value::operator[](std::string const& key) const +{ + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) return nullRef; + return *found; } -Value& Value::operator[](const std::string& key) { - return (*this)[key.c_str()]; +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); } -const Value& Value::operator[](const std::string& key) const { - return (*this)[key.c_str()]; +Value& Value::operator[](const std::string& key) { + return resolveReference(key.data(), key.data() + key.length()); } Value& Value::operator[](const StaticString& key) { - return resolveReference(key, true); + return resolveReference(key.c_str()); } #ifdef JSON_USE_CPPTL Value& Value::operator[](const CppTL::ConstString& key) { - return (*this)[key.c_str()]; + return resolveReference(key.c_str(), key.end_c_str()); } - -const Value& Value::operator[](const CppTL::ConstString& key) const { - return (*this)[key.c_str()]; +Value const& Value::operator[](CppTL::ConstString const& key) const +{ + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) return nullRef; + return *found; } #endif Value& Value::append(const Value& value) { return (*this)[size()] = value; } -Value Value::get(const char* key, const Value& defaultValue) const { - const Value* value = &((*this)[key]); - return value == &null ? defaultValue : *value; +Value Value::get(char const* key, char const* end, Value const& defaultValue) const +{ + Value const* found = find(key, end); + return !found ? defaultValue : *found; } - -Value Value::get(const std::string& key, const Value& defaultValue) const { - return get(key.c_str(), defaultValue); +Value Value::get(char const* key, Value const& defaultValue) const +{ + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(std::string const& key, Value const& defaultValue) const +{ + return get(key.data(), key.data() + key.length(), defaultValue); } -Value Value::removeMember(const char* key) { - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, - "in Json::Value::removeMember(): requires objectValue"); - if (type_ == nullValue) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey(key, CZString::noDuplication); + +bool Value::removeMember(const char* key, const char* end, Value* removed) +{ + if (type_ != objectValue) { + return false; + } + CZString actualKey(key, static_cast<unsigned>(end-key), CZString::noDuplication); ObjectValues::iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) - return null; - Value old(it->second); + return false; + *removed = it->second; value_.map_->erase(it); - return old; -#else - Value* value = value_.map_->find(key); - if (value) { - Value old(*value); - value_.map_.remove(key); - return old; - } else { - return null; - } -#endif + return true; +} +bool Value::removeMember(const char* key, Value* removed) +{ + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(std::string const& key, Value* removed) +{ + return removeMember(key.data(), key.data() + key.length(), removed); } +Value Value::removeMember(const char* key) +{ + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return nullRef; -Value Value::removeMember(const std::string& key) { + Value removed; // null + removeMember(key, key + strlen(key), &removed); + return removed; // still null if removeMember() did nothing +} +Value Value::removeMember(const std::string& key) +{ return removeMember(key.c_str()); } +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + CZString key(i); + (*value_.map_)[key] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + #ifdef JSON_USE_CPPTL Value Value::get(const CppTL::ConstString& key, const Value& defaultValue) const { - return get(key.c_str(), defaultValue); + return get(key.c_str(), key.end_c_str(), defaultValue); } #endif -bool Value::isMember(const char* key) const { - const Value* value = &((*this)[key]); - return value != &null; +bool Value::isMember(char const* key, char const* end) const +{ + Value const* value = find(key, end); + return NULL != value; } - -bool Value::isMember(const std::string& key) const { - return isMember(key.c_str()); +bool Value::isMember(char const* key) const +{ + return isMember(key, key + strlen(key)); +} +bool Value::isMember(std::string const& key) const +{ + return isMember(key.data(), key.data() + key.length()); } #ifdef JSON_USE_CPPTL bool Value::isMember(const CppTL::ConstString& key) const { - return isMember(key.c_str()); + return isMember(key.c_str(), key.end_c_str()); } #endif @@ -1043,19 +1176,12 @@ Value::Members Value::getMemberNames() const { return Value::Members(); Members members; members.reserve(value_.map_->size()); -#ifndef JSON_VALUE_USE_INTERNAL_MAP ObjectValues::const_iterator it = value_.map_->begin(); ObjectValues::const_iterator itEnd = value_.map_->end(); - for (; it != itEnd; ++it) - members.push_back(std::string((*it).first.c_str())); -#else - ValueInternalMap::IteratorState it; - ValueInternalMap::IteratorState itEnd; - value_.map_->makeBeginIterator(it); - value_.map_->makeEndIterator(itEnd); - for (; !ValueInternalMap::equals(it, itEnd); ValueInternalMap::increment(it)) - members.push_back(std::string(ValueInternalMap::key(it))); -#endif + for (; it != itEnd; ++it) { + members.push_back(std::string((*it).first.data(), + (*it).first.length())); + } return members; } // @@ -1181,14 +1307,22 @@ bool Value::isArray() const { return type_ == arrayValue; } bool Value::isObject() const { return type_ == objectValue; } -void Value::setComment(const char* comment, CommentPlacement placement) { +void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { if (!comments_) comments_ = new CommentInfo[numberOfCommentPlacement]; - comments_[placement].setComment(comment); + if ((len > 0) && (comment[len-1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); } void Value::setComment(const std::string& comment, CommentPlacement placement) { - setComment(comment.c_str(), placement); + setComment(comment.c_str(), comment.length(), placement); } bool Value::hasComment(CommentPlacement placement) const { @@ -1216,28 +1350,11 @@ std::string Value::toStyledString() const { Value::const_iterator Value::begin() const { switch (type_) { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if (value_.array_) { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator(it); - return const_iterator(it); - } - break; - case objectValue: - if (value_.map_) { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator(it); - return const_iterator(it); - } - break; -#else case arrayValue: case objectValue: if (value_.map_) return const_iterator(value_.map_->begin()); break; -#endif default: break; } @@ -1246,28 +1363,11 @@ Value::const_iterator Value::begin() const { Value::const_iterator Value::end() const { switch (type_) { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if (value_.array_) { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator(it); - return const_iterator(it); - } - break; - case objectValue: - if (value_.map_) { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator(it); - return const_iterator(it); - } - break; -#else case arrayValue: case objectValue: if (value_.map_) return const_iterator(value_.map_->end()); break; -#endif default: break; } @@ -1276,28 +1376,11 @@ Value::const_iterator Value::end() const { Value::iterator Value::begin() { switch (type_) { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if (value_.array_) { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator(it); - return iterator(it); - } - break; - case objectValue: - if (value_.map_) { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator(it); - return iterator(it); - } - break; -#else case arrayValue: case objectValue: if (value_.map_) return iterator(value_.map_->begin()); break; -#endif default: break; } @@ -1306,28 +1389,11 @@ Value::iterator Value::begin() { Value::iterator Value::end() { switch (type_) { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if (value_.array_) { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator(it); - return iterator(it); - } - break; - case objectValue: - if (value_.map_) { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator(it); - return iterator(it); - } - break; -#else case arrayValue: case objectValue: if (value_.map_) return iterator(value_.map_->end()); break; -#endif default: break; } @@ -1428,7 +1494,7 @@ const Value& Path::resolve(const Value& root) const { // Error: unable to resolve path (object value expected at position...) } node = &((*node)[arg.key_]); - if (node == &Value::null) { + if (node == &Value::nullRef) { // Error: unable to resolve path (object has no member named '' at // position...) } @@ -1449,7 +1515,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const { if (!node->isObject()) return defaultValue; node = &((*node)[arg.key_]); - if (node == &Value::null) + if (node == &Value::nullRef) return defaultValue; } } |