mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2024-12-27 11:21:02 +08:00
Merge pull request #185 from open-source-parsers/drop-internal-map
`JSON_VALUE_USE_INTERNAL_MAP` and `JSON_USE_SIMPLE_INTERNAL_ALLOCATOR` did not actually compile with current compilers. In fact, as far as I can tell, they haven't worked since just after the 0.6.0-rc2 release. And according to blep, there are bugs, e.g. [this one](https://sourceforge.net/p/jsoncpp/bugs/27). It's probably better to hide the implementation of Value (maybe in the next major release) and to put experiments like this into completely separate classes.
This commit is contained in:
commit
4ac4cac2be
@ -118,7 +118,6 @@ def amalgamate_source(source_top_dir=None,
|
|||||||
lib_json = "src/lib_json"
|
lib_json = "src/lib_json"
|
||||||
source.add_file(os.path.join(lib_json, "json_tool.h"))
|
source.add_file(os.path.join(lib_json, "json_tool.h"))
|
||||||
source.add_file(os.path.join(lib_json, "json_reader.cpp"))
|
source.add_file(os.path.join(lib_json, "json_reader.cpp"))
|
||||||
source.add_file(os.path.join(lib_json, "json_batchallocator.h"))
|
|
||||||
source.add_file(os.path.join(lib_json, "json_valueiterator.inl"))
|
source.add_file(os.path.join(lib_json, "json_valueiterator.inl"))
|
||||||
source.add_file(os.path.join(lib_json, "json_value.cpp"))
|
source.add_file(os.path.join(lib_json, "json_value.cpp"))
|
||||||
source.add_file(os.path.join(lib_json, "json_writer.cpp"))
|
source.add_file(os.path.join(lib_json, "json_writer.cpp"))
|
||||||
|
@ -1946,8 +1946,7 @@ INCLUDE_FILE_PATTERNS = *.h
|
|||||||
PREDEFINED = "_MSC_VER=1400" \
|
PREDEFINED = "_MSC_VER=1400" \
|
||||||
_CPPRTTI \
|
_CPPRTTI \
|
||||||
_WIN32 \
|
_WIN32 \
|
||||||
JSONCPP_DOC_EXCLUDE_IMPLEMENTATION \
|
JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
# tag can be used to specify a list of macro names that should be expanded. The
|
# tag can be used to specify a list of macro names that should be expanded. The
|
||||||
|
@ -1946,8 +1946,7 @@ INCLUDE_FILE_PATTERNS = *.h
|
|||||||
PREDEFINED = "_MSC_VER=1400" \
|
PREDEFINED = "_MSC_VER=1400" \
|
||||||
_CPPRTTI \
|
_CPPRTTI \
|
||||||
_WIN32 \
|
_WIN32 \
|
||||||
JSONCPP_DOC_EXCLUDE_IMPLEMENTATION \
|
JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
# tag can be used to specify a list of macro names that should be expanded. The
|
# tag can be used to specify a list of macro names that should be expanded. The
|
||||||
|
@ -15,17 +15,6 @@
|
|||||||
/// std::map
|
/// std::map
|
||||||
/// as Value container.
|
/// as Value container.
|
||||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||||
/// If defined, indicates that Json specific container should be used
|
|
||||||
/// (hash table & simple deque container with customizable allocator).
|
|
||||||
/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
|
|
||||||
//# define JSON_VALUE_USE_INTERNAL_MAP 1
|
|
||||||
/// Force usage of standard new/malloc based allocator instead of memory pool
|
|
||||||
/// based allocator.
|
|
||||||
/// The memory pools allocator used optimization (initializing Value and
|
|
||||||
/// ValueInternalLink
|
|
||||||
/// as if it was a POD) that may cause some validation tool to report errors.
|
|
||||||
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
|
|
||||||
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
|
|
||||||
|
|
||||||
// If non-zero, the library uses exceptions to report bad input instead of C
|
// If non-zero, the library uses exceptions to report bad input instead of C
|
||||||
// assertion macros. The default is to use exceptions.
|
// assertion macros. The default is to use exceptions.
|
||||||
|
@ -31,12 +31,6 @@ class Value;
|
|||||||
class ValueIteratorBase;
|
class ValueIteratorBase;
|
||||||
class ValueIterator;
|
class ValueIterator;
|
||||||
class ValueConstIterator;
|
class ValueConstIterator;
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
class ValueMapAllocator;
|
|
||||||
class ValueInternalLink;
|
|
||||||
class ValueInternalArray;
|
|
||||||
class ValueInternalMap;
|
|
||||||
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
} // namespace Json
|
} // namespace Json
|
||||||
|
|
||||||
|
@ -115,10 +115,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
class JSON_API Value {
|
class JSON_API Value {
|
||||||
friend class ValueIteratorBase;
|
friend class ValueIteratorBase;
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
friend class ValueInternalLink;
|
|
||||||
friend class ValueInternalMap;
|
|
||||||
#endif
|
|
||||||
public:
|
public:
|
||||||
typedef std::vector<std::string> Members;
|
typedef std::vector<std::string> Members;
|
||||||
typedef ValueIterator iterator;
|
typedef ValueIterator iterator;
|
||||||
@ -160,7 +156,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
class CZString {
|
class CZString {
|
||||||
public:
|
public:
|
||||||
enum DuplicationPolicy {
|
enum DuplicationPolicy {
|
||||||
@ -191,7 +186,6 @@ public:
|
|||||||
#else
|
#else
|
||||||
typedef CppTL::SmallMap<CZString, Value> ObjectValues;
|
typedef CppTL::SmallMap<CZString, Value> ObjectValues;
|
||||||
#endif // ifndef JSON_USE_CPPTL_SMALLMAP
|
#endif // ifndef JSON_USE_CPPTL_SMALLMAP
|
||||||
#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -463,19 +457,6 @@ private:
|
|||||||
|
|
||||||
Value& resolveReference(const char* key, bool isStatic);
|
Value& resolveReference(const char* key, bool isStatic);
|
||||||
|
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
inline bool isItemAvailable() const { return itemIsUsed_ == 0; }
|
|
||||||
|
|
||||||
inline void setItemUsed(bool isUsed = true) { itemIsUsed_ = isUsed ? 1 : 0; }
|
|
||||||
|
|
||||||
inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; }
|
|
||||||
|
|
||||||
inline void setMemberNameIsStatic(bool isStatic) {
|
|
||||||
memberNameIsStatic_ = isStatic ? 1 : 0;
|
|
||||||
}
|
|
||||||
#endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct CommentInfo {
|
struct CommentInfo {
|
||||||
CommentInfo();
|
CommentInfo();
|
||||||
~CommentInfo();
|
~CommentInfo();
|
||||||
@ -500,19 +481,10 @@ private:
|
|||||||
double real_;
|
double real_;
|
||||||
bool bool_;
|
bool bool_;
|
||||||
char* string_;
|
char* string_;
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ValueInternalArray* array_;
|
|
||||||
ValueInternalMap* map_;
|
|
||||||
#else
|
|
||||||
ObjectValues* map_;
|
ObjectValues* map_;
|
||||||
#endif
|
|
||||||
} value_;
|
} value_;
|
||||||
ValueType type_ : 8;
|
ValueType type_ : 8;
|
||||||
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
|
|
||||||
unsigned int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
|
|
||||||
#endif
|
|
||||||
CommentInfo* comments_;
|
CommentInfo* comments_;
|
||||||
|
|
||||||
// [start, limit) byte offsets in the source JSON text from which this Value
|
// [start, limit) byte offsets in the source JSON text from which this Value
|
||||||
@ -584,345 +556,6 @@ private:
|
|||||||
Args args_;
|
Args args_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
/** \brief Allocator to customize Value internal map.
|
|
||||||
* Below is an example of a simple implementation (default implementation
|
|
||||||
actually
|
|
||||||
* use memory pool for speed).
|
|
||||||
* \code
|
|
||||||
class DefaultValueMapAllocator : public ValueMapAllocator
|
|
||||||
{
|
|
||||||
public: // overridden from ValueMapAllocator
|
|
||||||
virtual ValueInternalMap *newMap()
|
|
||||||
{
|
|
||||||
return new ValueInternalMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
|
||||||
{
|
|
||||||
return new ValueInternalMap( other );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void destructMap( ValueInternalMap *map )
|
|
||||||
{
|
|
||||||
delete map;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
|
||||||
{
|
|
||||||
return new ValueInternalLink[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void releaseMapBuckets( ValueInternalLink *links )
|
|
||||||
{
|
|
||||||
delete [] links;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ValueInternalLink *allocateMapLink()
|
|
||||||
{
|
|
||||||
return new ValueInternalLink();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void releaseMapLink( ValueInternalLink *link )
|
|
||||||
{
|
|
||||||
delete link;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
* \endcode
|
|
||||||
*/
|
|
||||||
class JSON_API ValueMapAllocator {
|
|
||||||
public:
|
|
||||||
virtual ~ValueMapAllocator();
|
|
||||||
virtual ValueInternalMap* newMap() = 0;
|
|
||||||
virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) = 0;
|
|
||||||
virtual void destructMap(ValueInternalMap* map) = 0;
|
|
||||||
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) = 0;
|
|
||||||
virtual void releaseMapBuckets(ValueInternalLink* links) = 0;
|
|
||||||
virtual ValueInternalLink* allocateMapLink() = 0;
|
|
||||||
virtual void releaseMapLink(ValueInternalLink* link) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
|
|
||||||
* \internal previous_ & next_ allows for bidirectional traversal.
|
|
||||||
*/
|
|
||||||
class JSON_API ValueInternalLink {
|
|
||||||
public:
|
|
||||||
enum {
|
|
||||||
itemPerLink = 6
|
|
||||||
}; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
|
|
||||||
enum InternalFlags {
|
|
||||||
flagAvailable = 0,
|
|
||||||
flagUsed = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
ValueInternalLink();
|
|
||||||
|
|
||||||
~ValueInternalLink();
|
|
||||||
|
|
||||||
Value items_[itemPerLink];
|
|
||||||
char* keys_[itemPerLink];
|
|
||||||
ValueInternalLink* previous_;
|
|
||||||
ValueInternalLink* next_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief A linked page based hash-table implementation used internally by
|
|
||||||
*Value.
|
|
||||||
* \internal ValueInternalMap is a tradional bucket based hash-table, with a
|
|
||||||
*linked
|
|
||||||
* list in each bucket to handle collision. There is an addional twist in that
|
|
||||||
* each node of the collision linked list is a page containing a fixed amount of
|
|
||||||
* value. This provides a better compromise between memory usage and speed.
|
|
||||||
*
|
|
||||||
* Each bucket is made up of a chained list of ValueInternalLink. The last
|
|
||||||
* link of a given bucket can be found in the 'previous_' field of the following
|
|
||||||
*bucket.
|
|
||||||
* The last link of the last bucket is stored in tailLink_ as it has no
|
|
||||||
*following bucket.
|
|
||||||
* Only the last link of a bucket may contains 'available' item. The last link
|
|
||||||
*always
|
|
||||||
* contains at least one element unless is it the bucket one very first link.
|
|
||||||
*/
|
|
||||||
class JSON_API ValueInternalMap {
|
|
||||||
friend class ValueIteratorBase;
|
|
||||||
friend class Value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef unsigned int HashKey;
|
|
||||||
typedef unsigned int BucketIndex;
|
|
||||||
|
|
||||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
struct IteratorState {
|
|
||||||
IteratorState() : map_(0), link_(0), itemIndex_(0), bucketIndex_(0) {}
|
|
||||||
ValueInternalMap* map_;
|
|
||||||
ValueInternalLink* link_;
|
|
||||||
BucketIndex itemIndex_;
|
|
||||||
BucketIndex bucketIndex_;
|
|
||||||
};
|
|
||||||
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
|
|
||||||
ValueInternalMap();
|
|
||||||
ValueInternalMap(const ValueInternalMap& other);
|
|
||||||
ValueInternalMap& operator=(ValueInternalMap other);
|
|
||||||
~ValueInternalMap();
|
|
||||||
|
|
||||||
void swap(ValueInternalMap& other);
|
|
||||||
|
|
||||||
BucketIndex size() const;
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
bool reserveDelta(BucketIndex growth);
|
|
||||||
|
|
||||||
bool reserve(BucketIndex newItemCount);
|
|
||||||
|
|
||||||
const Value* find(const char* key) const;
|
|
||||||
|
|
||||||
Value* find(const char* key);
|
|
||||||
|
|
||||||
Value& resolveReference(const char* key, bool isStatic);
|
|
||||||
|
|
||||||
void remove(const char* key);
|
|
||||||
|
|
||||||
void doActualRemove(ValueInternalLink* link,
|
|
||||||
BucketIndex index,
|
|
||||||
BucketIndex bucketIndex);
|
|
||||||
|
|
||||||
ValueInternalLink*& getLastLinkInBucket(BucketIndex bucketIndex);
|
|
||||||
|
|
||||||
Value& setNewItem(const char* key,
|
|
||||||
bool isStatic,
|
|
||||||
ValueInternalLink* link,
|
|
||||||
BucketIndex index);
|
|
||||||
|
|
||||||
Value& unsafeAdd(const char* key, bool isStatic, HashKey hashedKey);
|
|
||||||
|
|
||||||
HashKey hash(const char* key) const;
|
|
||||||
|
|
||||||
int compare(const ValueInternalMap& other) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void makeBeginIterator(IteratorState& it) const;
|
|
||||||
void makeEndIterator(IteratorState& it) const;
|
|
||||||
static bool equals(const IteratorState& x, const IteratorState& other);
|
|
||||||
static void increment(IteratorState& iterator);
|
|
||||||
static void incrementBucket(IteratorState& iterator);
|
|
||||||
static void decrement(IteratorState& iterator);
|
|
||||||
static const char* key(const IteratorState& iterator);
|
|
||||||
static const char* key(const IteratorState& iterator, bool& isStatic);
|
|
||||||
static Value& value(const IteratorState& iterator);
|
|
||||||
static int distance(const IteratorState& x, const IteratorState& y);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ValueInternalLink* buckets_;
|
|
||||||
ValueInternalLink* tailLink_;
|
|
||||||
BucketIndex bucketsSize_;
|
|
||||||
BucketIndex itemCount_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief A simplified deque implementation used internally by Value.
|
|
||||||
* \internal
|
|
||||||
* It is based on a list of fixed "page", each page contains a fixed number of
|
|
||||||
*items.
|
|
||||||
* Instead of using a linked-list, a array of pointer is used for fast item
|
|
||||||
*look-up.
|
|
||||||
* Look-up for an element is as follow:
|
|
||||||
* - compute page index: pageIndex = itemIndex / itemsPerPage
|
|
||||||
* - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
|
|
||||||
*
|
|
||||||
* Insertion is amortized constant time (only the array containing the index of
|
|
||||||
*pointers
|
|
||||||
* need to be reallocated when items are appended).
|
|
||||||
*/
|
|
||||||
class JSON_API ValueInternalArray {
|
|
||||||
friend class Value;
|
|
||||||
friend class ValueIteratorBase;
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum {
|
|
||||||
itemsPerPage = 8
|
|
||||||
}; // should be a power of 2 for fast divide and modulo.
|
|
||||||
typedef Value::ArrayIndex ArrayIndex;
|
|
||||||
typedef unsigned int PageIndex;
|
|
||||||
|
|
||||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
struct IteratorState // Must be a POD
|
|
||||||
{
|
|
||||||
IteratorState() : array_(0), currentPageIndex_(0), currentItemIndex_(0) {}
|
|
||||||
ValueInternalArray* array_;
|
|
||||||
Value** currentPageIndex_;
|
|
||||||
unsigned int currentItemIndex_;
|
|
||||||
};
|
|
||||||
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
|
|
||||||
ValueInternalArray();
|
|
||||||
ValueInternalArray(const ValueInternalArray& other);
|
|
||||||
ValueInternalArray& operator=(ValueInternalArray other);
|
|
||||||
~ValueInternalArray();
|
|
||||||
void swap(ValueInternalArray& other);
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
void resize(ArrayIndex newSize);
|
|
||||||
|
|
||||||
Value& resolveReference(ArrayIndex index);
|
|
||||||
|
|
||||||
Value* find(ArrayIndex index) const;
|
|
||||||
|
|
||||||
ArrayIndex size() const;
|
|
||||||
|
|
||||||
int compare(const ValueInternalArray& other) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool equals(const IteratorState& x, const IteratorState& other);
|
|
||||||
static void increment(IteratorState& iterator);
|
|
||||||
static void decrement(IteratorState& iterator);
|
|
||||||
static Value& dereference(const IteratorState& iterator);
|
|
||||||
static Value& unsafeDereference(const IteratorState& iterator);
|
|
||||||
static int distance(const IteratorState& x, const IteratorState& y);
|
|
||||||
static ArrayIndex indexOf(const IteratorState& iterator);
|
|
||||||
void makeBeginIterator(IteratorState& it) const;
|
|
||||||
void makeEndIterator(IteratorState& it) const;
|
|
||||||
void makeIterator(IteratorState& it, ArrayIndex index) const;
|
|
||||||
|
|
||||||
void makeIndexValid(ArrayIndex index);
|
|
||||||
|
|
||||||
Value** pages_;
|
|
||||||
ArrayIndex size_;
|
|
||||||
PageIndex pageCount_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \brief Experimental: do not use. Allocator to customize Value internal
|
|
||||||
array.
|
|
||||||
* Below is an example of a simple implementation (actual implementation use
|
|
||||||
* memory pool).
|
|
||||||
\code
|
|
||||||
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
|
||||||
{
|
|
||||||
public: // overridden from ValueArrayAllocator
|
|
||||||
virtual ~DefaultValueArrayAllocator()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ValueInternalArray *newArray()
|
|
||||||
{
|
|
||||||
return new ValueInternalArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
|
||||||
{
|
|
||||||
return new ValueInternalArray( other );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void destruct( ValueInternalArray *array )
|
|
||||||
{
|
|
||||||
delete array;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void reallocateArrayPageIndex( Value **&indexes,
|
|
||||||
ValueInternalArray::PageIndex
|
|
||||||
&indexCount,
|
|
||||||
ValueInternalArray::PageIndex
|
|
||||||
minNewIndexCount )
|
|
||||||
{
|
|
||||||
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
|
||||||
if ( minNewIndexCount > newIndexCount )
|
|
||||||
newIndexCount = minNewIndexCount;
|
|
||||||
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
|
||||||
if ( !newIndexes )
|
|
||||||
throw std::bad_alloc();
|
|
||||||
indexCount = newIndexCount;
|
|
||||||
indexes = static_cast<Value **>( newIndexes );
|
|
||||||
}
|
|
||||||
virtual void releaseArrayPageIndex( Value **indexes,
|
|
||||||
ValueInternalArray::PageIndex indexCount )
|
|
||||||
{
|
|
||||||
if ( indexes )
|
|
||||||
free( indexes );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Value *allocateArrayPage()
|
|
||||||
{
|
|
||||||
return static_cast<Value *>( malloc( sizeof(Value) *
|
|
||||||
ValueInternalArray::itemsPerPage ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void releaseArrayPage( Value *value )
|
|
||||||
{
|
|
||||||
if ( value )
|
|
||||||
free( value );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
\endcode
|
|
||||||
*/
|
|
||||||
class JSON_API ValueArrayAllocator {
|
|
||||||
public:
|
|
||||||
virtual ~ValueArrayAllocator();
|
|
||||||
virtual ValueInternalArray* newArray() = 0;
|
|
||||||
virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) = 0;
|
|
||||||
virtual void destructArray(ValueInternalArray* array) = 0;
|
|
||||||
/** \brief Reallocate array page index.
|
|
||||||
* Reallocates an array of pointer on each page.
|
|
||||||
* \param indexes [input] pointer on the current index. May be \c NULL.
|
|
||||||
* [output] pointer on the new index of at least
|
|
||||||
* \a minNewIndexCount pages.
|
|
||||||
* \param indexCount [input] current number of pages in the index.
|
|
||||||
* [output] number of page the reallocated index can handle.
|
|
||||||
* \b MUST be >= \a minNewIndexCount.
|
|
||||||
* \param minNewIndexCount Minimum number of page the new index must be able
|
|
||||||
* to
|
|
||||||
* handle.
|
|
||||||
*/
|
|
||||||
virtual void
|
|
||||||
reallocateArrayPageIndex(Value**& indexes,
|
|
||||||
ValueInternalArray::PageIndex& indexCount,
|
|
||||||
ValueInternalArray::PageIndex minNewIndexCount) = 0;
|
|
||||||
virtual void
|
|
||||||
releaseArrayPageIndex(Value** indexes,
|
|
||||||
ValueInternalArray::PageIndex indexCount) = 0;
|
|
||||||
virtual Value* allocateArrayPage() = 0;
|
|
||||||
virtual void releaseArrayPage(Value* value) = 0;
|
|
||||||
};
|
|
||||||
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
/** \brief base class for Value iterators.
|
/** \brief base class for Value iterators.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -934,12 +567,7 @@ public:
|
|||||||
typedef ValueIteratorBase SelfType;
|
typedef ValueIteratorBase SelfType;
|
||||||
|
|
||||||
ValueIteratorBase();
|
ValueIteratorBase();
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
|
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
|
||||||
#else
|
|
||||||
ValueIteratorBase(const ValueInternalArray::IteratorState& state);
|
|
||||||
ValueIteratorBase(const ValueInternalMap::IteratorState& state);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool operator==(const SelfType& other) const { return isEqual(other); }
|
bool operator==(const SelfType& other) const { return isEqual(other); }
|
||||||
|
|
||||||
@ -974,17 +602,9 @@ protected:
|
|||||||
void copy(const SelfType& other);
|
void copy(const SelfType& other);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
Value::ObjectValues::iterator current_;
|
Value::ObjectValues::iterator current_;
|
||||||
// Indicates that iterator is for a null value.
|
// Indicates that iterator is for a null value.
|
||||||
bool isNull_;
|
bool isNull_;
|
||||||
#else
|
|
||||||
union {
|
|
||||||
ValueInternalArray::IteratorState array_;
|
|
||||||
ValueInternalMap::IteratorState map_;
|
|
||||||
} iterator_;
|
|
||||||
bool isArray_;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief const iterator for object and array value.
|
/** \brief const iterator for object and array value.
|
||||||
@ -1006,12 +626,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
/*! \internal Use by Value to create an iterator.
|
/*! \internal Use by Value to create an iterator.
|
||||||
*/
|
*/
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
|
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
|
||||||
#else
|
|
||||||
ValueConstIterator(const ValueInternalArray::IteratorState& state);
|
|
||||||
ValueConstIterator(const ValueInternalMap::IteratorState& state);
|
|
||||||
#endif
|
|
||||||
public:
|
public:
|
||||||
SelfType& operator=(const ValueIteratorBase& other);
|
SelfType& operator=(const ValueIteratorBase& other);
|
||||||
|
|
||||||
@ -1062,12 +677,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
/*! \internal Use by Value to create an iterator.
|
/*! \internal Use by Value to create an iterator.
|
||||||
*/
|
*/
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
explicit ValueIterator(const Value::ObjectValues::iterator& current);
|
explicit ValueIterator(const Value::ObjectValues::iterator& current);
|
||||||
#else
|
|
||||||
ValueIterator(const ValueInternalArray::IteratorState& state);
|
|
||||||
ValueIterator(const ValueInternalMap::IteratorState& state);
|
|
||||||
#endif
|
|
||||||
public:
|
public:
|
||||||
SelfType& operator=(const SelfType& other);
|
SelfType& operator=(const SelfType& other);
|
||||||
|
|
||||||
|
@ -178,15 +178,6 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\json\json.h">
|
RelativePath="..\..\include\json\json.h">
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\lib_json\json_batchallocator.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\lib_json\json_internalarray.inl">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\src\lib_json\json_internalmap.inl">
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\lib_json\json_reader.cpp">
|
RelativePath="..\..\src\lib_json\json_reader.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
@ -34,7 +34,6 @@ SOURCE_GROUP( "Public API" FILES ${PUBLIC_HEADERS} )
|
|||||||
SET(jsoncpp_sources
|
SET(jsoncpp_sources
|
||||||
json_tool.h
|
json_tool.h
|
||||||
json_reader.cpp
|
json_reader.cpp
|
||||||
json_batchallocator.h
|
|
||||||
json_valueiterator.inl
|
json_valueiterator.inl
|
||||||
json_value.cpp
|
json_value.cpp
|
||||||
json_writer.cpp
|
json_writer.cpp
|
||||||
|
@ -1,121 +0,0 @@
|
|||||||
// Copyright 2007-2010 Baptiste Lepilleur
|
|
||||||
// Distributed under MIT license, or public domain if desired and
|
|
||||||
// recognized in your jurisdiction.
|
|
||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
|
||||||
|
|
||||||
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
|
||||||
#define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
|
||||||
|
|
||||||
namespace Json {
|
|
||||||
|
|
||||||
/* Fast memory allocator.
|
|
||||||
*
|
|
||||||
* This memory allocator allocates memory for a batch of object (specified by
|
|
||||||
* the page size, the number of object in each page).
|
|
||||||
*
|
|
||||||
* It does not allow the destruction of a single object. All the allocated
|
|
||||||
* objects can be destroyed at once. The memory can be either released or reused
|
|
||||||
* for future allocation.
|
|
||||||
*
|
|
||||||
* The in-place new operator must be used to construct the object using the
|
|
||||||
* pointer returned by allocate.
|
|
||||||
*/
|
|
||||||
template <typename AllocatedType, const unsigned int objectPerAllocation>
|
|
||||||
class BatchAllocator {
|
|
||||||
public:
|
|
||||||
BatchAllocator(unsigned int objectsPerPage = 255)
|
|
||||||
: freeHead_(0), objectsPerPage_(objectsPerPage) {
|
|
||||||
// printf( "Size: %d => %s\n", sizeof(AllocatedType),
|
|
||||||
// typeid(AllocatedType).name() );
|
|
||||||
assert(sizeof(AllocatedType) * objectPerAllocation >=
|
|
||||||
sizeof(AllocatedType*)); // We must be able to store a slist in the
|
|
||||||
// object free space.
|
|
||||||
assert(objectsPerPage >= 16);
|
|
||||||
batches_ = allocateBatch(0); // allocated a dummy page
|
|
||||||
currentBatch_ = batches_;
|
|
||||||
}
|
|
||||||
|
|
||||||
~BatchAllocator() {
|
|
||||||
for (BatchInfo* batch = batches_; batch;) {
|
|
||||||
BatchInfo* nextBatch = batch->next_;
|
|
||||||
free(batch);
|
|
||||||
batch = nextBatch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// allocate space for an array of objectPerAllocation object.
|
|
||||||
/// @warning it is the responsability of the caller to call objects
|
|
||||||
/// constructors.
|
|
||||||
AllocatedType* allocate() {
|
|
||||||
if (freeHead_) // returns node from free list.
|
|
||||||
{
|
|
||||||
AllocatedType* object = freeHead_;
|
|
||||||
freeHead_ = *(AllocatedType**)object;
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
if (currentBatch_->used_ == currentBatch_->end_) {
|
|
||||||
currentBatch_ = currentBatch_->next_;
|
|
||||||
while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_)
|
|
||||||
currentBatch_ = currentBatch_->next_;
|
|
||||||
|
|
||||||
if (!currentBatch_) // no free batch found, allocate a new one
|
|
||||||
{
|
|
||||||
currentBatch_ = allocateBatch(objectsPerPage_);
|
|
||||||
currentBatch_->next_ = batches_; // insert at the head of the list
|
|
||||||
batches_ = currentBatch_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AllocatedType* allocated = currentBatch_->used_;
|
|
||||||
currentBatch_->used_ += objectPerAllocation;
|
|
||||||
return allocated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Release the object.
|
|
||||||
/// @warning it is the responsability of the caller to actually destruct the
|
|
||||||
/// object.
|
|
||||||
void release(AllocatedType* object) {
|
|
||||||
assert(object != 0);
|
|
||||||
*(AllocatedType**)object = freeHead_;
|
|
||||||
freeHead_ = object;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct BatchInfo {
|
|
||||||
BatchInfo* next_;
|
|
||||||
AllocatedType* used_;
|
|
||||||
AllocatedType* end_;
|
|
||||||
AllocatedType buffer_[objectPerAllocation];
|
|
||||||
};
|
|
||||||
|
|
||||||
// disabled copy constructor and assignement operator.
|
|
||||||
BatchAllocator(const BatchAllocator&);
|
|
||||||
void operator=(const BatchAllocator&);
|
|
||||||
|
|
||||||
static BatchInfo* allocateBatch(unsigned int objectsPerPage) {
|
|
||||||
const unsigned int mallocSize =
|
|
||||||
sizeof(BatchInfo) - sizeof(AllocatedType) * objectPerAllocation +
|
|
||||||
sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
|
||||||
BatchInfo* batch = static_cast<BatchInfo*>(malloc(mallocSize));
|
|
||||||
batch->next_ = 0;
|
|
||||||
batch->used_ = batch->buffer_;
|
|
||||||
batch->end_ = batch->buffer_ + objectsPerPage;
|
|
||||||
return batch;
|
|
||||||
}
|
|
||||||
|
|
||||||
BatchInfo* batches_;
|
|
||||||
BatchInfo* currentBatch_;
|
|
||||||
/// Head of a single linked list within the allocated space of freeed object
|
|
||||||
AllocatedType* freeHead_;
|
|
||||||
unsigned int objectsPerPage_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Json
|
|
||||||
|
|
||||||
#endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
|
||||||
|
|
||||||
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
|
@ -1,360 +0,0 @@
|
|||||||
// Copyright 2007-2010 Baptiste Lepilleur
|
|
||||||
// Distributed under MIT license, or public domain if desired and
|
|
||||||
// recognized in your jurisdiction.
|
|
||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
|
||||||
|
|
||||||
// included by json_value.cpp
|
|
||||||
|
|
||||||
namespace Json {
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// class ValueInternalArray
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ValueArrayAllocator::~ValueArrayAllocator() {}
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// class DefaultValueArrayAllocator
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
|
||||||
class DefaultValueArrayAllocator : public ValueArrayAllocator {
|
|
||||||
public: // overridden from ValueArrayAllocator
|
|
||||||
virtual ~DefaultValueArrayAllocator() {}
|
|
||||||
|
|
||||||
virtual ValueInternalArray* newArray() { return new ValueInternalArray(); }
|
|
||||||
|
|
||||||
virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
|
|
||||||
return new ValueInternalArray(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void destructArray(ValueInternalArray* array) { delete array; }
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
reallocateArrayPageIndex(Value**& indexes,
|
|
||||||
ValueInternalArray::PageIndex& indexCount,
|
|
||||||
ValueInternalArray::PageIndex minNewIndexCount) {
|
|
||||||
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
|
|
||||||
if (minNewIndexCount > newIndexCount)
|
|
||||||
newIndexCount = minNewIndexCount;
|
|
||||||
void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
|
|
||||||
JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
|
|
||||||
indexCount = newIndexCount;
|
|
||||||
indexes = static_cast<Value**>(newIndexes);
|
|
||||||
}
|
|
||||||
virtual void releaseArrayPageIndex(Value** indexes,
|
|
||||||
ValueInternalArray::PageIndex indexCount) {
|
|
||||||
if (indexes)
|
|
||||||
free(indexes);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Value* allocateArrayPage() {
|
|
||||||
return static_cast<Value*>(
|
|
||||||
malloc(sizeof(Value) * ValueInternalArray::itemsPerPage));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void releaseArrayPage(Value* value) {
|
|
||||||
if (value)
|
|
||||||
free(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
|
||||||
/// @todo make this thread-safe (lock when accessign batch allocator)
|
|
||||||
class DefaultValueArrayAllocator : public ValueArrayAllocator {
|
|
||||||
public: // overridden from ValueArrayAllocator
|
|
||||||
virtual ~DefaultValueArrayAllocator() {}
|
|
||||||
|
|
||||||
virtual ValueInternalArray* newArray() {
|
|
||||||
ValueInternalArray* array = arraysAllocator_.allocate();
|
|
||||||
new (array) ValueInternalArray(); // placement new
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
|
|
||||||
ValueInternalArray* array = arraysAllocator_.allocate();
|
|
||||||
new (array) ValueInternalArray(other); // placement new
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void destructArray(ValueInternalArray* array) {
|
|
||||||
if (array) {
|
|
||||||
array->~ValueInternalArray();
|
|
||||||
arraysAllocator_.release(array);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
reallocateArrayPageIndex(Value**& indexes,
|
|
||||||
ValueInternalArray::PageIndex& indexCount,
|
|
||||||
ValueInternalArray::PageIndex minNewIndexCount) {
|
|
||||||
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
|
|
||||||
if (minNewIndexCount > newIndexCount)
|
|
||||||
newIndexCount = minNewIndexCount;
|
|
||||||
void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
|
|
||||||
JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
|
|
||||||
indexCount = newIndexCount;
|
|
||||||
indexes = static_cast<Value**>(newIndexes);
|
|
||||||
}
|
|
||||||
virtual void releaseArrayPageIndex(Value** indexes,
|
|
||||||
ValueInternalArray::PageIndex indexCount) {
|
|
||||||
if (indexes)
|
|
||||||
free(indexes);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Value* allocateArrayPage() {
|
|
||||||
return static_cast<Value*>(pagesAllocator_.allocate());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void releaseArrayPage(Value* value) {
|
|
||||||
if (value)
|
|
||||||
pagesAllocator_.release(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BatchAllocator<ValueInternalArray, 1> arraysAllocator_;
|
|
||||||
BatchAllocator<Value, ValueInternalArray::itemsPerPage> pagesAllocator_;
|
|
||||||
};
|
|
||||||
#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
|
||||||
|
|
||||||
static ValueArrayAllocator*& arrayAllocator() {
|
|
||||||
static DefaultValueArrayAllocator defaultAllocator;
|
|
||||||
static ValueArrayAllocator* arrayAllocator = &defaultAllocator;
|
|
||||||
return arrayAllocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct DummyArrayAllocatorInitializer {
|
|
||||||
DummyArrayAllocatorInitializer() {
|
|
||||||
arrayAllocator(); // ensure arrayAllocator() statics are initialized before
|
|
||||||
// main().
|
|
||||||
}
|
|
||||||
} dummyArrayAllocatorInitializer;
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// class ValueInternalArray
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
bool ValueInternalArray::equals(const IteratorState& x,
|
|
||||||
const IteratorState& other) {
|
|
||||||
return x.array_ == other.array_ &&
|
|
||||||
x.currentItemIndex_ == other.currentItemIndex_ &&
|
|
||||||
x.currentPageIndex_ == other.currentPageIndex_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalArray::increment(IteratorState& it) {
|
|
||||||
JSON_ASSERT_MESSAGE(
|
|
||||||
it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
|
|
||||||
it.currentItemIndex_ !=
|
|
||||||
it.array_->size_,
|
|
||||||
"ValueInternalArray::increment(): moving iterator beyond end");
|
|
||||||
++(it.currentItemIndex_);
|
|
||||||
if (it.currentItemIndex_ == itemsPerPage) {
|
|
||||||
it.currentItemIndex_ = 0;
|
|
||||||
++(it.currentPageIndex_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalArray::decrement(IteratorState& it) {
|
|
||||||
JSON_ASSERT_MESSAGE(
|
|
||||||
it.array_ && it.currentPageIndex_ == it.array_->pages_ &&
|
|
||||||
it.currentItemIndex_ == 0,
|
|
||||||
"ValueInternalArray::decrement(): moving iterator beyond end");
|
|
||||||
if (it.currentItemIndex_ == 0) {
|
|
||||||
it.currentItemIndex_ = itemsPerPage - 1;
|
|
||||||
--(it.currentPageIndex_);
|
|
||||||
} else {
|
|
||||||
--(it.currentItemIndex_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Value& ValueInternalArray::unsafeDereference(const IteratorState& it) {
|
|
||||||
return (*(it.currentPageIndex_))[it.currentItemIndex_];
|
|
||||||
}
|
|
||||||
|
|
||||||
Value& ValueInternalArray::dereference(const IteratorState& it) {
|
|
||||||
JSON_ASSERT_MESSAGE(
|
|
||||||
it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
|
|
||||||
it.currentItemIndex_ <
|
|
||||||
it.array_->size_,
|
|
||||||
"ValueInternalArray::dereference(): dereferencing invalid iterator");
|
|
||||||
return unsafeDereference(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalArray::makeBeginIterator(IteratorState& it) const {
|
|
||||||
it.array_ = const_cast<ValueInternalArray*>(this);
|
|
||||||
it.currentItemIndex_ = 0;
|
|
||||||
it.currentPageIndex_ = pages_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalArray::makeIterator(IteratorState& it,
|
|
||||||
ArrayIndex index) const {
|
|
||||||
it.array_ = const_cast<ValueInternalArray*>(this);
|
|
||||||
it.currentItemIndex_ = index % itemsPerPage;
|
|
||||||
it.currentPageIndex_ = pages_ + index / itemsPerPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalArray::makeEndIterator(IteratorState& it) const {
|
|
||||||
makeIterator(it, size_);
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalArray::ValueInternalArray() : pages_(0), size_(0), pageCount_(0) {}
|
|
||||||
|
|
||||||
ValueInternalArray::ValueInternalArray(const ValueInternalArray& other)
|
|
||||||
: pages_(0), size_(other.size_), pageCount_(0) {
|
|
||||||
PageIndex minNewPages = other.size_ / itemsPerPage;
|
|
||||||
arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
|
|
||||||
JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
|
|
||||||
"ValueInternalArray::reserve(): bad reallocation");
|
|
||||||
IteratorState itOther;
|
|
||||||
other.makeBeginIterator(itOther);
|
|
||||||
Value* value;
|
|
||||||
for (ArrayIndex index = 0; index < size_; ++index, increment(itOther)) {
|
|
||||||
if (index % itemsPerPage == 0) {
|
|
||||||
PageIndex pageIndex = index / itemsPerPage;
|
|
||||||
value = arrayAllocator()->allocateArrayPage();
|
|
||||||
pages_[pageIndex] = value;
|
|
||||||
}
|
|
||||||
new (value) Value(dereference(itOther));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalArray& ValueInternalArray::operator=(ValueInternalArray other) {
|
|
||||||
swap(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalArray::~ValueInternalArray() {
|
|
||||||
// destroy all constructed items
|
|
||||||
IteratorState it;
|
|
||||||
IteratorState itEnd;
|
|
||||||
makeBeginIterator(it);
|
|
||||||
makeEndIterator(itEnd);
|
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
|
||||||
Value* value = &dereference(it);
|
|
||||||
value->~Value();
|
|
||||||
}
|
|
||||||
// release all pages
|
|
||||||
PageIndex lastPageIndex = size_ / itemsPerPage;
|
|
||||||
for (PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex)
|
|
||||||
arrayAllocator()->releaseArrayPage(pages_[pageIndex]);
|
|
||||||
// release pages index
|
|
||||||
arrayAllocator()->releaseArrayPageIndex(pages_, pageCount_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalArray::swap(ValueInternalArray& other) {
|
|
||||||
Value** tempPages = pages_;
|
|
||||||
pages_ = other.pages_;
|
|
||||||
other.pages_ = tempPages;
|
|
||||||
ArrayIndex tempSize = size_;
|
|
||||||
size_ = other.size_;
|
|
||||||
other.size_ = tempSize;
|
|
||||||
PageIndex tempPageCount = pageCount_;
|
|
||||||
pageCount_ = other.pageCount_;
|
|
||||||
other.pageCount_ = tempPageCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalArray::clear() {
|
|
||||||
ValueInternalArray dummy;
|
|
||||||
swap(dummy);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalArray::resize(ArrayIndex newSize) {
|
|
||||||
if (newSize == 0)
|
|
||||||
clear();
|
|
||||||
else if (newSize < size_) {
|
|
||||||
IteratorState it;
|
|
||||||
IteratorState itEnd;
|
|
||||||
makeIterator(it, newSize);
|
|
||||||
makeIterator(itEnd, size_);
|
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
|
||||||
Value* value = &dereference(it);
|
|
||||||
value->~Value();
|
|
||||||
}
|
|
||||||
PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
|
|
||||||
PageIndex lastPageIndex = size_ / itemsPerPage;
|
|
||||||
for (; pageIndex < lastPageIndex; ++pageIndex)
|
|
||||||
arrayAllocator()->releaseArrayPage(pages_[pageIndex]);
|
|
||||||
size_ = newSize;
|
|
||||||
} else if (newSize > size_)
|
|
||||||
resolveReference(newSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalArray::makeIndexValid(ArrayIndex index) {
|
|
||||||
// Need to enlarge page index ?
|
|
||||||
if (index >= pageCount_ * itemsPerPage) {
|
|
||||||
PageIndex minNewPages = (index + 1) / itemsPerPage;
|
|
||||||
arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
|
|
||||||
JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
|
|
||||||
"ValueInternalArray::reserve(): bad reallocation");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to allocate new pages ?
|
|
||||||
ArrayIndex nextPageIndex = (size_ % itemsPerPage) != 0
|
|
||||||
? size_ - (size_ % itemsPerPage) + itemsPerPage
|
|
||||||
: size_;
|
|
||||||
if (nextPageIndex <= index) {
|
|
||||||
PageIndex pageIndex = nextPageIndex / itemsPerPage;
|
|
||||||
PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
|
|
||||||
for (; pageToAllocate-- > 0; ++pageIndex)
|
|
||||||
pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize all new entries
|
|
||||||
IteratorState it;
|
|
||||||
IteratorState itEnd;
|
|
||||||
makeIterator(it, size_);
|
|
||||||
size_ = index + 1;
|
|
||||||
makeIterator(itEnd, size_);
|
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
|
||||||
Value* value = &dereference(it);
|
|
||||||
new (value) Value(); // Construct a default value using placement new
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Value& ValueInternalArray::resolveReference(ArrayIndex index) {
|
|
||||||
if (index >= size_)
|
|
||||||
makeIndexValid(index);
|
|
||||||
return pages_[index / itemsPerPage][index % itemsPerPage];
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* ValueInternalArray::find(ArrayIndex index) const {
|
|
||||||
if (index >= size_)
|
|
||||||
return 0;
|
|
||||||
return &(pages_[index / itemsPerPage][index % itemsPerPage]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalArray::ArrayIndex ValueInternalArray::size() const {
|
|
||||||
return size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ValueInternalArray::distance(const IteratorState& x,
|
|
||||||
const IteratorState& y) {
|
|
||||||
return indexOf(y) - indexOf(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalArray::ArrayIndex
|
|
||||||
ValueInternalArray::indexOf(const IteratorState& iterator) {
|
|
||||||
if (!iterator.array_)
|
|
||||||
return ArrayIndex(-1);
|
|
||||||
return ArrayIndex((iterator.currentPageIndex_ - iterator.array_->pages_) *
|
|
||||||
itemsPerPage +
|
|
||||||
iterator.currentItemIndex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ValueInternalArray::compare(const ValueInternalArray& other) const {
|
|
||||||
int sizeDiff(size_ - other.size_);
|
|
||||||
if (sizeDiff != 0)
|
|
||||||
return sizeDiff;
|
|
||||||
|
|
||||||
for (ArrayIndex index = 0; index < size_; ++index) {
|
|
||||||
int diff = pages_[index / itemsPerPage][index % itemsPerPage].compare(
|
|
||||||
other.pages_[index / itemsPerPage][index % itemsPerPage]);
|
|
||||||
if (diff != 0)
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Json
|
|
@ -1,473 +0,0 @@
|
|||||||
// Copyright 2007-2010 Baptiste Lepilleur
|
|
||||||
// Distributed under MIT license, or public domain if desired and
|
|
||||||
// recognized in your jurisdiction.
|
|
||||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
|
||||||
|
|
||||||
// included by json_value.cpp
|
|
||||||
|
|
||||||
namespace Json {
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// class ValueInternalMap
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/** \internal MUST be safely initialized using memset( this, 0,
|
|
||||||
* sizeof(ValueInternalLink) );
|
|
||||||
* This optimization is used by the fast allocator.
|
|
||||||
*/
|
|
||||||
ValueInternalLink::ValueInternalLink() : previous_(0), next_(0) {}
|
|
||||||
|
|
||||||
ValueInternalLink::~ValueInternalLink() {
|
|
||||||
for (int index = 0; index < itemPerLink; ++index) {
|
|
||||||
if (!items_[index].isItemAvailable()) {
|
|
||||||
if (!items_[index].isMemberNameStatic())
|
|
||||||
free(keys_[index]);
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueMapAllocator::~ValueMapAllocator() {}
|
|
||||||
|
|
||||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
|
||||||
class DefaultValueMapAllocator : public ValueMapAllocator {
|
|
||||||
public: // overridden from ValueMapAllocator
|
|
||||||
virtual ValueInternalMap* newMap() { return new ValueInternalMap(); }
|
|
||||||
|
|
||||||
virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
|
|
||||||
return new ValueInternalMap(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void destructMap(ValueInternalMap* map) { delete map; }
|
|
||||||
|
|
||||||
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
|
|
||||||
return new ValueInternalLink[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
|
|
||||||
|
|
||||||
virtual ValueInternalLink* allocateMapLink() {
|
|
||||||
return new ValueInternalLink();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void releaseMapLink(ValueInternalLink* link) { delete link; }
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
/// @todo make this thread-safe (lock when accessign batch allocator)
|
|
||||||
class DefaultValueMapAllocator : public ValueMapAllocator {
|
|
||||||
public: // overridden from ValueMapAllocator
|
|
||||||
virtual ValueInternalMap* newMap() {
|
|
||||||
ValueInternalMap* map = mapsAllocator_.allocate();
|
|
||||||
new (map) ValueInternalMap(); // placement new
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
|
|
||||||
ValueInternalMap* map = mapsAllocator_.allocate();
|
|
||||||
new (map) ValueInternalMap(other); // placement new
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void destructMap(ValueInternalMap* map) {
|
|
||||||
if (map) {
|
|
||||||
map->~ValueInternalMap();
|
|
||||||
mapsAllocator_.release(map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
|
|
||||||
return new ValueInternalLink[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
|
|
||||||
|
|
||||||
virtual ValueInternalLink* allocateMapLink() {
|
|
||||||
ValueInternalLink* link = linksAllocator_.allocate();
|
|
||||||
memset(link, 0, sizeof(ValueInternalLink));
|
|
||||||
return link;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void releaseMapLink(ValueInternalLink* link) {
|
|
||||||
link->~ValueInternalLink();
|
|
||||||
linksAllocator_.release(link);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BatchAllocator<ValueInternalMap, 1> mapsAllocator_;
|
|
||||||
BatchAllocator<ValueInternalLink, 1> linksAllocator_;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static ValueMapAllocator*& mapAllocator() {
|
|
||||||
static DefaultValueMapAllocator defaultAllocator;
|
|
||||||
static ValueMapAllocator* mapAllocator = &defaultAllocator;
|
|
||||||
return mapAllocator;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct DummyMapAllocatorInitializer {
|
|
||||||
DummyMapAllocatorInitializer() {
|
|
||||||
mapAllocator(); // ensure mapAllocator() statics are initialized before
|
|
||||||
// main().
|
|
||||||
}
|
|
||||||
} dummyMapAllocatorInitializer;
|
|
||||||
|
|
||||||
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
|
|
||||||
|
|
||||||
/*
|
|
||||||
use linked list hash map.
|
|
||||||
buckets array is a container.
|
|
||||||
linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
|
|
||||||
value have extra state: valid, available, deleted
|
|
||||||
*/
|
|
||||||
|
|
||||||
ValueInternalMap::ValueInternalMap()
|
|
||||||
: buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {}
|
|
||||||
|
|
||||||
ValueInternalMap::ValueInternalMap(const ValueInternalMap& other)
|
|
||||||
: buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {
|
|
||||||
reserve(other.itemCount_);
|
|
||||||
IteratorState it;
|
|
||||||
IteratorState itEnd;
|
|
||||||
other.makeBeginIterator(it);
|
|
||||||
other.makeEndIterator(itEnd);
|
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
|
||||||
bool isStatic;
|
|
||||||
const char* memberName = key(it, isStatic);
|
|
||||||
const Value& aValue = value(it);
|
|
||||||
resolveReference(memberName, isStatic) = aValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalMap& ValueInternalMap::operator=(ValueInternalMap other) {
|
|
||||||
swap(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalMap::~ValueInternalMap() {
|
|
||||||
if (buckets_) {
|
|
||||||
for (BucketIndex bucketIndex = 0; bucketIndex < bucketsSize_;
|
|
||||||
++bucketIndex) {
|
|
||||||
ValueInternalLink* link = buckets_[bucketIndex].next_;
|
|
||||||
while (link) {
|
|
||||||
ValueInternalLink* linkToRelease = link;
|
|
||||||
link = link->next_;
|
|
||||||
mapAllocator()->releaseMapLink(linkToRelease);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mapAllocator()->releaseMapBuckets(buckets_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalMap::swap(ValueInternalMap& other) {
|
|
||||||
ValueInternalLink* tempBuckets = buckets_;
|
|
||||||
buckets_ = other.buckets_;
|
|
||||||
other.buckets_ = tempBuckets;
|
|
||||||
ValueInternalLink* tempTailLink = tailLink_;
|
|
||||||
tailLink_ = other.tailLink_;
|
|
||||||
other.tailLink_ = tempTailLink;
|
|
||||||
BucketIndex tempBucketsSize = bucketsSize_;
|
|
||||||
bucketsSize_ = other.bucketsSize_;
|
|
||||||
other.bucketsSize_ = tempBucketsSize;
|
|
||||||
BucketIndex tempItemCount = itemCount_;
|
|
||||||
itemCount_ = other.itemCount_;
|
|
||||||
other.itemCount_ = tempItemCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalMap::clear() {
|
|
||||||
ValueInternalMap dummy;
|
|
||||||
swap(dummy);
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalMap::BucketIndex ValueInternalMap::size() const {
|
|
||||||
return itemCount_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ValueInternalMap::reserveDelta(BucketIndex growth) {
|
|
||||||
return reserve(itemCount_ + growth);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ValueInternalMap::reserve(BucketIndex newItemCount) {
|
|
||||||
if (!buckets_ && newItemCount > 0) {
|
|
||||||
buckets_ = mapAllocator()->allocateMapBuckets(1);
|
|
||||||
bucketsSize_ = 1;
|
|
||||||
tailLink_ = &buckets_[0];
|
|
||||||
}
|
|
||||||
// BucketIndex idealBucketCount = (newItemCount +
|
|
||||||
// ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Value* ValueInternalMap::find(const char* key) const {
|
|
||||||
if (!bucketsSize_)
|
|
||||||
return 0;
|
|
||||||
HashKey hashedKey = hash(key);
|
|
||||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
|
||||||
for (const ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
|
|
||||||
current = current->next_) {
|
|
||||||
for (BucketIndex index = 0; index < ValueInternalLink::itemPerLink;
|
|
||||||
++index) {
|
|
||||||
if (current->items_[index].isItemAvailable())
|
|
||||||
return 0;
|
|
||||||
if (strcmp(key, current->keys_[index]) == 0)
|
|
||||||
return ¤t->items_[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* ValueInternalMap::find(const char* key) {
|
|
||||||
const ValueInternalMap* constThis = this;
|
|
||||||
return const_cast<Value*>(constThis->find(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
Value& ValueInternalMap::resolveReference(const char* key, bool isStatic) {
|
|
||||||
HashKey hashedKey = hash(key);
|
|
||||||
if (bucketsSize_) {
|
|
||||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
|
||||||
ValueInternalLink** previous = 0;
|
|
||||||
BucketIndex index;
|
|
||||||
for (ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
|
|
||||||
previous = ¤t->next_, current = current->next_) {
|
|
||||||
for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
|
|
||||||
if (current->items_[index].isItemAvailable())
|
|
||||||
return setNewItem(key, isStatic, current, index);
|
|
||||||
if (strcmp(key, current->keys_[index]) == 0)
|
|
||||||
return current->items_[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reserveDelta(1);
|
|
||||||
return unsafeAdd(key, isStatic, hashedKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalMap::remove(const char* key) {
|
|
||||||
HashKey hashedKey = hash(key);
|
|
||||||
if (!bucketsSize_)
|
|
||||||
return;
|
|
||||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
|
||||||
for (ValueInternalLink* link = &buckets_[bucketIndex]; link != 0;
|
|
||||||
link = link->next_) {
|
|
||||||
BucketIndex index;
|
|
||||||
for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
|
|
||||||
if (link->items_[index].isItemAvailable())
|
|
||||||
return;
|
|
||||||
if (strcmp(key, link->keys_[index]) == 0) {
|
|
||||||
doActualRemove(link, index, bucketIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalMap::doActualRemove(ValueInternalLink* link,
|
|
||||||
BucketIndex index,
|
|
||||||
BucketIndex bucketIndex) {
|
|
||||||
// find last item of the bucket and swap it with the 'removed' one.
|
|
||||||
// set removed items flags to 'available'.
|
|
||||||
// if last page only contains 'available' items, then desallocate it (it's
|
|
||||||
// empty)
|
|
||||||
ValueInternalLink*& lastLink = getLastLinkInBucket(index);
|
|
||||||
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
|
|
||||||
for (; lastItemIndex < ValueInternalLink::itemPerLink;
|
|
||||||
++lastItemIndex) // may be optimized with dicotomic search
|
|
||||||
{
|
|
||||||
if (lastLink->items_[lastItemIndex].isItemAvailable())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
BucketIndex lastUsedIndex = lastItemIndex - 1;
|
|
||||||
Value* valueToDelete = &link->items_[index];
|
|
||||||
Value* valueToPreserve = &lastLink->items_[lastUsedIndex];
|
|
||||||
if (valueToDelete != valueToPreserve)
|
|
||||||
valueToDelete->swap(*valueToPreserve);
|
|
||||||
if (lastUsedIndex == 0) // page is now empty
|
|
||||||
{ // remove it from bucket linked list and delete it.
|
|
||||||
ValueInternalLink* linkPreviousToLast = lastLink->previous_;
|
|
||||||
if (linkPreviousToLast != 0) // can not deleted bucket link.
|
|
||||||
{
|
|
||||||
mapAllocator()->releaseMapLink(lastLink);
|
|
||||||
linkPreviousToLast->next_ = 0;
|
|
||||||
lastLink = linkPreviousToLast;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Value dummy;
|
|
||||||
valueToPreserve->swap(dummy); // restore deleted to default Value.
|
|
||||||
valueToPreserve->setItemUsed(false);
|
|
||||||
}
|
|
||||||
--itemCount_;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalLink*&
|
|
||||||
ValueInternalMap::getLastLinkInBucket(BucketIndex bucketIndex) {
|
|
||||||
if (bucketIndex == bucketsSize_ - 1)
|
|
||||||
return tailLink_;
|
|
||||||
ValueInternalLink*& previous = buckets_[bucketIndex + 1].previous_;
|
|
||||||
if (!previous)
|
|
||||||
previous = &buckets_[bucketIndex];
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value& ValueInternalMap::setNewItem(const char* key,
|
|
||||||
bool isStatic,
|
|
||||||
ValueInternalLink* link,
|
|
||||||
BucketIndex index) {
|
|
||||||
char* duplicatedKey = makeMemberName(key);
|
|
||||||
++itemCount_;
|
|
||||||
link->keys_[index] = duplicatedKey;
|
|
||||||
link->items_[index].setItemUsed();
|
|
||||||
link->items_[index].setMemberNameIsStatic(isStatic);
|
|
||||||
return link->items_[index]; // items already default constructed.
|
|
||||||
}
|
|
||||||
|
|
||||||
Value&
|
|
||||||
ValueInternalMap::unsafeAdd(const char* key, bool isStatic, HashKey hashedKey) {
|
|
||||||
JSON_ASSERT_MESSAGE(bucketsSize_ > 0,
|
|
||||||
"ValueInternalMap::unsafeAdd(): internal logic error.");
|
|
||||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
|
||||||
ValueInternalLink*& previousLink = getLastLinkInBucket(bucketIndex);
|
|
||||||
ValueInternalLink* link = previousLink;
|
|
||||||
BucketIndex index;
|
|
||||||
for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
|
|
||||||
if (link->items_[index].isItemAvailable())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (index == ValueInternalLink::itemPerLink) // need to add a new page
|
|
||||||
{
|
|
||||||
ValueInternalLink* newLink = mapAllocator()->allocateMapLink();
|
|
||||||
index = 0;
|
|
||||||
link->next_ = newLink;
|
|
||||||
previousLink = newLink;
|
|
||||||
link = newLink;
|
|
||||||
}
|
|
||||||
return setNewItem(key, isStatic, link, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueInternalMap::HashKey ValueInternalMap::hash(const char* key) const {
|
|
||||||
HashKey hash = 0;
|
|
||||||
while (*key)
|
|
||||||
hash += *key++ * 37;
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ValueInternalMap::compare(const ValueInternalMap& other) const {
|
|
||||||
int sizeDiff(itemCount_ - other.itemCount_);
|
|
||||||
if (sizeDiff != 0)
|
|
||||||
return sizeDiff;
|
|
||||||
// Strict order guaranty is required. Compare all keys FIRST, then compare
|
|
||||||
// values.
|
|
||||||
IteratorState it;
|
|
||||||
IteratorState itEnd;
|
|
||||||
makeBeginIterator(it);
|
|
||||||
makeEndIterator(itEnd);
|
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
|
||||||
if (!other.find(key(it)))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All keys are equals, let's compare values
|
|
||||||
makeBeginIterator(it);
|
|
||||||
for (; !equals(it, itEnd); increment(it)) {
|
|
||||||
const Value* otherValue = other.find(key(it));
|
|
||||||
int valueDiff = value(it).compare(*otherValue);
|
|
||||||
if (valueDiff != 0)
|
|
||||||
return valueDiff;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalMap::makeBeginIterator(IteratorState& it) const {
|
|
||||||
it.map_ = const_cast<ValueInternalMap*>(this);
|
|
||||||
it.bucketIndex_ = 0;
|
|
||||||
it.itemIndex_ = 0;
|
|
||||||
it.link_ = buckets_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalMap::makeEndIterator(IteratorState& it) const {
|
|
||||||
it.map_ = const_cast<ValueInternalMap*>(this);
|
|
||||||
it.bucketIndex_ = bucketsSize_;
|
|
||||||
it.itemIndex_ = 0;
|
|
||||||
it.link_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ValueInternalMap::equals(const IteratorState& x,
|
|
||||||
const IteratorState& other) {
|
|
||||||
return x.map_ == other.map_ && x.bucketIndex_ == other.bucketIndex_ &&
|
|
||||||
x.link_ == other.link_ && x.itemIndex_ == other.itemIndex_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalMap::incrementBucket(IteratorState& iterator) {
|
|
||||||
++iterator.bucketIndex_;
|
|
||||||
JSON_ASSERT_MESSAGE(
|
|
||||||
iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
|
|
||||||
"ValueInternalMap::increment(): attempting to iterate beyond end.");
|
|
||||||
if (iterator.bucketIndex_ == iterator.map_->bucketsSize_)
|
|
||||||
iterator.link_ = 0;
|
|
||||||
else
|
|
||||||
iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
|
|
||||||
iterator.itemIndex_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalMap::increment(IteratorState& iterator) {
|
|
||||||
JSON_ASSERT_MESSAGE(iterator.map_,
|
|
||||||
"Attempting to iterator using invalid iterator.");
|
|
||||||
++iterator.itemIndex_;
|
|
||||||
if (iterator.itemIndex_ == ValueInternalLink::itemPerLink) {
|
|
||||||
JSON_ASSERT_MESSAGE(
|
|
||||||
iterator.link_ != 0,
|
|
||||||
"ValueInternalMap::increment(): attempting to iterate beyond end.");
|
|
||||||
iterator.link_ = iterator.link_->next_;
|
|
||||||
if (iterator.link_ == 0)
|
|
||||||
incrementBucket(iterator);
|
|
||||||
} else if (iterator.link_->items_[iterator.itemIndex_].isItemAvailable()) {
|
|
||||||
incrementBucket(iterator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValueInternalMap::decrement(IteratorState& iterator) {
|
|
||||||
if (iterator.itemIndex_ == 0) {
|
|
||||||
JSON_ASSERT_MESSAGE(iterator.map_,
|
|
||||||
"Attempting to iterate using invalid iterator.");
|
|
||||||
if (iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_]) {
|
|
||||||
JSON_ASSERT_MESSAGE(iterator.bucketIndex_ > 0,
|
|
||||||
"Attempting to iterate beyond beginning.");
|
|
||||||
--(iterator.bucketIndex_);
|
|
||||||
}
|
|
||||||
iterator.link_ = iterator.link_->previous_;
|
|
||||||
iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ValueInternalMap::key(const IteratorState& iterator) {
|
|
||||||
JSON_ASSERT_MESSAGE(iterator.link_,
|
|
||||||
"Attempting to iterate using invalid iterator.");
|
|
||||||
return iterator.link_->keys_[iterator.itemIndex_];
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ValueInternalMap::key(const IteratorState& iterator,
|
|
||||||
bool& isStatic) {
|
|
||||||
JSON_ASSERT_MESSAGE(iterator.link_,
|
|
||||||
"Attempting to iterate using invalid iterator.");
|
|
||||||
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
|
|
||||||
return iterator.link_->keys_[iterator.itemIndex_];
|
|
||||||
}
|
|
||||||
|
|
||||||
Value& ValueInternalMap::value(const IteratorState& iterator) {
|
|
||||||
JSON_ASSERT_MESSAGE(iterator.link_,
|
|
||||||
"Attempting to iterate using invalid iterator.");
|
|
||||||
return iterator.link_->items_[iterator.itemIndex_];
|
|
||||||
}
|
|
||||||
|
|
||||||
int ValueInternalMap::distance(const IteratorState& x, const IteratorState& y) {
|
|
||||||
int offset = 0;
|
|
||||||
IteratorState it = x;
|
|
||||||
while (!equals(it, y))
|
|
||||||
increment(it);
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Json
|
|
@ -7,9 +7,6 @@
|
|||||||
#include <json/assertions.h>
|
#include <json/assertions.h>
|
||||||
#include <json/value.h>
|
#include <json/value.h>
|
||||||
#include <json/writer.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)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@ -117,10 +114,6 @@ static inline void releaseStringValue(char* value) { free(value); }
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
#if !defined(JSON_IS_AMALGAMATION)
|
#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"
|
#include "json_valueiterator.inl"
|
||||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||||
@ -162,7 +155,6 @@ void Value::CommentInfo::setComment(const char* text, size_t len) {
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
// Notes: index_ indicates if the string was allocated when
|
// Notes: index_ indicates if the string was allocated when
|
||||||
// a string is stored.
|
// a string is stored.
|
||||||
@ -215,8 +207,6 @@ const char* Value::CZString::c_str() const { return cstr_; }
|
|||||||
|
|
||||||
bool Value::CZString::isStaticString() const { return index_ == noDuplication; }
|
bool Value::CZString::isStaticString() const { return index_ == noDuplication; }
|
||||||
|
|
||||||
#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@ -244,19 +234,10 @@ Value::Value(ValueType type) {
|
|||||||
case stringValue:
|
case stringValue:
|
||||||
value_.string_ = 0;
|
value_.string_ = 0;
|
||||||
break;
|
break;
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
value_.map_ = new ObjectValues();
|
value_.map_ = new ObjectValues();
|
||||||
break;
|
break;
|
||||||
#else
|
|
||||||
case arrayValue:
|
|
||||||
value_.array_ = arrayAllocator()->newArray();
|
|
||||||
break;
|
|
||||||
case objectValue:
|
|
||||||
value_.map_ = mapAllocator()->newMap();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case booleanValue:
|
case booleanValue:
|
||||||
value_.bool_ = false;
|
value_.bool_ = false;
|
||||||
break;
|
break;
|
||||||
@ -326,10 +307,6 @@ Value::Value(bool value) {
|
|||||||
|
|
||||||
Value::Value(const Value& other)
|
Value::Value(const Value& other)
|
||||||
: type_(other.type_), allocated_(false)
|
: 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_) {
|
switch (type_) {
|
||||||
@ -349,19 +326,10 @@ Value::Value(const Value& other)
|
|||||||
allocated_ = false;
|
allocated_ = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
value_.map_ = new ObjectValues(*other.value_.map_);
|
value_.map_ = new ObjectValues(*other.value_.map_);
|
||||||
break;
|
break;
|
||||||
#else
|
|
||||||
case arrayValue:
|
|
||||||
value_.array_ = arrayAllocator()->newArrayCopy(*other.value_.array_);
|
|
||||||
break;
|
|
||||||
case objectValue:
|
|
||||||
value_.map_ = mapAllocator()->newMapCopy(*other.value_.map_);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
}
|
}
|
||||||
@ -388,19 +356,10 @@ Value::~Value() {
|
|||||||
if (allocated_)
|
if (allocated_)
|
||||||
releaseStringValue(value_.string_);
|
releaseStringValue(value_.string_);
|
||||||
break;
|
break;
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
delete value_.map_;
|
delete value_.map_;
|
||||||
break;
|
break;
|
||||||
#else
|
|
||||||
case arrayValue:
|
|
||||||
arrayAllocator()->destructArray(value_.array_);
|
|
||||||
break;
|
|
||||||
case objectValue:
|
|
||||||
mapAllocator()->destructMap(value_.map_);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
}
|
}
|
||||||
@ -460,7 +419,6 @@ bool Value::operator<(const Value& other) const {
|
|||||||
return (value_.string_ == 0 && other.value_.string_) ||
|
return (value_.string_ == 0 && other.value_.string_) ||
|
||||||
(other.value_.string_ && value_.string_ &&
|
(other.value_.string_ && value_.string_ &&
|
||||||
strcmp(value_.string_, other.value_.string_) < 0);
|
strcmp(value_.string_, other.value_.string_) < 0);
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue: {
|
case objectValue: {
|
||||||
int delta = int(value_.map_->size() - other.value_.map_->size());
|
int delta = int(value_.map_->size() - other.value_.map_->size());
|
||||||
@ -468,12 +426,6 @@ bool Value::operator<(const Value& other) const {
|
|||||||
return delta < 0;
|
return delta < 0;
|
||||||
return (*value_.map_) < (*other.value_.map_);
|
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:
|
default:
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
}
|
}
|
||||||
@ -509,17 +461,10 @@ bool Value::operator==(const Value& other) const {
|
|||||||
return (value_.string_ == other.value_.string_) ||
|
return (value_.string_ == other.value_.string_) ||
|
||||||
(other.value_.string_ && value_.string_ &&
|
(other.value_.string_ && value_.string_ &&
|
||||||
strcmp(value_.string_, other.value_.string_) == 0);
|
strcmp(value_.string_, other.value_.string_) == 0);
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
return value_.map_->size() == other.value_.map_->size() &&
|
return value_.map_->size() == other.value_.map_->size() &&
|
||||||
(*value_.map_) == (*other.value_.map_);
|
(*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:
|
default:
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
}
|
}
|
||||||
@ -769,7 +714,6 @@ ArrayIndex Value::size() const {
|
|||||||
case booleanValue:
|
case booleanValue:
|
||||||
case stringValue:
|
case stringValue:
|
||||||
return 0;
|
return 0;
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
case arrayValue: // size of the array is highest index + 1
|
case arrayValue: // size of the array is highest index + 1
|
||||||
if (!value_.map_->empty()) {
|
if (!value_.map_->empty()) {
|
||||||
ObjectValues::const_iterator itLast = value_.map_->end();
|
ObjectValues::const_iterator itLast = value_.map_->end();
|
||||||
@ -779,12 +723,6 @@ ArrayIndex Value::size() const {
|
|||||||
return 0;
|
return 0;
|
||||||
case objectValue:
|
case objectValue:
|
||||||
return ArrayIndex(value_.map_->size());
|
return ArrayIndex(value_.map_->size());
|
||||||
#else
|
|
||||||
case arrayValue:
|
|
||||||
return Int(value_.array_->size());
|
|
||||||
case objectValue:
|
|
||||||
return Int(value_.map_->size());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
JSON_ASSERT_UNREACHABLE;
|
JSON_ASSERT_UNREACHABLE;
|
||||||
return 0; // unreachable;
|
return 0; // unreachable;
|
||||||
@ -806,19 +744,10 @@ void Value::clear() {
|
|||||||
start_ = 0;
|
start_ = 0;
|
||||||
limit_ = 0;
|
limit_ = 0;
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
case arrayValue:
|
case arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
value_.map_->clear();
|
value_.map_->clear();
|
||||||
break;
|
break;
|
||||||
#else
|
|
||||||
case arrayValue:
|
|
||||||
value_.array_->clear();
|
|
||||||
break;
|
|
||||||
case objectValue:
|
|
||||||
value_.map_->clear();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -829,7 +758,6 @@ void Value::resize(ArrayIndex newSize) {
|
|||||||
"in Json::Value::resize(): requires arrayValue");
|
"in Json::Value::resize(): requires arrayValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
*this = Value(arrayValue);
|
*this = Value(arrayValue);
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ArrayIndex oldSize = size();
|
ArrayIndex oldSize = size();
|
||||||
if (newSize == 0)
|
if (newSize == 0)
|
||||||
clear();
|
clear();
|
||||||
@ -841,9 +769,6 @@ void Value::resize(ArrayIndex newSize) {
|
|||||||
}
|
}
|
||||||
assert(size() == newSize);
|
assert(size() == newSize);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
value_.array_->resize(newSize);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator[](ArrayIndex index) {
|
Value& Value::operator[](ArrayIndex index) {
|
||||||
@ -852,7 +777,6 @@ Value& Value::operator[](ArrayIndex index) {
|
|||||||
"in Json::Value::operator[](ArrayIndex): requires arrayValue");
|
"in Json::Value::operator[](ArrayIndex): requires arrayValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
*this = Value(arrayValue);
|
*this = Value(arrayValue);
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
CZString key(index);
|
CZString key(index);
|
||||||
ObjectValues::iterator it = value_.map_->lower_bound(key);
|
ObjectValues::iterator it = value_.map_->lower_bound(key);
|
||||||
if (it != value_.map_->end() && (*it).first == key)
|
if (it != value_.map_->end() && (*it).first == key)
|
||||||
@ -861,9 +785,6 @@ Value& Value::operator[](ArrayIndex index) {
|
|||||||
ObjectValues::value_type defaultValue(key, null);
|
ObjectValues::value_type defaultValue(key, null);
|
||||||
it = value_.map_->insert(it, defaultValue);
|
it = value_.map_->insert(it, defaultValue);
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
#else
|
|
||||||
return value_.array_->resolveReference(index);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator[](int index) {
|
Value& Value::operator[](int index) {
|
||||||
@ -879,16 +800,11 @@ const Value& Value::operator[](ArrayIndex index) const {
|
|||||||
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
|
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
return null;
|
return null;
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
CZString key(index);
|
CZString key(index);
|
||||||
ObjectValues::const_iterator it = value_.map_->find(key);
|
ObjectValues::const_iterator it = value_.map_->find(key);
|
||||||
if (it == value_.map_->end())
|
if (it == value_.map_->end())
|
||||||
return null;
|
return null;
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
#else
|
|
||||||
Value* value = value_.array_->find(index);
|
|
||||||
return value ? *value : null;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Value& Value::operator[](int index) const {
|
const Value& Value::operator[](int index) const {
|
||||||
@ -905,9 +821,6 @@ Value& Value::operator[](const char* key) {
|
|||||||
void Value::initBasic(ValueType type, bool allocated) {
|
void Value::initBasic(ValueType type, bool allocated) {
|
||||||
type_ = type;
|
type_ = type;
|
||||||
allocated_ = allocated;
|
allocated_ = allocated;
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
itemIsUsed_ = 0;
|
|
||||||
#endif
|
|
||||||
comments_ = 0;
|
comments_ = 0;
|
||||||
start_ = 0;
|
start_ = 0;
|
||||||
limit_ = 0;
|
limit_ = 0;
|
||||||
@ -919,7 +832,6 @@ Value& Value::resolveReference(const char* key, bool isStatic) {
|
|||||||
"in Json::Value::resolveReference(): requires objectValue");
|
"in Json::Value::resolveReference(): requires objectValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
*this = Value(objectValue);
|
*this = Value(objectValue);
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
CZString actualKey(
|
CZString actualKey(
|
||||||
key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy);
|
key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy);
|
||||||
ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
|
ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
|
||||||
@ -930,9 +842,6 @@ Value& Value::resolveReference(const char* key, bool isStatic) {
|
|||||||
it = value_.map_->insert(it, defaultValue);
|
it = value_.map_->insert(it, defaultValue);
|
||||||
Value& value = (*it).second;
|
Value& value = (*it).second;
|
||||||
return value;
|
return value;
|
||||||
#else
|
|
||||||
return value_.map_->resolveReference(key, isStatic);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
|
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
|
||||||
@ -948,16 +857,11 @@ const Value& Value::operator[](const char* key) const {
|
|||||||
"in Json::Value::operator[](char const*)const: requires objectValue");
|
"in Json::Value::operator[](char const*)const: requires objectValue");
|
||||||
if (type_ == nullValue)
|
if (type_ == nullValue)
|
||||||
return null;
|
return null;
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
CZString actualKey(key, CZString::noDuplication);
|
CZString actualKey(key, CZString::noDuplication);
|
||||||
ObjectValues::const_iterator it = value_.map_->find(actualKey);
|
ObjectValues::const_iterator it = value_.map_->find(actualKey);
|
||||||
if (it == value_.map_->end())
|
if (it == value_.map_->end())
|
||||||
return null;
|
return null;
|
||||||
return (*it).second;
|
return (*it).second;
|
||||||
#else
|
|
||||||
const Value* value = value_.map_->find(key);
|
|
||||||
return value ? *value : null;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value& Value::operator[](const std::string& key) {
|
Value& Value::operator[](const std::string& key) {
|
||||||
@ -998,7 +902,6 @@ bool Value::removeMember(const char* key, Value* removed) {
|
|||||||
if (type_ != objectValue) {
|
if (type_ != objectValue) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
CZString actualKey(key, CZString::noDuplication);
|
CZString actualKey(key, CZString::noDuplication);
|
||||||
ObjectValues::iterator it = value_.map_->find(actualKey);
|
ObjectValues::iterator it = value_.map_->find(actualKey);
|
||||||
if (it == value_.map_->end())
|
if (it == value_.map_->end())
|
||||||
@ -1006,16 +909,6 @@ bool Value::removeMember(const char* key, Value* removed) {
|
|||||||
*removed = it->second;
|
*removed = it->second;
|
||||||
value_.map_->erase(it);
|
value_.map_->erase(it);
|
||||||
return true;
|
return true;
|
||||||
#else
|
|
||||||
Value* value = value_.map_->find(key);
|
|
||||||
if (value) {
|
|
||||||
*removed = *value;
|
|
||||||
value_.map_.remove(key);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Value::removeMember(const char* key) {
|
Value Value::removeMember(const char* key) {
|
||||||
@ -1037,10 +930,6 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
|||||||
if (type_ != arrayValue) {
|
if (type_ != arrayValue) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
JSON_FAIL_MESSAGE("removeIndex is not implemented for ValueInternalArray.");
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
CZString key(index);
|
CZString key(index);
|
||||||
ObjectValues::iterator it = value_.map_->find(key);
|
ObjectValues::iterator it = value_.map_->find(key);
|
||||||
if (it == value_.map_->end()) {
|
if (it == value_.map_->end()) {
|
||||||
@ -1058,7 +947,6 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
|||||||
ObjectValues::iterator itLast = value_.map_->find(keyLast);
|
ObjectValues::iterator itLast = value_.map_->find(keyLast);
|
||||||
value_.map_->erase(itLast);
|
value_.map_->erase(itLast);
|
||||||
return true;
|
return true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JSON_USE_CPPTL
|
#ifdef JSON_USE_CPPTL
|
||||||
@ -1091,19 +979,10 @@ Value::Members Value::getMemberNames() const {
|
|||||||
return Value::Members();
|
return Value::Members();
|
||||||
Members members;
|
Members members;
|
||||||
members.reserve(value_.map_->size());
|
members.reserve(value_.map_->size());
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ObjectValues::const_iterator it = value_.map_->begin();
|
ObjectValues::const_iterator it = value_.map_->begin();
|
||||||
ObjectValues::const_iterator itEnd = value_.map_->end();
|
ObjectValues::const_iterator itEnd = value_.map_->end();
|
||||||
for (; it != itEnd; ++it)
|
for (; it != itEnd; ++it)
|
||||||
members.push_back(std::string((*it).first.c_str()));
|
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
|
|
||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@ -1272,28 +1151,11 @@ std::string Value::toStyledString() const {
|
|||||||
|
|
||||||
Value::const_iterator Value::begin() const {
|
Value::const_iterator Value::begin() const {
|
||||||
switch (type_) {
|
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 arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
if (value_.map_)
|
if (value_.map_)
|
||||||
return const_iterator(value_.map_->begin());
|
return const_iterator(value_.map_->begin());
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1302,28 +1164,11 @@ Value::const_iterator Value::begin() const {
|
|||||||
|
|
||||||
Value::const_iterator Value::end() const {
|
Value::const_iterator Value::end() const {
|
||||||
switch (type_) {
|
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 arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
if (value_.map_)
|
if (value_.map_)
|
||||||
return const_iterator(value_.map_->end());
|
return const_iterator(value_.map_->end());
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1332,28 +1177,11 @@ Value::const_iterator Value::end() const {
|
|||||||
|
|
||||||
Value::iterator Value::begin() {
|
Value::iterator Value::begin() {
|
||||||
switch (type_) {
|
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 arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
if (value_.map_)
|
if (value_.map_)
|
||||||
return iterator(value_.map_->begin());
|
return iterator(value_.map_->begin());
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1362,28 +1190,11 @@ Value::iterator Value::begin() {
|
|||||||
|
|
||||||
Value::iterator Value::end() {
|
Value::iterator Value::end() {
|
||||||
switch (type_) {
|
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 arrayValue:
|
||||||
case objectValue:
|
case objectValue:
|
||||||
if (value_.map_)
|
if (value_.map_)
|
||||||
return iterator(value_.map_->end());
|
return iterator(value_.map_->end());
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -16,66 +16,27 @@ namespace Json {
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ValueIteratorBase::ValueIteratorBase()
|
ValueIteratorBase::ValueIteratorBase()
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
: current_(), isNull_(true) {
|
: current_(), isNull_(true) {
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
: isArray_(true), isNull_(true) {
|
|
||||||
iterator_.array_ = ValueInternalArray::IteratorState();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ValueIteratorBase::ValueIteratorBase(
|
ValueIteratorBase::ValueIteratorBase(
|
||||||
const Value::ObjectValues::iterator& current)
|
const Value::ObjectValues::iterator& current)
|
||||||
: current_(current), isNull_(false) {}
|
: current_(current), isNull_(false) {}
|
||||||
#else
|
|
||||||
ValueIteratorBase::ValueIteratorBase(
|
|
||||||
const ValueInternalArray::IteratorState& state)
|
|
||||||
: isArray_(true) {
|
|
||||||
iterator_.array_ = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueIteratorBase::ValueIteratorBase(
|
|
||||||
const ValueInternalMap::IteratorState& state)
|
|
||||||
: isArray_(false) {
|
|
||||||
iterator_.map_ = state;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Value& ValueIteratorBase::deref() const {
|
Value& ValueIteratorBase::deref() const {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
return current_->second;
|
return current_->second;
|
||||||
#else
|
|
||||||
if (isArray_)
|
|
||||||
return ValueInternalArray::dereference(iterator_.array_);
|
|
||||||
return ValueInternalMap::value(iterator_.map_);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueIteratorBase::increment() {
|
void ValueIteratorBase::increment() {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
++current_;
|
++current_;
|
||||||
#else
|
|
||||||
if (isArray_)
|
|
||||||
ValueInternalArray::increment(iterator_.array_);
|
|
||||||
ValueInternalMap::increment(iterator_.map_);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueIteratorBase::decrement() {
|
void ValueIteratorBase::decrement() {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
--current_;
|
--current_;
|
||||||
#else
|
|
||||||
if (isArray_)
|
|
||||||
ValueInternalArray::decrement(iterator_.array_);
|
|
||||||
ValueInternalMap::decrement(iterator_.map_);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueIteratorBase::difference_type
|
ValueIteratorBase::difference_type
|
||||||
ValueIteratorBase::computeDistance(const SelfType& other) const {
|
ValueIteratorBase::computeDistance(const SelfType& other) const {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
#ifdef JSON_USE_CPPTL_SMALLMAP
|
#ifdef JSON_USE_CPPTL_SMALLMAP
|
||||||
return other.current_ - current_;
|
return other.current_ - current_;
|
||||||
#else
|
#else
|
||||||
@ -100,40 +61,21 @@ ValueIteratorBase::computeDistance(const SelfType& other) const {
|
|||||||
}
|
}
|
||||||
return myDistance;
|
return myDistance;
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
if (isArray_)
|
|
||||||
return ValueInternalArray::distance(iterator_.array_,
|
|
||||||
other.iterator_.array_);
|
|
||||||
return ValueInternalMap::distance(iterator_.map_, other.iterator_.map_);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ValueIteratorBase::isEqual(const SelfType& other) const {
|
bool ValueIteratorBase::isEqual(const SelfType& other) const {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
if (isNull_) {
|
if (isNull_) {
|
||||||
return other.isNull_;
|
return other.isNull_;
|
||||||
}
|
}
|
||||||
return current_ == other.current_;
|
return current_ == other.current_;
|
||||||
#else
|
|
||||||
if (isArray_)
|
|
||||||
return ValueInternalArray::equals(iterator_.array_, other.iterator_.array_);
|
|
||||||
return ValueInternalMap::equals(iterator_.map_, other.iterator_.map_);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValueIteratorBase::copy(const SelfType& other) {
|
void ValueIteratorBase::copy(const SelfType& other) {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
current_ = other.current_;
|
current_ = other.current_;
|
||||||
isNull_ = other.isNull_;
|
isNull_ = other.isNull_;
|
||||||
#else
|
|
||||||
if (isArray_)
|
|
||||||
iterator_.array_ = other.iterator_.array_;
|
|
||||||
iterator_.map_ = other.iterator_.map_;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ValueIteratorBase::key() const {
|
Value ValueIteratorBase::key() const {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
const Value::CZString czstring = (*current_).first;
|
const Value::CZString czstring = (*current_).first;
|
||||||
if (czstring.c_str()) {
|
if (czstring.c_str()) {
|
||||||
if (czstring.isStaticString())
|
if (czstring.isStaticString())
|
||||||
@ -141,39 +83,18 @@ Value ValueIteratorBase::key() const {
|
|||||||
return Value(czstring.c_str());
|
return Value(czstring.c_str());
|
||||||
}
|
}
|
||||||
return Value(czstring.index());
|
return Value(czstring.index());
|
||||||
#else
|
|
||||||
if (isArray_)
|
|
||||||
return Value(ValueInternalArray::indexOf(iterator_.array_));
|
|
||||||
bool isStatic;
|
|
||||||
const char* memberName = ValueInternalMap::key(iterator_.map_, isStatic);
|
|
||||||
if (isStatic)
|
|
||||||
return Value(StaticString(memberName));
|
|
||||||
return Value(memberName);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt ValueIteratorBase::index() const {
|
UInt ValueIteratorBase::index() const {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
const Value::CZString czstring = (*current_).first;
|
const Value::CZString czstring = (*current_).first;
|
||||||
if (!czstring.c_str())
|
if (!czstring.c_str())
|
||||||
return czstring.index();
|
return czstring.index();
|
||||||
return Value::UInt(-1);
|
return Value::UInt(-1);
|
||||||
#else
|
|
||||||
if (isArray_)
|
|
||||||
return Value::UInt(ValueInternalArray::indexOf(iterator_.array_));
|
|
||||||
return Value::UInt(-1);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ValueIteratorBase::memberName() const {
|
const char* ValueIteratorBase::memberName() const {
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
const char* name = (*current_).first.c_str();
|
const char* name = (*current_).first.c_str();
|
||||||
return name ? name : "";
|
return name ? name : "";
|
||||||
#else
|
|
||||||
if (!isArray_)
|
|
||||||
return ValueInternalMap::key(iterator_.map_);
|
|
||||||
return "";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
@ -186,19 +107,9 @@ const char* ValueIteratorBase::memberName() const {
|
|||||||
|
|
||||||
ValueConstIterator::ValueConstIterator() {}
|
ValueConstIterator::ValueConstIterator() {}
|
||||||
|
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ValueConstIterator::ValueConstIterator(
|
ValueConstIterator::ValueConstIterator(
|
||||||
const Value::ObjectValues::iterator& current)
|
const Value::ObjectValues::iterator& current)
|
||||||
: ValueIteratorBase(current) {}
|
: ValueIteratorBase(current) {}
|
||||||
#else
|
|
||||||
ValueConstIterator::ValueConstIterator(
|
|
||||||
const ValueInternalArray::IteratorState& state)
|
|
||||||
: ValueIteratorBase(state) {}
|
|
||||||
|
|
||||||
ValueConstIterator::ValueConstIterator(
|
|
||||||
const ValueInternalMap::IteratorState& state)
|
|
||||||
: ValueIteratorBase(state) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ValueConstIterator& ValueConstIterator::
|
ValueConstIterator& ValueConstIterator::
|
||||||
operator=(const ValueIteratorBase& other) {
|
operator=(const ValueIteratorBase& other) {
|
||||||
@ -216,16 +127,8 @@ operator=(const ValueIteratorBase& other) {
|
|||||||
|
|
||||||
ValueIterator::ValueIterator() {}
|
ValueIterator::ValueIterator() {}
|
||||||
|
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
|
||||||
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
||||||
: ValueIteratorBase(current) {}
|
: ValueIteratorBase(current) {}
|
||||||
#else
|
|
||||||
ValueIterator::ValueIterator(const ValueInternalArray::IteratorState& state)
|
|
||||||
: ValueIteratorBase(state) {}
|
|
||||||
|
|
||||||
ValueIterator::ValueIterator(const ValueInternalMap::IteratorState& state)
|
|
||||||
: ValueIteratorBase(state) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ValueIterator::ValueIterator(const ValueConstIterator& other)
|
ValueIterator::ValueIterator(const ValueConstIterator& other)
|
||||||
: ValueIteratorBase(other) {}
|
: ValueIteratorBase(other) {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user