You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1103 lines
35 KiB
1103 lines
35 KiB
// 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 CPPTL_JSON_H_INCLUDED |
|
# define CPPTL_JSON_H_INCLUDED |
|
|
|
#if !defined(JSON_IS_AMALGAMATION) |
|
# include "forwards.h" |
|
#endif // if !defined(JSON_IS_AMALGAMATION) |
|
# include <string> |
|
# include <vector> |
|
|
|
# ifndef JSON_USE_CPPTL_SMALLMAP |
|
# include <map> |
|
# else |
|
# include <cpptl/smallmap.h> |
|
# endif |
|
# ifdef JSON_USE_CPPTL |
|
# include <cpptl/forwards.h> |
|
# endif |
|
|
|
/** \brief JSON (JavaScript Object Notation). |
|
*/ |
|
namespace Json { |
|
|
|
/** \brief Type of the value held by a Value object. |
|
*/ |
|
enum ValueType |
|
{ |
|
nullValue = 0, ///< 'null' value |
|
intValue, ///< signed integer value |
|
uintValue, ///< unsigned integer value |
|
realValue, ///< double value |
|
stringValue, ///< UTF-8 string value |
|
booleanValue, ///< bool value |
|
arrayValue, ///< array value (ordered list) |
|
objectValue ///< object value (collection of name/value pairs). |
|
}; |
|
|
|
enum CommentPlacement |
|
{ |
|
commentBefore = 0, ///< a comment placed on the line before a value |
|
commentAfterOnSameLine, ///< a comment just after a value on the same line |
|
commentAfter, ///< a comment on the line after a value (only make sense for root value) |
|
numberOfCommentPlacement |
|
}; |
|
|
|
//# ifdef JSON_USE_CPPTL |
|
// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames; |
|
// typedef CppTL::AnyEnumerator<const Value &> EnumValues; |
|
//# endif |
|
|
|
/** \brief Lightweight wrapper to tag static string. |
|
* |
|
* Value constructor and objectValue member assignement takes advantage of the |
|
* StaticString and avoid the cost of string duplication when storing the |
|
* string or the member name. |
|
* |
|
* Example of usage: |
|
* \code |
|
* Json::Value aValue( StaticString("some text") ); |
|
* Json::Value object; |
|
* static const StaticString code("code"); |
|
* object[code] = 1234; |
|
* \endcode |
|
*/ |
|
class JSON_API StaticString |
|
{ |
|
public: |
|
explicit StaticString( const char *czstring ) |
|
: str_( czstring ) |
|
{ |
|
} |
|
|
|
operator const char *() const |
|
{ |
|
return str_; |
|
} |
|
|
|
const char *c_str() const |
|
{ |
|
return str_; |
|
} |
|
|
|
private: |
|
const char *str_; |
|
}; |
|
|
|
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value. |
|
* |
|
* This class is a discriminated union wrapper that can represents a: |
|
* - signed integer [range: Value::minInt - Value::maxInt] |
|
* - unsigned integer (range: 0 - Value::maxUInt) |
|
* - double |
|
* - UTF-8 string |
|
* - boolean |
|
* - 'null' |
|
* - an ordered list of Value |
|
* - collection of name/value pairs (javascript object) |
|
* |
|
* The type of the held value is represented by a #ValueType and |
|
* can be obtained using type(). |
|
* |
|
* values of an #objectValue or #arrayValue can be accessed using operator[]() methods. |
|
* Non const methods will automatically create the a #nullValue element |
|
* if it does not exist. |
|
* The sequence of an #arrayValue will be automatically resize and initialized |
|
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. |
|
* |
|
* The get() methods can be used to obtanis default value in the case the required element |
|
* does not exist. |
|
* |
|
* It is possible to iterate over the list of a #objectValue values using |
|
* the getMemberNames() method. |
|
*/ |
|
class JSON_API Value |
|
{ |
|
friend class ValueIteratorBase; |
|
# ifdef JSON_VALUE_USE_INTERNAL_MAP |
|
friend class ValueInternalLink; |
|
friend class ValueInternalMap; |
|
# endif |
|
public: |
|
typedef std::vector<std::string> Members; |
|
typedef ValueIterator iterator; |
|
typedef ValueConstIterator const_iterator; |
|
typedef Json::UInt UInt; |
|
typedef Json::Int Int; |
|
# if defined(JSON_HAS_INT64) |
|
typedef Json::UInt64 UInt64; |
|
typedef Json::Int64 Int64; |
|
#endif // defined(JSON_HAS_INT64) |
|
typedef Json::LargestInt LargestInt; |
|
typedef Json::LargestUInt LargestUInt; |
|
typedef Json::ArrayIndex ArrayIndex; |
|
|
|
static const Value null; |
|
/// Minimum signed integer value that can be stored in a Json::Value. |
|
static const LargestInt minLargestInt; |
|
/// Maximum signed integer value that can be stored in a Json::Value. |
|
static const LargestInt maxLargestInt; |
|
/// Maximum unsigned integer value that can be stored in a Json::Value. |
|
static const LargestUInt maxLargestUInt; |
|
|
|
/// Minimum signed int value that can be stored in a Json::Value. |
|
static const Int minInt; |
|
/// Maximum signed int value that can be stored in a Json::Value. |
|
static const Int maxInt; |
|
/// Maximum unsigned int value that can be stored in a Json::Value. |
|
static const UInt maxUInt; |
|
|
|
/// Minimum signed 64 bits int value that can be stored in a Json::Value. |
|
static const Int64 minInt64; |
|
/// Maximum signed 64 bits int value that can be stored in a Json::Value. |
|
static const Int64 maxInt64; |
|
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value. |
|
static const UInt64 maxUInt64; |
|
|
|
private: |
|
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION |
|
# ifndef JSON_VALUE_USE_INTERNAL_MAP |
|
class CZString |
|
{ |
|
public: |
|
enum DuplicationPolicy |
|
{ |
|
noDuplication = 0, |
|
duplicate, |
|
duplicateOnCopy |
|
}; |
|
CZString( ArrayIndex index ); |
|
CZString( const char *cstr, DuplicationPolicy allocate ); |
|
CZString( const CZString &other ); |
|
~CZString(); |
|
CZString &operator =( const CZString &other ); |
|
bool operator<( const CZString &other ) const; |
|
bool operator==( const CZString &other ) const; |
|
ArrayIndex index() const; |
|
const char *c_str() const; |
|
bool isStaticString() const; |
|
private: |
|
void swap( CZString &other ); |
|
const char *cstr_; |
|
ArrayIndex index_; |
|
}; |
|
|
|
public: |
|
# ifndef JSON_USE_CPPTL_SMALLMAP |
|
typedef std::map<CZString, Value> ObjectValues; |
|
# else |
|
typedef CppTL::SmallMap<CZString, Value> ObjectValues; |
|
# endif // ifndef JSON_USE_CPPTL_SMALLMAP |
|
# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP |
|
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION |
|
|
|
public: |
|
/** \brief Create a default Value of the given type. |
|
|
|
This is a very useful constructor. |
|
To create an empty array, pass arrayValue. |
|
To create an empty object, pass objectValue. |
|
Another Value can then be set to this one by assignment. |
|
This is useful since clear() and resize() will not alter types. |
|
|
|
Examples: |
|
\code |
|
Json::Value null_value; // null |
|
Json::Value arr_value(Json::arrayValue); // [] |
|
Json::Value obj_value(Json::objectValue); // {} |
|
\endcode |
|
*/ |
|
Value( ValueType type = nullValue ); |
|
Value( Int value ); |
|
Value( UInt value ); |
|
#if defined(JSON_HAS_INT64) |
|
Value( Int64 value ); |
|
Value( UInt64 value ); |
|
#endif // if defined(JSON_HAS_INT64) |
|
Value( double value ); |
|
Value( const char *value ); |
|
Value( const char *beginValue, const char *endValue ); |
|
/** \brief Constructs a value from a static string. |
|
|
|
* Like other value string constructor but do not duplicate the string for |
|
* internal storage. The given string must remain alive after the call to this |
|
* constructor. |
|
* Example of usage: |
|
* \code |
|
* Json::Value aValue( StaticString("some text") ); |
|
* \endcode |
|
*/ |
|
Value( const StaticString &value ); |
|
Value( const std::string &value ); |
|
# ifdef JSON_USE_CPPTL |
|
Value( const CppTL::ConstString &value ); |
|
# endif |
|
Value( bool value ); |
|
Value( const Value &other ); |
|
~Value(); |
|
|
|
Value &operator=( const Value &other ); |
|
/// Swap values. |
|
/// \note Currently, comments are intentionally not swapped, for |
|
/// both logic and efficiency. |
|
void swap( Value &other ); |
|
|
|
ValueType type() const; |
|
|
|
bool operator <( const Value &other ) const; |
|
bool operator <=( const Value &other ) const; |
|
bool operator >=( const Value &other ) const; |
|
bool operator >( const Value &other ) const; |
|
|
|
bool operator ==( const Value &other ) const; |
|
bool operator !=( const Value &other ) const; |
|
|
|
int compare( const Value &other ) const; |
|
|
|
const char *asCString() const; |
|
std::string asString() const; |
|
# ifdef JSON_USE_CPPTL |
|
CppTL::ConstString asConstString() const; |
|
# endif |
|
Int asInt() const; |
|
UInt asUInt() const; |
|
Int64 asInt64() const; |
|
UInt64 asUInt64() const; |
|
LargestInt asLargestInt() const; |
|
LargestUInt asLargestUInt() const; |
|
float asFloat() const; |
|
double asDouble() const; |
|
bool asBool() const; |
|
|
|
bool isNull() const; |
|
bool isBool() const; |
|
bool isInt() const; |
|
bool isUInt() const; |
|
bool isIntegral() const; |
|
bool isDouble() const; |
|
bool isNumeric() const; |
|
bool isString() const; |
|
bool isArray() const; |
|
bool isObject() const; |
|
|
|
bool isConvertibleTo( ValueType other ) const; |
|
|
|
/// Number of values in array or object |
|
ArrayIndex size() const; |
|
|
|
/// \brief Return true if empty array, empty object, or null; |
|
/// otherwise, false. |
|
bool empty() const; |
|
|
|
/// Return isNull() |
|
bool operator!() const; |
|
|
|
/// Remove all object members and array elements. |
|
/// \pre type() is arrayValue, objectValue, or nullValue |
|
/// \post type() is unchanged |
|
void clear(); |
|
|
|
/// Resize the array to size elements. |
|
/// New elements are initialized to null. |
|
/// May only be called on nullValue or arrayValue. |
|
/// \pre type() is arrayValue or nullValue |
|
/// \post type() is arrayValue |
|
void resize( ArrayIndex size ); |
|
|
|
/// Access an array element (zero based index ). |
|
/// If the array contains less than index element, then null value are inserted |
|
/// in the array so that its size is index+1. |
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish |
|
/// this from the operator[] which takes a string.) |
|
Value &operator[]( ArrayIndex index ); |
|
|
|
/// Access an array element (zero based index ). |
|
/// If the array contains less than index element, then null value are inserted |
|
/// in the array so that its size is index+1. |
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish |
|
/// this from the operator[] which takes a string.) |
|
Value &operator[]( int index ); |
|
|
|
/// Access an array element (zero based index ) |
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish |
|
/// this from the operator[] which takes a string.) |
|
const Value &operator[]( ArrayIndex index ) const; |
|
|
|
/// Access an array element (zero based index ) |
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish |
|
/// this from the operator[] which takes a string.) |
|
const Value &operator[]( int index ) const; |
|
|
|
/// If the array contains at least index+1 elements, returns the element value, |
|
/// otherwise returns defaultValue. |
|
Value get( ArrayIndex index, |
|
const Value &defaultValue ) const; |
|
/// Return true if index < size(). |
|
bool isValidIndex( ArrayIndex index ) const; |
|
/// \brief Append value to array at the end. |
|
/// |
|
/// Equivalent to jsonvalue[jsonvalue.size()] = value; |
|
Value &append( const Value &value ); |
|
|
|
/// Access an object value by name, create a null member if it does not exist. |
|
Value &operator[]( const char *key ); |
|
/// Access an object value by name, returns null if there is no member with that name. |
|
const Value &operator[]( const char *key ) const; |
|
/// Access an object value by name, create a null member if it does not exist. |
|
Value &operator[]( const std::string &key ); |
|
/// Access an object value by name, returns null if there is no member with that name. |
|
const Value &operator[]( const std::string &key ) const; |
|
/** \brief Access an object value by name, create a null member if it does not exist. |
|
|
|
* If the object as no entry for that name, then the member name used to store |
|
* the new entry is not duplicated. |
|
* Example of use: |
|
* \code |
|
* Json::Value object; |
|
* static const StaticString code("code"); |
|
* object[code] = 1234; |
|
* \endcode |
|
*/ |
|
Value &operator[]( const StaticString &key ); |
|
# ifdef JSON_USE_CPPTL |
|
/// Access an object value by name, create a null member if it does not exist. |
|
Value &operator[]( const CppTL::ConstString &key ); |
|
/// Access an object value by name, returns null if there is no member with that name. |
|
const Value &operator[]( const CppTL::ConstString &key ) const; |
|
# endif |
|
/// Return the member named key if it exist, defaultValue otherwise. |
|
Value get( const char *key, |
|
const Value &defaultValue ) const; |
|
/// Return the member named key if it exist, defaultValue otherwise. |
|
Value get( const std::string &key, |
|
const Value &defaultValue ) const; |
|
# ifdef JSON_USE_CPPTL |
|
/// Return the member named key if it exist, defaultValue otherwise. |
|
Value get( const CppTL::ConstString &key, |
|
const Value &defaultValue ) const; |
|
# endif |
|
/// \brief Remove and return the named member. |
|
/// |
|
/// Do nothing if it did not exist. |
|
/// \return the removed Value, or null. |
|
/// \pre type() is objectValue or nullValue |
|
/// \post type() is unchanged |
|
Value removeMember( const char* key ); |
|
/// Same as removeMember(const char*) |
|
Value removeMember( const std::string &key ); |
|
|
|
/// Return true if the object has a member named key. |
|
bool isMember( const char *key ) const; |
|
/// Return true if the object has a member named key. |
|
bool isMember( const std::string &key ) const; |
|
# ifdef JSON_USE_CPPTL |
|
/// Return true if the object has a member named key. |
|
bool isMember( const CppTL::ConstString &key ) const; |
|
# endif |
|
|
|
/// \brief Return a list of the member names. |
|
/// |
|
/// If null, return an empty list. |
|
/// \pre type() is objectValue or nullValue |
|
/// \post if type() was nullValue, it remains nullValue |
|
Members getMemberNames() const; |
|
|
|
//# ifdef JSON_USE_CPPTL |
|
// EnumMemberNames enumMemberNames() const; |
|
// EnumValues enumValues() const; |
|
//# endif |
|
|
|
/// Comments must be //... or /* ... */ |
|
void setComment( const char *comment, |
|
CommentPlacement placement ); |
|
/// Comments must be //... or /* ... */ |
|
void setComment( const std::string &comment, |
|
CommentPlacement placement ); |
|
bool hasComment( CommentPlacement placement ) const; |
|
/// Include delimiters and embedded newlines. |
|
std::string getComment( CommentPlacement placement ) const; |
|
|
|
std::string toStyledString() const; |
|
|
|
const_iterator begin() const; |
|
const_iterator end() const; |
|
|
|
iterator begin(); |
|
iterator end(); |
|
|
|
private: |
|
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 |
|
{ |
|
CommentInfo(); |
|
~CommentInfo(); |
|
|
|
void setComment( const char *text ); |
|
|
|
char *comment_; |
|
}; |
|
|
|
//struct MemberNamesTransform |
|
//{ |
|
// typedef const char *result_type; |
|
// const char *operator()( const CZString &name ) const |
|
// { |
|
// return name.c_str(); |
|
// } |
|
//}; |
|
|
|
union ValueHolder |
|
{ |
|
LargestInt int_; |
|
LargestUInt uint_; |
|
double real_; |
|
bool bool_; |
|
char *string_; |
|
# ifdef JSON_VALUE_USE_INTERNAL_MAP |
|
ValueInternalArray *array_; |
|
ValueInternalMap *map_; |
|
#else |
|
ObjectValues *map_; |
|
# endif |
|
} value_; |
|
ValueType type_ : 8; |
|
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. |
|
int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. |
|
# endif |
|
CommentInfo *comments_; |
|
}; |
|
|
|
|
|
/** \brief Experimental and untested: represents an element of the "path" to access a node. |
|
*/ |
|
class PathArgument |
|
{ |
|
public: |
|
friend class Path; |
|
|
|
PathArgument(); |
|
PathArgument( ArrayIndex index ); |
|
PathArgument( const char *key ); |
|
PathArgument( const std::string &key ); |
|
|
|
private: |
|
enum Kind |
|
{ |
|
kindNone = 0, |
|
kindIndex, |
|
kindKey |
|
}; |
|
std::string key_; |
|
ArrayIndex index_; |
|
Kind kind_; |
|
}; |
|
|
|
/** \brief Experimental and untested: represents a "path" to access a node. |
|
* |
|
* Syntax: |
|
* - "." => root node |
|
* - ".[n]" => elements at index 'n' of root node (an array value) |
|
* - ".name" => member named 'name' of root node (an object value) |
|
* - ".name1.name2.name3" |
|
* - ".[0][1][2].name1[3]" |
|
* - ".%" => member name is provided as parameter |
|
* - ".[%]" => index is provied as parameter |
|
*/ |
|
class Path |
|
{ |
|
public: |
|
Path( const std::string &path, |
|
const PathArgument &a1 = PathArgument(), |
|
const PathArgument &a2 = PathArgument(), |
|
const PathArgument &a3 = PathArgument(), |
|
const PathArgument &a4 = PathArgument(), |
|
const PathArgument &a5 = PathArgument() ); |
|
|
|
const Value &resolve( const Value &root ) const; |
|
Value resolve( const Value &root, |
|
const Value &defaultValue ) const; |
|
/// Creates the "path" to access the specified node and returns a reference on the node. |
|
Value &make( Value &root ) const; |
|
|
|
private: |
|
typedef std::vector<const PathArgument *> InArgs; |
|
typedef std::vector<PathArgument> Args; |
|
|
|
void makePath( const std::string &path, |
|
const InArgs &in ); |
|
void addPathInArg( const std::string &path, |
|
const InArgs &in, |
|
InArgs::const_iterator &itInArg, |
|
PathArgument::Kind kind ); |
|
void invalidPath( const std::string &path, |
|
int location ); |
|
|
|
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 =( const 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 =( const 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. |
|
* |
|
*/ |
|
class ValueIteratorBase |
|
{ |
|
public: |
|
typedef unsigned int size_t; |
|
typedef int difference_type; |
|
typedef ValueIteratorBase SelfType; |
|
|
|
ValueIteratorBase(); |
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP |
|
explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); |
|
#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 ); |
|
} |
|
|
|
difference_type operator -( const SelfType &other ) const |
|
{ |
|
return computeDistance( other ); |
|
} |
|
|
|
/// Return either the index or the member name of the referenced value as a Value. |
|
Value key() const; |
|
|
|
/// Return the index of the referenced Value. -1 if it is not an arrayValue. |
|
UInt index() const; |
|
|
|
/// Return the member name of the referenced Value. "" if it is not an objectValue. |
|
const char *memberName() const; |
|
|
|
protected: |
|
Value &deref() const; |
|
|
|
void increment(); |
|
|
|
void decrement(); |
|
|
|
difference_type computeDistance( const SelfType &other ) const; |
|
|
|
bool isEqual( const SelfType &other ) const; |
|
|
|
void copy( const SelfType &other ); |
|
|
|
private: |
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP |
|
Value::ObjectValues::iterator current_; |
|
// Indicates that iterator is for a null value. |
|
bool isNull_; |
|
#else |
|
union |
|
{ |
|
ValueInternalArray::IteratorState array_; |
|
ValueInternalMap::IteratorState map_; |
|
} iterator_; |
|
bool isArray_; |
|
#endif |
|
}; |
|
|
|
/** \brief const iterator for object and array value. |
|
* |
|
*/ |
|
class ValueConstIterator : public ValueIteratorBase |
|
{ |
|
friend class Value; |
|
public: |
|
typedef unsigned int size_t; |
|
typedef int difference_type; |
|
typedef const Value &reference; |
|
typedef const Value *pointer; |
|
typedef ValueConstIterator SelfType; |
|
|
|
ValueConstIterator(); |
|
private: |
|
/*! \internal Use by Value to create an iterator. |
|
*/ |
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP |
|
explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); |
|
#else |
|
ValueConstIterator( const ValueInternalArray::IteratorState &state ); |
|
ValueConstIterator( const ValueInternalMap::IteratorState &state ); |
|
#endif |
|
public: |
|
SelfType &operator =( const ValueIteratorBase &other ); |
|
|
|
SelfType operator++( int ) |
|
{ |
|
SelfType temp( *this ); |
|
++*this; |
|
return temp; |
|
} |
|
|
|
SelfType operator--( int ) |
|
{ |
|
SelfType temp( *this ); |
|
--*this; |
|
return temp; |
|
} |
|
|
|
SelfType &operator--() |
|
{ |
|
decrement(); |
|
return *this; |
|
} |
|
|
|
SelfType &operator++() |
|
{ |
|
increment(); |
|
return *this; |
|
} |
|
|
|
reference operator *() const |
|
{ |
|
return deref(); |
|
} |
|
}; |
|
|
|
|
|
/** \brief Iterator for object and array value. |
|
*/ |
|
class ValueIterator : public ValueIteratorBase |
|
{ |
|
friend class Value; |
|
public: |
|
typedef unsigned int size_t; |
|
typedef int difference_type; |
|
typedef Value &reference; |
|
typedef Value *pointer; |
|
typedef ValueIterator SelfType; |
|
|
|
ValueIterator(); |
|
ValueIterator( const ValueConstIterator &other ); |
|
ValueIterator( const ValueIterator &other ); |
|
private: |
|
/*! \internal Use by Value to create an iterator. |
|
*/ |
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP |
|
explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); |
|
#else |
|
ValueIterator( const ValueInternalArray::IteratorState &state ); |
|
ValueIterator( const ValueInternalMap::IteratorState &state ); |
|
#endif |
|
public: |
|
|
|
SelfType &operator =( const SelfType &other ); |
|
|
|
SelfType operator++( int ) |
|
{ |
|
SelfType temp( *this ); |
|
++*this; |
|
return temp; |
|
} |
|
|
|
SelfType operator--( int ) |
|
{ |
|
SelfType temp( *this ); |
|
--*this; |
|
return temp; |
|
} |
|
|
|
SelfType &operator--() |
|
{ |
|
decrement(); |
|
return *this; |
|
} |
|
|
|
SelfType &operator++() |
|
{ |
|
increment(); |
|
return *this; |
|
} |
|
|
|
reference operator *() const |
|
{ |
|
return deref(); |
|
} |
|
}; |
|
|
|
|
|
} // namespace Json |
|
|
|
|
|
#endif // CPPTL_JSON_H_INCLUDED
|
|
|