ian@0: // Copyright 2007-2010 Baptiste Lepilleur ian@0: // Distributed under MIT license, or public domain if desired and ian@0: // recognized in your jurisdiction. ian@0: // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE ian@0: ian@0: #ifndef CPPTL_JSON_H_INCLUDED ian@0: # define CPPTL_JSON_H_INCLUDED ian@0: ian@0: #if !defined(JSON_IS_AMALGAMATION) ian@0: # include "forwards.h" ian@0: #endif // if !defined(JSON_IS_AMALGAMATION) ian@0: # include ian@0: # include ian@0: ian@0: # ifndef JSON_USE_CPPTL_SMALLMAP ian@0: # include ian@0: # else ian@0: # include ian@0: # endif ian@0: # ifdef JSON_USE_CPPTL ian@0: # include ian@0: # endif ian@0: ian@0: /** \brief JSON (JavaScript Object Notation). ian@0: */ ian@0: namespace Json { ian@0: ian@0: /** \brief Type of the value held by a Value object. ian@0: */ ian@0: enum ValueType ian@0: { ian@0: nullValue = 0, ///< 'null' value ian@0: intValue, ///< signed integer value ian@0: uintValue, ///< unsigned integer value ian@0: realValue, ///< double value ian@0: stringValue, ///< UTF-8 string value ian@0: booleanValue, ///< bool value ian@0: arrayValue, ///< array value (ordered list) ian@0: objectValue ///< object value (collection of name/value pairs). ian@0: }; ian@0: ian@0: enum CommentPlacement ian@0: { ian@0: commentBefore = 0, ///< a comment placed on the line before a value ian@0: commentAfterOnSameLine, ///< a comment just after a value on the same line ian@0: commentAfter, ///< a comment on the line after a value (only make sense for root value) ian@0: numberOfCommentPlacement ian@0: }; ian@0: ian@0: //# ifdef JSON_USE_CPPTL ian@0: // typedef CppTL::AnyEnumerator EnumMemberNames; ian@0: // typedef CppTL::AnyEnumerator EnumValues; ian@0: //# endif ian@0: ian@0: /** \brief Lightweight wrapper to tag static string. ian@0: * ian@0: * Value constructor and objectValue member assignement takes advantage of the ian@0: * StaticString and avoid the cost of string duplication when storing the ian@0: * string or the member name. ian@0: * ian@0: * Example of usage: ian@0: * \code ian@0: * Json::Value aValue( StaticString("some text") ); ian@0: * Json::Value object; ian@0: * static const StaticString code("code"); ian@0: * object[code] = 1234; ian@0: * \endcode ian@0: */ ian@0: class JSON_API StaticString ian@0: { ian@0: public: ian@0: explicit StaticString( const char *czstring ) ian@0: : str_( czstring ) ian@0: { ian@0: } ian@0: ian@0: operator const char *() const ian@0: { ian@0: return str_; ian@0: } ian@0: ian@0: const char *c_str() const ian@0: { ian@0: return str_; ian@0: } ian@0: ian@0: private: ian@0: const char *str_; ian@0: }; ian@0: ian@0: /** \brief Represents a JSON value. ian@0: * ian@0: * This class is a discriminated union wrapper that can represents a: ian@0: * - signed integer [range: Value::minInt - Value::maxInt] ian@0: * - unsigned integer (range: 0 - Value::maxUInt) ian@0: * - double ian@0: * - UTF-8 string ian@0: * - boolean ian@0: * - 'null' ian@0: * - an ordered list of Value ian@0: * - collection of name/value pairs (javascript object) ian@0: * ian@0: * The type of the held value is represented by a #ValueType and ian@0: * can be obtained using type(). ian@0: * ian@0: * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. ian@0: * Non const methods will automatically create the a #nullValue element ian@0: * if it does not exist. ian@0: * The sequence of an #arrayValue will be automatically resize and initialized ian@0: * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. ian@0: * ian@0: * The get() methods can be used to obtanis default value in the case the required element ian@0: * does not exist. ian@0: * ian@0: * It is possible to iterate over the list of a #objectValue values using ian@0: * the getMemberNames() method. ian@0: */ ian@0: class JSON_API Value ian@0: { ian@0: friend class ValueIteratorBase; ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: friend class ValueInternalLink; ian@0: friend class ValueInternalMap; ian@0: # endif ian@0: public: ian@0: typedef std::vector Members; ian@0: typedef ValueIterator iterator; ian@0: typedef ValueConstIterator const_iterator; ian@0: typedef Json::UInt UInt; ian@0: typedef Json::Int Int; ian@0: # if defined(JSON_HAS_INT64) ian@0: typedef Json::UInt64 UInt64; ian@0: typedef Json::Int64 Int64; ian@0: #endif // defined(JSON_HAS_INT64) ian@0: typedef Json::LargestInt LargestInt; ian@0: typedef Json::LargestUInt LargestUInt; ian@0: typedef Json::ArrayIndex ArrayIndex; ian@0: ian@0: static const Value null; ian@0: /// Minimum signed integer value that can be stored in a Json::Value. ian@0: static const LargestInt minLargestInt; ian@0: /// Maximum signed integer value that can be stored in a Json::Value. ian@0: static const LargestInt maxLargestInt; ian@0: /// Maximum unsigned integer value that can be stored in a Json::Value. ian@0: static const LargestUInt maxLargestUInt; ian@0: ian@0: /// Minimum signed int value that can be stored in a Json::Value. ian@0: static const Int minInt; ian@0: /// Maximum signed int value that can be stored in a Json::Value. ian@0: static const Int maxInt; ian@0: /// Maximum unsigned int value that can be stored in a Json::Value. ian@0: static const UInt maxUInt; ian@0: ian@0: # if defined(JSON_HAS_INT64) ian@0: /// Minimum signed 64 bits int value that can be stored in a Json::Value. ian@0: static const Int64 minInt64; ian@0: /// Maximum signed 64 bits int value that can be stored in a Json::Value. ian@0: static const Int64 maxInt64; ian@0: /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. ian@0: static const UInt64 maxUInt64; ian@0: #endif // defined(JSON_HAS_INT64) ian@0: ian@0: private: ian@0: #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ian@0: # ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: class CZString ian@0: { ian@0: public: ian@0: enum DuplicationPolicy ian@0: { ian@0: noDuplication = 0, ian@0: duplicate, ian@0: duplicateOnCopy ian@0: }; ian@0: CZString( ArrayIndex index ); ian@0: CZString( const char *cstr, DuplicationPolicy allocate ); ian@0: CZString( const CZString &other ); ian@0: ~CZString(); ian@0: CZString &operator =( const CZString &other ); ian@0: bool operator<( const CZString &other ) const; ian@0: bool operator==( const CZString &other ) const; ian@0: ArrayIndex index() const; ian@0: const char *c_str() const; ian@0: bool isStaticString() const; ian@0: private: ian@0: void swap( CZString &other ); ian@0: const char *cstr_; ian@0: ArrayIndex index_; ian@0: }; ian@0: ian@0: public: ian@0: # ifndef JSON_USE_CPPTL_SMALLMAP ian@0: typedef std::map ObjectValues; ian@0: # else ian@0: typedef CppTL::SmallMap ObjectValues; ian@0: # endif // ifndef JSON_USE_CPPTL_SMALLMAP ian@0: # endif // ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ian@0: ian@0: public: ian@0: /** \brief Create a default Value of the given type. ian@0: ian@0: This is a very useful constructor. ian@0: To create an empty array, pass arrayValue. ian@0: To create an empty object, pass objectValue. ian@0: Another Value can then be set to this one by assignment. ian@0: This is useful since clear() and resize() will not alter types. ian@0: ian@0: Examples: ian@0: \code ian@0: Json::Value null_value; // null ian@0: Json::Value arr_value(Json::arrayValue); // [] ian@0: Json::Value obj_value(Json::objectValue); // {} ian@0: \endcode ian@0: */ ian@0: Value( ValueType type = nullValue ); ian@0: Value( Int value ); ian@0: Value( UInt value ); ian@0: #if defined(JSON_HAS_INT64) ian@0: Value( Int64 value ); ian@0: Value( UInt64 value ); ian@0: #endif // if defined(JSON_HAS_INT64) ian@0: Value( double value ); ian@0: Value( const char *value ); ian@0: Value( const char *beginValue, const char *endValue ); ian@0: /** \brief Constructs a value from a static string. ian@0: ian@0: * Like other value string constructor but do not duplicate the string for ian@0: * internal storage. The given string must remain alive after the call to this ian@0: * constructor. ian@0: * Example of usage: ian@0: * \code ian@0: * Json::Value aValue( StaticString("some text") ); ian@0: * \endcode ian@0: */ ian@0: Value( const StaticString &value ); ian@0: Value( const std::string &value ); ian@0: # ifdef JSON_USE_CPPTL ian@0: Value( const CppTL::ConstString &value ); ian@0: # endif ian@0: Value( bool value ); ian@0: Value( const Value &other ); ian@0: ~Value(); ian@0: ian@0: Value &operator=( const Value &other ); ian@0: /// Swap values. ian@0: /// \note Currently, comments are intentionally not swapped, for ian@0: /// both logic and efficiency. ian@0: void swap( Value &other ); ian@0: ian@0: ValueType type() const; ian@0: ian@0: bool operator <( const Value &other ) const; ian@0: bool operator <=( const Value &other ) const; ian@0: bool operator >=( const Value &other ) const; ian@0: bool operator >( const Value &other ) const; ian@0: ian@0: bool operator ==( const Value &other ) const; ian@0: bool operator !=( const Value &other ) const; ian@0: ian@0: int compare( const Value &other ) const; ian@0: ian@0: const char *asCString() const; ian@0: std::string asString() const; ian@0: # ifdef JSON_USE_CPPTL ian@0: CppTL::ConstString asConstString() const; ian@0: # endif ian@0: Int asInt() const; ian@0: UInt asUInt() const; ian@0: #if defined(JSON_HAS_INT64) ian@0: Int64 asInt64() const; ian@0: UInt64 asUInt64() const; ian@0: #endif // if defined(JSON_HAS_INT64) ian@0: LargestInt asLargestInt() const; ian@0: LargestUInt asLargestUInt() const; ian@0: float asFloat() const; ian@0: double asDouble() const; ian@0: bool asBool() const; ian@0: ian@0: bool isNull() const; ian@0: bool isBool() const; ian@0: bool isInt() const; ian@0: bool isInt64() const; ian@0: bool isUInt() const; ian@0: bool isUInt64() const; ian@0: bool isIntegral() const; ian@0: bool isDouble() const; ian@0: bool isNumeric() const; ian@0: bool isString() const; ian@0: bool isArray() const; ian@0: bool isObject() const; ian@0: ian@0: bool isConvertibleTo( ValueType other ) const; ian@0: ian@0: /// Number of values in array or object ian@0: ArrayIndex size() const; ian@0: ian@0: /// \brief Return true if empty array, empty object, or null; ian@0: /// otherwise, false. ian@0: bool empty() const; ian@0: ian@0: /// Return isNull() ian@0: bool operator!() const; ian@0: ian@0: /// Remove all object members and array elements. ian@0: /// \pre type() is arrayValue, objectValue, or nullValue ian@0: /// \post type() is unchanged ian@0: void clear(); ian@0: ian@0: /// Resize the array to size elements. ian@0: /// New elements are initialized to null. ian@0: /// May only be called on nullValue or arrayValue. ian@0: /// \pre type() is arrayValue or nullValue ian@0: /// \post type() is arrayValue ian@0: void resize( ArrayIndex size ); ian@0: ian@0: /// Access an array element (zero based index ). ian@0: /// If the array contains less than index element, then null value are inserted ian@0: /// in the array so that its size is index+1. ian@0: /// (You may need to say 'value[0u]' to get your compiler to distinguish ian@0: /// this from the operator[] which takes a string.) ian@0: Value &operator[]( ArrayIndex index ); ian@0: ian@0: /// Access an array element (zero based index ). ian@0: /// If the array contains less than index element, then null value are inserted ian@0: /// in the array so that its size is index+1. ian@0: /// (You may need to say 'value[0u]' to get your compiler to distinguish ian@0: /// this from the operator[] which takes a string.) ian@0: Value &operator[]( int index ); ian@0: ian@0: /// Access an array element (zero based index ) ian@0: /// (You may need to say 'value[0u]' to get your compiler to distinguish ian@0: /// this from the operator[] which takes a string.) ian@0: const Value &operator[]( ArrayIndex index ) const; ian@0: ian@0: /// Access an array element (zero based index ) ian@0: /// (You may need to say 'value[0u]' to get your compiler to distinguish ian@0: /// this from the operator[] which takes a string.) ian@0: const Value &operator[]( int index ) const; ian@0: ian@0: /// If the array contains at least index+1 elements, returns the element value, ian@0: /// otherwise returns defaultValue. ian@0: Value get( ArrayIndex index, ian@0: const Value &defaultValue ) const; ian@0: /// Return true if index < size(). ian@0: bool isValidIndex( ArrayIndex index ) const; ian@0: /// \brief Append value to array at the end. ian@0: /// ian@0: /// Equivalent to jsonvalue[jsonvalue.size()] = value; ian@0: Value &append( const Value &value ); ian@0: ian@0: /// Access an object value by name, create a null member if it does not exist. ian@0: Value &operator[]( const char *key ); ian@0: /// Access an object value by name, returns null if there is no member with that name. ian@0: const Value &operator[]( const char *key ) const; ian@0: /// Access an object value by name, create a null member if it does not exist. ian@0: Value &operator[]( const std::string &key ); ian@0: /// Access an object value by name, returns null if there is no member with that name. ian@0: const Value &operator[]( const std::string &key ) const; ian@0: /** \brief Access an object value by name, create a null member if it does not exist. ian@0: ian@0: * If the object as no entry for that name, then the member name used to store ian@0: * the new entry is not duplicated. ian@0: * Example of use: ian@0: * \code ian@0: * Json::Value object; ian@0: * static const StaticString code("code"); ian@0: * object[code] = 1234; ian@0: * \endcode ian@0: */ ian@0: Value &operator[]( const StaticString &key ); ian@0: # ifdef JSON_USE_CPPTL ian@0: /// Access an object value by name, create a null member if it does not exist. ian@0: Value &operator[]( const CppTL::ConstString &key ); ian@0: /// Access an object value by name, returns null if there is no member with that name. ian@0: const Value &operator[]( const CppTL::ConstString &key ) const; ian@0: # endif ian@0: /// Return the member named key if it exist, defaultValue otherwise. ian@0: Value get( const char *key, ian@0: const Value &defaultValue ) const; ian@0: /// Return the member named key if it exist, defaultValue otherwise. ian@0: Value get( const std::string &key, ian@0: const Value &defaultValue ) const; ian@0: # ifdef JSON_USE_CPPTL ian@0: /// Return the member named key if it exist, defaultValue otherwise. ian@0: Value get( const CppTL::ConstString &key, ian@0: const Value &defaultValue ) const; ian@0: # endif ian@0: /// \brief Remove and return the named member. ian@0: /// ian@0: /// Do nothing if it did not exist. ian@0: /// \return the removed Value, or null. ian@0: /// \pre type() is objectValue or nullValue ian@0: /// \post type() is unchanged ian@0: Value removeMember( const char* key ); ian@0: /// Same as removeMember(const char*) ian@0: Value removeMember( const std::string &key ); ian@0: ian@0: /// Return true if the object has a member named key. ian@0: bool isMember( const char *key ) const; ian@0: /// Return true if the object has a member named key. ian@0: bool isMember( const std::string &key ) const; ian@0: # ifdef JSON_USE_CPPTL ian@0: /// Return true if the object has a member named key. ian@0: bool isMember( const CppTL::ConstString &key ) const; ian@0: # endif ian@0: ian@0: /// \brief Return a list of the member names. ian@0: /// ian@0: /// If null, return an empty list. ian@0: /// \pre type() is objectValue or nullValue ian@0: /// \post if type() was nullValue, it remains nullValue ian@0: Members getMemberNames() const; ian@0: ian@0: //# ifdef JSON_USE_CPPTL ian@0: // EnumMemberNames enumMemberNames() const; ian@0: // EnumValues enumValues() const; ian@0: //# endif ian@0: ian@0: /// Comments must be //... or /* ... */ ian@0: void setComment( const char *comment, ian@0: CommentPlacement placement ); ian@0: /// Comments must be //... or /* ... */ ian@0: void setComment( const std::string &comment, ian@0: CommentPlacement placement ); ian@0: bool hasComment( CommentPlacement placement ) const; ian@0: /// Include delimiters and embedded newlines. ian@0: std::string getComment( CommentPlacement placement ) const; ian@0: ian@0: std::string toStyledString() const; ian@0: ian@0: const_iterator begin() const; ian@0: const_iterator end() const; ian@0: ian@0: iterator begin(); ian@0: iterator end(); ian@0: ian@0: private: ian@0: Value &resolveReference( const char *key, ian@0: bool isStatic ); ian@0: ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: inline bool isItemAvailable() const ian@0: { ian@0: return itemIsUsed_ == 0; ian@0: } ian@0: ian@0: inline void setItemUsed( bool isUsed = true ) ian@0: { ian@0: itemIsUsed_ = isUsed ? 1 : 0; ian@0: } ian@0: ian@0: inline bool isMemberNameStatic() const ian@0: { ian@0: return memberNameIsStatic_ == 0; ian@0: } ian@0: ian@0: inline void setMemberNameIsStatic( bool isStatic ) ian@0: { ian@0: memberNameIsStatic_ = isStatic ? 1 : 0; ian@0: } ian@0: # endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: ian@0: private: ian@0: struct CommentInfo ian@0: { ian@0: CommentInfo(); ian@0: ~CommentInfo(); ian@0: ian@0: void setComment( const char *text ); ian@0: ian@0: char *comment_; ian@0: }; ian@0: ian@0: //struct MemberNamesTransform ian@0: //{ ian@0: // typedef const char *result_type; ian@0: // const char *operator()( const CZString &name ) const ian@0: // { ian@0: // return name.c_str(); ian@0: // } ian@0: //}; ian@0: ian@0: union ValueHolder ian@0: { ian@0: LargestInt int_; ian@0: LargestUInt uint_; ian@0: double real_; ian@0: bool bool_; ian@0: char *string_; ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: ValueInternalArray *array_; ian@0: ValueInternalMap *map_; ian@0: #else ian@0: ObjectValues *map_; ian@0: # endif ian@0: } value_; ian@0: ValueType type_ : 8; ian@0: int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. ian@0: # ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. ian@0: int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. ian@0: # endif ian@0: CommentInfo *comments_; ian@0: }; ian@0: ian@0: ian@0: /** \brief Experimental and untested: represents an element of the "path" to access a node. ian@0: */ ian@0: class PathArgument ian@0: { ian@0: public: ian@0: friend class Path; ian@0: ian@0: PathArgument(); ian@0: PathArgument( ArrayIndex index ); ian@0: PathArgument( const char *key ); ian@0: PathArgument( const std::string &key ); ian@0: ian@0: private: ian@0: enum Kind ian@0: { ian@0: kindNone = 0, ian@0: kindIndex, ian@0: kindKey ian@0: }; ian@0: std::string key_; ian@0: ArrayIndex index_; ian@0: Kind kind_; ian@0: }; ian@0: ian@0: /** \brief Experimental and untested: represents a "path" to access a node. ian@0: * ian@0: * Syntax: ian@0: * - "." => root node ian@0: * - ".[n]" => elements at index 'n' of root node (an array value) ian@0: * - ".name" => member named 'name' of root node (an object value) ian@0: * - ".name1.name2.name3" ian@0: * - ".[0][1][2].name1[3]" ian@0: * - ".%" => member name is provided as parameter ian@0: * - ".[%]" => index is provied as parameter ian@0: */ ian@0: class Path ian@0: { ian@0: public: ian@0: Path( const std::string &path, ian@0: const PathArgument &a1 = PathArgument(), ian@0: const PathArgument &a2 = PathArgument(), ian@0: const PathArgument &a3 = PathArgument(), ian@0: const PathArgument &a4 = PathArgument(), ian@0: const PathArgument &a5 = PathArgument() ); ian@0: ian@0: const Value &resolve( const Value &root ) const; ian@0: Value resolve( const Value &root, ian@0: const Value &defaultValue ) const; ian@0: /// Creates the "path" to access the specified node and returns a reference on the node. ian@0: Value &make( Value &root ) const; ian@0: ian@0: private: ian@0: typedef std::vector InArgs; ian@0: typedef std::vector Args; ian@0: ian@0: void makePath( const std::string &path, ian@0: const InArgs &in ); ian@0: void addPathInArg( const std::string &path, ian@0: const InArgs &in, ian@0: InArgs::const_iterator &itInArg, ian@0: PathArgument::Kind kind ); ian@0: void invalidPath( const std::string &path, ian@0: int location ); ian@0: ian@0: Args args_; ian@0: }; ian@0: ian@0: ian@0: ian@0: #ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: /** \brief Allocator to customize Value internal map. ian@0: * Below is an example of a simple implementation (default implementation actually ian@0: * use memory pool for speed). ian@0: * \code ian@0: class DefaultValueMapAllocator : public ValueMapAllocator ian@0: { ian@0: public: // overridden from ValueMapAllocator ian@0: virtual ValueInternalMap *newMap() ian@0: { ian@0: return new ValueInternalMap(); ian@0: } ian@0: ian@0: virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) ian@0: { ian@0: return new ValueInternalMap( other ); ian@0: } ian@0: ian@0: virtual void destructMap( ValueInternalMap *map ) ian@0: { ian@0: delete map; ian@0: } ian@0: ian@0: virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) ian@0: { ian@0: return new ValueInternalLink[size]; ian@0: } ian@0: ian@0: virtual void releaseMapBuckets( ValueInternalLink *links ) ian@0: { ian@0: delete [] links; ian@0: } ian@0: ian@0: virtual ValueInternalLink *allocateMapLink() ian@0: { ian@0: return new ValueInternalLink(); ian@0: } ian@0: ian@0: virtual void releaseMapLink( ValueInternalLink *link ) ian@0: { ian@0: delete link; ian@0: } ian@0: }; ian@0: * \endcode ian@0: */ ian@0: class JSON_API ValueMapAllocator ian@0: { ian@0: public: ian@0: virtual ~ValueMapAllocator(); ian@0: virtual ValueInternalMap *newMap() = 0; ian@0: virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; ian@0: virtual void destructMap( ValueInternalMap *map ) = 0; ian@0: virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; ian@0: virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; ian@0: virtual ValueInternalLink *allocateMapLink() = 0; ian@0: virtual void releaseMapLink( ValueInternalLink *link ) = 0; ian@0: }; ian@0: ian@0: /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). ian@0: * \internal previous_ & next_ allows for bidirectional traversal. ian@0: */ ian@0: class JSON_API ValueInternalLink ian@0: { ian@0: public: ian@0: enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. ian@0: enum InternalFlags { ian@0: flagAvailable = 0, ian@0: flagUsed = 1 ian@0: }; ian@0: ian@0: ValueInternalLink(); ian@0: ian@0: ~ValueInternalLink(); ian@0: ian@0: Value items_[itemPerLink]; ian@0: char *keys_[itemPerLink]; ian@0: ValueInternalLink *previous_; ian@0: ValueInternalLink *next_; ian@0: }; ian@0: ian@0: ian@0: /** \brief A linked page based hash-table implementation used internally by Value. ian@0: * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked ian@0: * list in each bucket to handle collision. There is an addional twist in that ian@0: * each node of the collision linked list is a page containing a fixed amount of ian@0: * value. This provides a better compromise between memory usage and speed. ian@0: * ian@0: * Each bucket is made up of a chained list of ValueInternalLink. The last ian@0: * link of a given bucket can be found in the 'previous_' field of the following bucket. ian@0: * The last link of the last bucket is stored in tailLink_ as it has no following bucket. ian@0: * Only the last link of a bucket may contains 'available' item. The last link always ian@0: * contains at least one element unless is it the bucket one very first link. ian@0: */ ian@0: class JSON_API ValueInternalMap ian@0: { ian@0: friend class ValueIteratorBase; ian@0: friend class Value; ian@0: public: ian@0: typedef unsigned int HashKey; ian@0: typedef unsigned int BucketIndex; ian@0: ian@0: # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ian@0: struct IteratorState ian@0: { ian@0: IteratorState() ian@0: : map_(0) ian@0: , link_(0) ian@0: , itemIndex_(0) ian@0: , bucketIndex_(0) ian@0: { ian@0: } ian@0: ValueInternalMap *map_; ian@0: ValueInternalLink *link_; ian@0: BucketIndex itemIndex_; ian@0: BucketIndex bucketIndex_; ian@0: }; ian@0: # endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ian@0: ian@0: ValueInternalMap(); ian@0: ValueInternalMap( const ValueInternalMap &other ); ian@0: ValueInternalMap &operator =( const ValueInternalMap &other ); ian@0: ~ValueInternalMap(); ian@0: ian@0: void swap( ValueInternalMap &other ); ian@0: ian@0: BucketIndex size() const; ian@0: ian@0: void clear(); ian@0: ian@0: bool reserveDelta( BucketIndex growth ); ian@0: ian@0: bool reserve( BucketIndex newItemCount ); ian@0: ian@0: const Value *find( const char *key ) const; ian@0: ian@0: Value *find( const char *key ); ian@0: ian@0: Value &resolveReference( const char *key, ian@0: bool isStatic ); ian@0: ian@0: void remove( const char *key ); ian@0: ian@0: void doActualRemove( ValueInternalLink *link, ian@0: BucketIndex index, ian@0: BucketIndex bucketIndex ); ian@0: ian@0: ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); ian@0: ian@0: Value &setNewItem( const char *key, ian@0: bool isStatic, ian@0: ValueInternalLink *link, ian@0: BucketIndex index ); ian@0: ian@0: Value &unsafeAdd( const char *key, ian@0: bool isStatic, ian@0: HashKey hashedKey ); ian@0: ian@0: HashKey hash( const char *key ) const; ian@0: ian@0: int compare( const ValueInternalMap &other ) const; ian@0: ian@0: private: ian@0: void makeBeginIterator( IteratorState &it ) const; ian@0: void makeEndIterator( IteratorState &it ) const; ian@0: static bool equals( const IteratorState &x, const IteratorState &other ); ian@0: static void increment( IteratorState &iterator ); ian@0: static void incrementBucket( IteratorState &iterator ); ian@0: static void decrement( IteratorState &iterator ); ian@0: static const char *key( const IteratorState &iterator ); ian@0: static const char *key( const IteratorState &iterator, bool &isStatic ); ian@0: static Value &value( const IteratorState &iterator ); ian@0: static int distance( const IteratorState &x, const IteratorState &y ); ian@0: ian@0: private: ian@0: ValueInternalLink *buckets_; ian@0: ValueInternalLink *tailLink_; ian@0: BucketIndex bucketsSize_; ian@0: BucketIndex itemCount_; ian@0: }; ian@0: ian@0: /** \brief A simplified deque implementation used internally by Value. ian@0: * \internal ian@0: * It is based on a list of fixed "page", each page contains a fixed number of items. ian@0: * Instead of using a linked-list, a array of pointer is used for fast item look-up. ian@0: * Look-up for an element is as follow: ian@0: * - compute page index: pageIndex = itemIndex / itemsPerPage ian@0: * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] ian@0: * ian@0: * Insertion is amortized constant time (only the array containing the index of pointers ian@0: * need to be reallocated when items are appended). ian@0: */ ian@0: class JSON_API ValueInternalArray ian@0: { ian@0: friend class Value; ian@0: friend class ValueIteratorBase; ian@0: public: ian@0: enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. ian@0: typedef Value::ArrayIndex ArrayIndex; ian@0: typedef unsigned int PageIndex; ian@0: ian@0: # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ian@0: struct IteratorState // Must be a POD ian@0: { ian@0: IteratorState() ian@0: : array_(0) ian@0: , currentPageIndex_(0) ian@0: , currentItemIndex_(0) ian@0: { ian@0: } ian@0: ValueInternalArray *array_; ian@0: Value **currentPageIndex_; ian@0: unsigned int currentItemIndex_; ian@0: }; ian@0: # endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ian@0: ian@0: ValueInternalArray(); ian@0: ValueInternalArray( const ValueInternalArray &other ); ian@0: ValueInternalArray &operator =( const ValueInternalArray &other ); ian@0: ~ValueInternalArray(); ian@0: void swap( ValueInternalArray &other ); ian@0: ian@0: void clear(); ian@0: void resize( ArrayIndex newSize ); ian@0: ian@0: Value &resolveReference( ArrayIndex index ); ian@0: ian@0: Value *find( ArrayIndex index ) const; ian@0: ian@0: ArrayIndex size() const; ian@0: ian@0: int compare( const ValueInternalArray &other ) const; ian@0: ian@0: private: ian@0: static bool equals( const IteratorState &x, const IteratorState &other ); ian@0: static void increment( IteratorState &iterator ); ian@0: static void decrement( IteratorState &iterator ); ian@0: static Value &dereference( const IteratorState &iterator ); ian@0: static Value &unsafeDereference( const IteratorState &iterator ); ian@0: static int distance( const IteratorState &x, const IteratorState &y ); ian@0: static ArrayIndex indexOf( const IteratorState &iterator ); ian@0: void makeBeginIterator( IteratorState &it ) const; ian@0: void makeEndIterator( IteratorState &it ) const; ian@0: void makeIterator( IteratorState &it, ArrayIndex index ) const; ian@0: ian@0: void makeIndexValid( ArrayIndex index ); ian@0: ian@0: Value **pages_; ian@0: ArrayIndex size_; ian@0: PageIndex pageCount_; ian@0: }; ian@0: ian@0: /** \brief Experimental: do not use. Allocator to customize Value internal array. ian@0: * Below is an example of a simple implementation (actual implementation use ian@0: * memory pool). ian@0: \code ian@0: class DefaultValueArrayAllocator : public ValueArrayAllocator ian@0: { ian@0: public: // overridden from ValueArrayAllocator ian@0: virtual ~DefaultValueArrayAllocator() ian@0: { ian@0: } ian@0: ian@0: virtual ValueInternalArray *newArray() ian@0: { ian@0: return new ValueInternalArray(); ian@0: } ian@0: ian@0: virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) ian@0: { ian@0: return new ValueInternalArray( other ); ian@0: } ian@0: ian@0: virtual void destruct( ValueInternalArray *array ) ian@0: { ian@0: delete array; ian@0: } ian@0: ian@0: virtual void reallocateArrayPageIndex( Value **&indexes, ian@0: ValueInternalArray::PageIndex &indexCount, ian@0: ValueInternalArray::PageIndex minNewIndexCount ) ian@0: { ian@0: ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; ian@0: if ( minNewIndexCount > newIndexCount ) ian@0: newIndexCount = minNewIndexCount; ian@0: void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); ian@0: if ( !newIndexes ) ian@0: throw std::bad_alloc(); ian@0: indexCount = newIndexCount; ian@0: indexes = static_cast( newIndexes ); ian@0: } ian@0: virtual void releaseArrayPageIndex( Value **indexes, ian@0: ValueInternalArray::PageIndex indexCount ) ian@0: { ian@0: if ( indexes ) ian@0: free( indexes ); ian@0: } ian@0: ian@0: virtual Value *allocateArrayPage() ian@0: { ian@0: return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); ian@0: } ian@0: ian@0: virtual void releaseArrayPage( Value *value ) ian@0: { ian@0: if ( value ) ian@0: free( value ); ian@0: } ian@0: }; ian@0: \endcode ian@0: */ ian@0: class JSON_API ValueArrayAllocator ian@0: { ian@0: public: ian@0: virtual ~ValueArrayAllocator(); ian@0: virtual ValueInternalArray *newArray() = 0; ian@0: virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; ian@0: virtual void destructArray( ValueInternalArray *array ) = 0; ian@0: /** \brief Reallocate array page index. ian@0: * Reallocates an array of pointer on each page. ian@0: * \param indexes [input] pointer on the current index. May be \c NULL. ian@0: * [output] pointer on the new index of at least ian@0: * \a minNewIndexCount pages. ian@0: * \param indexCount [input] current number of pages in the index. ian@0: * [output] number of page the reallocated index can handle. ian@0: * \b MUST be >= \a minNewIndexCount. ian@0: * \param minNewIndexCount Minimum number of page the new index must be able to ian@0: * handle. ian@0: */ ian@0: virtual void reallocateArrayPageIndex( Value **&indexes, ian@0: ValueInternalArray::PageIndex &indexCount, ian@0: ValueInternalArray::PageIndex minNewIndexCount ) = 0; ian@0: virtual void releaseArrayPageIndex( Value **indexes, ian@0: ValueInternalArray::PageIndex indexCount ) = 0; ian@0: virtual Value *allocateArrayPage() = 0; ian@0: virtual void releaseArrayPage( Value *value ) = 0; ian@0: }; ian@0: #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP ian@0: ian@0: ian@0: /** \brief base class for Value iterators. ian@0: * ian@0: */ ian@0: class ValueIteratorBase ian@0: { ian@0: public: ian@0: typedef unsigned int size_t; ian@0: typedef int difference_type; ian@0: typedef ValueIteratorBase SelfType; ian@0: ian@0: ValueIteratorBase(); ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); ian@0: #else ian@0: ValueIteratorBase( const ValueInternalArray::IteratorState &state ); ian@0: ValueIteratorBase( const ValueInternalMap::IteratorState &state ); ian@0: #endif ian@0: ian@0: bool operator ==( const SelfType &other ) const ian@0: { ian@0: return isEqual( other ); ian@0: } ian@0: ian@0: bool operator !=( const SelfType &other ) const ian@0: { ian@0: return !isEqual( other ); ian@0: } ian@0: ian@0: difference_type operator -( const SelfType &other ) const ian@0: { ian@0: return computeDistance( other ); ian@0: } ian@0: ian@0: /// Return either the index or the member name of the referenced value as a Value. ian@0: Value key() const; ian@0: ian@0: /// Return the index of the referenced Value. -1 if it is not an arrayValue. ian@0: UInt index() const; ian@0: ian@0: /// Return the member name of the referenced Value. "" if it is not an objectValue. ian@0: const char *memberName() const; ian@0: ian@0: protected: ian@0: Value &deref() const; ian@0: ian@0: void increment(); ian@0: ian@0: void decrement(); ian@0: ian@0: difference_type computeDistance( const SelfType &other ) const; ian@0: ian@0: bool isEqual( const SelfType &other ) const; ian@0: ian@0: void copy( const SelfType &other ); ian@0: ian@0: private: ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: Value::ObjectValues::iterator current_; ian@0: // Indicates that iterator is for a null value. ian@0: bool isNull_; ian@0: #else ian@0: union ian@0: { ian@0: ValueInternalArray::IteratorState array_; ian@0: ValueInternalMap::IteratorState map_; ian@0: } iterator_; ian@0: bool isArray_; ian@0: #endif ian@0: }; ian@0: ian@0: /** \brief const iterator for object and array value. ian@0: * ian@0: */ ian@0: class ValueConstIterator : public ValueIteratorBase ian@0: { ian@0: friend class Value; ian@0: public: ian@0: typedef unsigned int size_t; ian@0: typedef int difference_type; ian@0: typedef const Value &reference; ian@0: typedef const Value *pointer; ian@0: typedef ValueConstIterator SelfType; ian@0: ian@0: ValueConstIterator(); ian@0: private: ian@0: /*! \internal Use by Value to create an iterator. ian@0: */ ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); ian@0: #else ian@0: ValueConstIterator( const ValueInternalArray::IteratorState &state ); ian@0: ValueConstIterator( const ValueInternalMap::IteratorState &state ); ian@0: #endif ian@0: public: ian@0: SelfType &operator =( const ValueIteratorBase &other ); ian@0: ian@0: SelfType operator++( int ) ian@0: { ian@0: SelfType temp( *this ); ian@0: ++*this; ian@0: return temp; ian@0: } ian@0: ian@0: SelfType operator--( int ) ian@0: { ian@0: SelfType temp( *this ); ian@0: --*this; ian@0: return temp; ian@0: } ian@0: ian@0: SelfType &operator--() ian@0: { ian@0: decrement(); ian@0: return *this; ian@0: } ian@0: ian@0: SelfType &operator++() ian@0: { ian@0: increment(); ian@0: return *this; ian@0: } ian@0: ian@0: reference operator *() const ian@0: { ian@0: return deref(); ian@0: } ian@0: }; ian@0: ian@0: ian@0: /** \brief Iterator for object and array value. ian@0: */ ian@0: class ValueIterator : public ValueIteratorBase ian@0: { ian@0: friend class Value; ian@0: public: ian@0: typedef unsigned int size_t; ian@0: typedef int difference_type; ian@0: typedef Value &reference; ian@0: typedef Value *pointer; ian@0: typedef ValueIterator SelfType; ian@0: ian@0: ValueIterator(); ian@0: ValueIterator( const ValueConstIterator &other ); ian@0: ValueIterator( const ValueIterator &other ); ian@0: private: ian@0: /*! \internal Use by Value to create an iterator. ian@0: */ ian@0: #ifndef JSON_VALUE_USE_INTERNAL_MAP ian@0: explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); ian@0: #else ian@0: ValueIterator( const ValueInternalArray::IteratorState &state ); ian@0: ValueIterator( const ValueInternalMap::IteratorState &state ); ian@0: #endif ian@0: public: ian@0: ian@0: SelfType &operator =( const SelfType &other ); ian@0: ian@0: SelfType operator++( int ) ian@0: { ian@0: SelfType temp( *this ); ian@0: ++*this; ian@0: return temp; ian@0: } ian@0: ian@0: SelfType operator--( int ) ian@0: { ian@0: SelfType temp( *this ); ian@0: --*this; ian@0: return temp; ian@0: } ian@0: ian@0: SelfType &operator--() ian@0: { ian@0: decrement(); ian@0: return *this; ian@0: } ian@0: ian@0: SelfType &operator++() ian@0: { ian@0: increment(); ian@0: return *this; ian@0: } ian@0: ian@0: reference operator *() const ian@0: { ian@0: return deref(); ian@0: } ian@0: }; ian@0: ian@0: ian@0: } // namespace Json ian@0: ian@0: ian@0: #endif // CPPTL_JSON_H_INCLUDED