jsonCPP 开源库详解
JsonCpp 是一个C++库,用于解析和生成 JSON 数据。它具有以下特点:
- 轻量级且易于集成
- 支持 STL 容器
- 提供 DOM 风格的 API
- 支持 JSON 指针和 JSON 补丁(部分版本)
主要功能
- 解析JSON字符串为 C++ 对象
- 将 C++ 对象序列化为 JSON 字符串
- 访问和修改 JSON 数据
- 支持 JSON 数组和对象
1、下载jsonCPP
源码下载:git clone https://github.com/open-source-parsers/jsoncpp.git
源码编译:
cd jsoncpp
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=release -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF ../
make
成功编译出 libjsoncpp.a库文件。
2、jsonCPP的使用
下面用一段代码说明jsonCPP的使用
#include <iostream>
#include <string>
#include <memory>
#include "json.h"using namespace std;/*如何使用jsoncpp库文件*/
string jsonStr = R"({"name": "John Doe","age": 30,"is_student": false,"courses": ["Math", "Physics"],"address": {"street": "123 Main St","city": "New York"}}
)";int main()
{Json::Value root;Json::CharReaderBuilder readerBuilder;unique_ptr<Json::CharReader> reader(readerBuilder.newCharReader());string errs;bool parsingSuccessful = reader->parse(jsonStr.c_str(),jsonStr.c_str()+jsonStr.size(),&root,&errs);if(!parsingSuccessful) cout << "failed to parse JSON:" << errs << endl;/*获取字符串值*/string name = root["name"].asString();cout << "name:" << name << endl;/*获取数值*/int age = root["age"].asInt();cout << "age:" << age << endl;/*获取布尔值*/bool isStudent = root["is_student"].asBool();cout << "is_student:" << isStudent << endl;/*获取数组*/const Json::Value& courses = root["courses"];for(Json::ArrayIndex i = 0; i<courses.size(); i++)cout << courses[i].asString() << endl;/*获取嵌套对象*/ const Json::Value& address = root["address"];string street = address["street"].asString();string city = address["city"].asString();cout << "address:" << street << ',' << city << endl;/*修改内容*/root["age"] = 31;root["email"] = "john.doe@example.com";root["courses"].append("chemistry");root["address"]["city"] = "Boston";/*生成JSON字符串*/Json::StreamWriterBuilder writerBuilder;unique_ptr<Json::StreamWriter> writer(writerBuilder.newStreamWriter());ostringstream oss;writer->write(root,&oss);string outputJson = oss.str();/*{"address" : {"city" : "Boston","street" : "123 Main St"},"age" : 31,"courses" : ["Math","Physics","chemistry"],"email" : "john.doe@example.com","is_student" : false,"name" : "John Doe"}*/cout << outputJson << endl;//可以直接使用ostream代替ostringstream类型cout << "直接输出JSON数据内容:" << endl;writer->write(root,&cout);cout << endl;//代码中针对Json::Value类重载了输出运算符<<,所以我们可以直接使用cout输出json内容cout << "cout的方式输出JSON数据:" << endl;cout << root << endl;return 1;
}
编译时记得链接 libjsoncpp.a 库文件以及-I 指定josn.h头文件的位置。
3、jsonCPP源码详解
jsonCPP源码主要完成两个功能:
一是解析json数据并且将解析后的数据通过map进行存储。其中作者非常巧妙的对Value类重载了好几个版本的下标运算符[]使得我们可以通过下标运算符来获取对应的值,如下所示:
string name = root["name"].asString();
bool isStudent = root["is_student"].asBool();
二是打印json数据,我们可以随意的修改json中的数据并将最终的结果打印出来。如下所示:
root["age"] = 31;
root["email"] = "john.doe@example.com";
由于jsonCPP的源码内容不是很长,阅读的难度也不是很大,鼓励大家去进行阅读。大家阅读时可以从Value类开始,因为这个类是核心重点。最后我将jsonCPP注释过的源码放在文章中,需要的同学自行阅读。
value.h内容如下:
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// 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 JSON_VALUE_H_INCLUDED
#define JSON_VALUE_H_INCLUDED#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION)// Conditional NORETURN attribute on the throw functions would:
// a) suppress false positives from static code analysis
// b) possibly improve optimization opportunities.
#if !defined(JSONCPP_NORETURN)
#if defined(_MSC_VER) && _MSC_VER == 1800
#define JSONCPP_NORETURN __declspec(noreturn)
#else
#define JSONCPP_NORETURN [[noreturn]]
#endif
#endif// Support for '= delete' with template declarations was a late addition
// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2
// even though these declare themselves to be c++11 compilers.
#if !defined(JSONCPP_TEMPLATE_DELETE)
#if defined(__clang__) && defined(__apple_build_version__)
#if __apple_build_version__ <= 8000042
#define JSONCPP_TEMPLATE_DELETE
#endif
#elif defined(__clang__)
#if __clang_major__ == 3 && __clang_minor__ <= 8
#define JSONCPP_TEMPLATE_DELETE
#endif
#endif
#if !defined(JSONCPP_TEMPLATE_DELETE)
#define JSONCPP_TEMPLATE_DELETE = delete
#endif
#endif#if __cplusplus >= 201703L
#define JSONCPP_HAS_STRING_VIEW 1
#endif#include <array>
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <vector>#ifdef JSONCPP_HAS_STRING_VIEW
#include <string_view>
#endif// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251 4275)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)#pragma pack(push)
#pragma pack()/** \brief JSON (JavaScript Object Notation).*/
namespace Json {#if JSON_USE_EXCEPTION
/** Base class for all exceptions we throw.** We use nothing but these internally. Of course, STL can throw others.*/
class JSON_API Exception : public std::exception {
public:Exception(String msg);~Exception() noexcept override;char const* what() const noexcept override;protected:String msg_;
};/** Exceptions which the user cannot easily avoid.** E.g. out-of-memory (when we use malloc), stack-overflow, malicious input** \remark derived from Json::Exception*/
class JSON_API RuntimeError : public Exception {
public:RuntimeError(String const& msg);
};/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.** These are precondition-violations (user bugs) and internal errors (our bugs).** \remark derived from Json::Exception*/
class JSON_API LogicError : public Exception {
public:LogicError(String const& msg);
};
#endif/// used internally
JSONCPP_NORETURN void throwRuntimeError(String const& msg);
/// used internally
JSONCPP_NORETURN void throwLogicError(String const& msg);/** \brief Type of the value held by a Value object.*/
/*Value能够存放的数据类型*/
enum ValueType {nullValue = 0, ///< 'null' valueintValue, ///< signed integer valueuintValue, ///< unsigned integer valuerealValue, ///< double valuestringValue, ///< UTF-8 string valuebooleanValue, ///< bool valuearrayValue, ///< array value (ordered list)objectValue ///< object value (collection of name/value pairs).
};enum CommentPlacement {// /*注释*/// a = 5;commentBefore = 0, ///< a comment placed on the line before a value// a = 5; /*注释*/commentAfterOnSameLine, ///< a comment just after a value on the same line// a = 5;// /*注释*/commentAfter, ///< a comment on the line after a value (only make sense for/// root value)numberOfCommentPlacement
};/** \brief Type of precision for formatting of real values.*/
enum PrecisionType {significantDigits = 0, ///< we set max number of significant digits in stringdecimalPlaces ///< we set max number of digits after "." in string
};/** \brief Lightweight wrapper to tag static string.** Value constructor and objectValue member assignment 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) : c_str_(czstring) {}/*定义了一个类型转换运算符,将对象转换为 const char* 类型*/operator const char*() const { return c_str_; }const char* c_str() const { return c_str_; }private:const char* c_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 resized and initialized* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.** The get() methods can be used to obtain default value in the case the* required element does not exist.** It is possible to iterate over the list of member keys of an object using* the getMemberNames() method.** \note #Value string-length fit in size_t, but keys must be < 2^30.* (The reason is an implementation detail.) A #CharReader will raise an* exception if a bound is exceeded to avoid security holes in your app,* but the Value API does *not* check bounds. That is the responsibility* of the caller.*/
/*Value类
JSON 数据由以下两种基本结构组成:
键值对集合(对象):用花括号 {} 包裹,键值对之间用逗号 , 分隔,键和值用冒号 : 分隔。键:必须是字符串(用双引号 "" 包裹)。值:可以是字符串、数字、布尔值、null、对象或数组。
值的有序列表(数组):用方括号 [] 包裹,元素之间用逗号 , 分隔。元素类型可以是字符串、数字、布尔值、null、对象或数组。
*/
class JSON_API Value {/*友元类*/friend class ValueIteratorBase;public:/*打印JSON时使用*/using Members = std::vector<String>;using iterator = ValueIterator;using const_iterator = ValueConstIterator;using UInt = Json::UInt;using Int = Json::Int;
#if defined(JSON_HAS_INT64)using UInt64 = Json::UInt64;using Int64 = Json::Int64;
#endif // defined(JSON_HAS_INT64)using LargestInt = Json::LargestInt;using LargestUInt = Json::LargestUInt;using ArrayIndex = Json::ArrayIndex;// Required for boost integration, e. g. BOOST_TESTusing value_type = std::string;/*静态成员*/
#if JSON_USE_NULLREF// Binary compatibility kludges, do not use./*null和nullRef的类型是const Value&而非指针*/static const Value& null;static const Value& nullRef;
#endif// null and nullRef are deprecated, use this instead.static Value const& nullSingleton();/// Minimum signed integer value that can be stored in a Json::Value./*能够存储的最小有符号整数,/2可以视为右移一位*/static constexpr LargestInt minLargestInt =LargestInt(~(LargestUInt(-1) / 2));/// Maximum signed integer value that can be stored in a Json::Value.static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2);/// Maximum unsigned integer value that can be stored in a Json::Value.static constexpr LargestUInt maxLargestUInt = LargestUInt(-1);/// Minimum signed int value that can be stored in a Json::Value.static constexpr Int minInt = Int(~(UInt(-1) / 2));/// Maximum signed int value that can be stored in a Json::Value.static constexpr Int maxInt = Int(UInt(-1) / 2);/// Maximum unsigned int value that can be stored in a Json::Value.static constexpr UInt maxUInt = UInt(-1);#if defined(JSON_HAS_INT64)/// Minimum signed 64 bits int value that can be stored in a Json::Value.static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2));/// Maximum signed 64 bits int value that can be stored in a Json::Value.static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2);/// Maximum unsigned 64 bits int value that can be stored in a Json::Value.static constexpr UInt64 maxUInt64 = UInt64(-1);
#endif // defined(JSON_HAS_INT64)/// Default precision for real value for string representation.static constexpr UInt defaultRealPrecision = 17;// The constant is hard-coded because some compiler have trouble// converting Value::maxUInt64 to a double correctly (AIX/xlC).// Assumes that UInt64 is a 64 bits integer.static constexpr double maxUInt64AsDouble = 18446744073709551615.0;
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
// when using gcc and clang backend compilers. CZString
// cannot be defined as private. See issue #486
#ifdef __NVCC__
public:
#else
private:
#endif
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION/*Value类里面包含了CZString类*/class CZString {public:/*复制策略*/enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy };CZString(ArrayIndex index);CZString(char const* str, unsigned length, DuplicationPolicy allocate);/*拷贝构造函数*/CZString(CZString const& other);/*移动构造函数*/CZString(CZString&& other) noexcept;/*析构函数*/~CZString();/*拷贝赋值运算符*/CZString& operator=(const CZString& other);/*移动赋值运算符*/CZString& operator=(CZString&& other) noexcept;/*实现为成员函数*/bool operator<(CZString const& other) const;bool operator==(CZString const& other) const;ArrayIndex index() const;// const char* c_str() const; ///< \deprecatedchar const* data() const;unsigned length() const;bool isStaticString() const;private:void swap(CZString& other);struct StringStorage {unsigned policy_ : 2;unsigned length_ : 30; // 1GB max};char const* cstr_; // actually, a prefixed string, unless policy is noDupunion {ArrayIndex index_;StringStorage storage_;};};public:/*使用map key-value对来存储*/typedef std::map<CZString, Value> ObjectValues;
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATIONpublic:/*** \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类的构造函数,支持整形,浮点数,布尔类型,字符串*/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); ///< Copy til first 0. (NULL causes to seg-fault.)Value(const char* begin, const char* end); ///< Copy all, incl zeroes./*** \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.** \note This works only for null-terminated strings. (We cannot change the* size of this class, so we have nowhere to store the length, which might be* computed later for various operations.)** Example of usage:* \code* static StaticString foo("some text");* Json::Value aValue(foo);* \endcode*/Value(const StaticString& value);Value(const String& value);
#ifdef JSONCPP_HAS_STRING_VIEWValue(std::string_view value);
#endifValue(bool value);Value(std::nullptr_t ptr) = delete;/*拷贝构造函数*/Value(const Value& other);/*移动构造函数*/Value(Value&& other) noexcept;~Value();/// \note Overwrite existing comments. To preserve comments, use/// #swapPayload()./*赋值运算符*/Value& operator=(const Value& other);/*移动运算符*/Value& operator=(Value&& other) noexcept;/// Swap everything.void swap(Value& other);/// Swap values but leave comments and source offsets in place.void swapPayload(Value& other);/// copy everything.void copy(const Value& other);/// copy values but leave comments and source offsets in place.void copyPayload(const Value& other);ValueType type() const;/// Compare payload only, not comments etc.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; ///< Embedded zeroes could cause you trouble!
#if JSONCPP_USE_SECURE_MEMORYunsigned getCStringLength() const; // Allows you to understand the length of// the CString
#endifString asString() const; ///< Embedded zeroes are possible./** Get raw char* of string-value.* \return false if !string. (Seg-fault if str or end are NULL.)*/bool getString(char const** begin, char const** end) const;
#ifdef JSONCPP_HAS_STRING_VIEW/** Get string_view of string-value.* \return false if !string. (Seg-fault if str is NULL.)*/bool getString(std::string_view* str) const;
#endifInt asInt() const;UInt asUInt() const;
#if defined(JSON_HAS_INT64)Int64 asInt64() const;UInt64 asUInt64() const;
#endif // if defined(JSON_HAS_INT64)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 isInt64() const;bool isUInt() const;bool isUInt64() const;bool isIntegral() const;bool isDouble() const;bool isNumeric() const;bool isString() const;bool isArray() const;bool isObject() const;/// The `as<T>` and `is<T>` member function templates and specializations.template <typename T> T as() const JSONCPP_TEMPLATE_DELETE;template <typename T> bool is() const JSONCPP_TEMPLATE_DELETE;bool isConvertibleTo(ValueType other) const;/// Number of values in array or objectArrayIndex size() const;/// \brief Return true if empty array, empty object, or null;/// otherwise, false.bool empty() const;/// Return !isNull()explicit operator bool() const;/// Remove all object members and array elements./// \pre type() is arrayValue, objectValue, or nullValue/// \post type() is unchangedvoid clear();/// Resize the array to newSize elements./// New elements are initialized to null./// May only be called on nullValue or arrayValue./// \pre type() is arrayValue or nullValue/// \post type() is arrayValuevoid resize(ArrayIndex newSize);///@{/// 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);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;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);Value& append(Value&& value);/// \brief Insert value in array at specific indexbool insert(ArrayIndex index, const Value& newValue);bool insert(ArrayIndex index, Value&& newValue);#ifdef JSONCPP_HAS_STRING_VIEW/// Access an object value by name, create a null member if it does not exist./// \param key may contain embedded nulls.Value& operator[](std::string_view key);/// Access an object value by name, returns null if there is no member with/// that name./// \param key may contain embedded nulls.const Value& operator[](std::string_view key) const;
#else/// Access an object value by name, create a null member if it does not exist./// \note Because of our implementation, keys are limited to 2^30 -1 chars./// Exceeding that will cause an exception.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./// \param key may contain embedded nulls.Value& operator[](const String& key);/// Access an object value by name, returns null if there is no member with/// that name./// \param key may contain embedded nulls.const Value& operator[](const String& key) const;
#endif/** \brief Access an object value by name, create a null member if it does not* exist.** If the object has 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 JSONCPP_HAS_STRING_VIEW/// Return the member named key if it exist, defaultValue otherwise./// \note deep copyValue get(std::string_view key, const Value& defaultValue) const;
#else/// Return the member named key if it exist, defaultValue otherwise./// \note deep copyValue get(const char* key, const Value& defaultValue) const;/// Return the member named key if it exist, defaultValue otherwise./// \note deep copy/// \param key may contain embedded nulls.Value get(const String& key, const Value& defaultValue) const;
#endif/// Return the member named key if it exist, defaultValue otherwise./// \note deep copy/// \note key may contain embedded nulls.Value get(const char* begin, const char* end,const Value& defaultValue) const;/// Most general and efficient version of isMember()const, get()const,/// and operator[]const/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30Value const* find(char const* begin, char const* end) const;/// Most general and efficient version of isMember()const, get()const,/// and operator[]constValue const* find(const String& key) const;/// Calls find and only returns a valid pointer if the type is foundtemplate <typename T, bool (T::*TMemFn)() const>Value const* findValue(const String& key) const {Value const* found = find(key);if (!found || !(found->*TMemFn)())return nullptr;return found;}Value const* findNull(const String& key) const;Value const* findBool(const String& key) const;Value const* findInt(const String& key) const;Value const* findInt64(const String& key) const;Value const* findUInt(const String& key) const;Value const* findUInt64(const String& key) const;Value const* findIntegral(const String& key) const;Value const* findDouble(const String& key) const;Value const* findNumeric(const String& key) const;Value const* findString(const String& key) const;Value const* findArray(const String& key) const;Value const* findObject(const String& key) const;/// Most general and efficient version of object-mutators./// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.Value* demand(char const* begin, char const* end);/// \brief Remove and return the named member.////// Do nothing if it did not exist./// \pre type() is objectValue or nullValue/// \post type() is unchanged
#if JSONCPP_HAS_STRING_VIEWvoid removeMember(std::string_view key);
#elsevoid removeMember(const char* key);/// Same as removeMember(const char*)/// \param key may contain embedded nulls.void removeMember(const String& key);
#endif/** \brief Remove the named map member.** Update 'removed' iff removed.* \param key may contain embedded nulls.* \return true iff removed (no exceptions)*/
#if JSONCPP_HAS_STRING_VIEWbool removeMember(std::string_view key, Value* removed);
#elsebool removeMember(String const& key, Value* removed);/// Same as removeMember(const char* begin, const char* end, Value* removed),/// but 'key' is null-terminated.bool removeMember(const char* key, Value* removed);
#endif/// Same as removeMember(String const& key, Value* removed)bool removeMember(const char* begin, const char* end, Value* removed);/** \brief Remove the indexed array element.** O(n) expensive operations.* Update 'removed' iff removed.* \return true if removed (no exceptions)*/bool removeIndex(ArrayIndex index, Value* removed);#ifdef JSONCPP_HAS_STRING_VIEW/// Return true if the object has a member named key./// \param key may contain embedded nulls.bool isMember(std::string_view key) const;
#else/// Return true if the object has a member named key./// \note 'key' must be null-terminated.bool isMember(const char* key) const;/// Return true if the object has a member named key./// \param key may contain embedded nulls.bool isMember(const String& key) const;
#endif/// Same as isMember(String const& key)constbool isMember(const char* begin, const char* end) const;/// \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 nullValueMembers getMemberNames() const;/// \deprecated Always pass len.JSONCPP_DEPRECATED("Use setComment(String const&) instead.")void setComment(const char* comment, CommentPlacement placement) {setComment(String(comment, strlen(comment)), placement);}/// Comments must be //... or /* ... */void setComment(const char* comment, size_t len, CommentPlacement placement) {setComment(String(comment, len), placement);}/// Comments must be //... or /* ... */void setComment(String comment, CommentPlacement placement);bool hasComment(CommentPlacement placement) const;/// Include delimiters and embedded newlines.String getComment(CommentPlacement placement) const;String toStyledString() const;const_iterator begin() const;const_iterator end() const;iterator begin();iterator end();/// \brief Returns a reference to the first element in the `Value`./// Requires that this value holds an array or json object, with at least one/// element.const Value& front() const;/// \brief Returns a reference to the first element in the `Value`./// Requires that this value holds an array or json object, with at least one/// element.Value& front();/// \brief Returns a reference to the last element in the `Value`./// Requires that value holds an array or json object, with at least one/// element.const Value& back() const;/// \brief Returns a reference to the last element in the `Value`./// Requires that this value holds an array or json object, with at least one/// element.Value& back();// Accessors for the [start, limit) range of bytes within the JSON text from// which this value was parsed, if any.void setOffsetStart(ptrdiff_t start);void setOffsetLimit(ptrdiff_t limit);ptrdiff_t getOffsetStart() const;ptrdiff_t getOffsetLimit() const;private:void setType(ValueType v) {bits_.value_type_ = static_cast<unsigned char>(v);}bool isAllocated() const { return bits_.allocated_; }void setIsAllocated(bool v) { bits_.allocated_ = v; }/*initBasic在声明时参数allocated存在默认参数*/void initBasic(ValueType type, bool allocated = false);void dupPayload(const Value& other);void releasePayload();void dupMeta(const Value& other);Value& resolveReference(const char* key);Value& resolveReference(const char* key, const char* end);// struct MemberNamesTransform//{// typedef const char *result_type;// const char *operator()( const CZString &name ) const// {// return name.c_str();// }//};/*存放值,因为需要各种类型的json数据,使用联合类型来存放*/union ValueHolder {LargestInt int_;LargestUInt uint_;double real_;bool bool_;/*只有bits_.allocated为1时,string中的内容才有效*/char* string_; // if allocated_, ptr to { unsigned, char[] }.ObjectValues* map_;} value_;struct {// Really a ValueType, but types should agree for bitfield packing./*表明数据类型,int bool,double,char *,map<>*/unsigned int value_type_ : 8;// Unless allocated_, string_ must be null-terminated.unsigned int allocated_ : 1;} bits_;class Comments {public:/*使用编译器生成的无参构造函数*/Comments() = default;Comments(const Comments& that);Comments(Comments&& that) noexcept;Comments& operator=(const Comments& that);Comments& operator=(Comments&& that) noexcept;bool has(CommentPlacement slot) const;String get(CommentPlacement slot) const;void set(CommentPlacement slot, String comment);private:using Array = std::array<String, numberOfCommentPlacement>;std::unique_ptr<Array> ptr_; /*ptr_存放注释内容??*/};Comments comments_;// [start, limit) byte offsets in the source JSON text from which this Value// was extracted.ptrdiff_t start_;ptrdiff_t limit_;
}; //Value类结束template <> inline bool Value::as<bool>() const { return asBool(); }
template <> inline bool Value::is<bool>() const { return isBool(); }template <> inline Int Value::as<Int>() const { return asInt(); }
template <> inline bool Value::is<Int>() const { return isInt(); }template <> inline UInt Value::as<UInt>() const { return asUInt(); }
template <> inline bool Value::is<UInt>() const { return isUInt(); }#if defined(JSON_HAS_INT64)
template <> inline Int64 Value::as<Int64>() const { return asInt64(); }
template <> inline bool Value::is<Int64>() const { return isInt64(); }template <> inline UInt64 Value::as<UInt64>() const { return asUInt64(); }
template <> inline bool Value::is<UInt64>() const { return isUInt64(); }
#endiftemplate <> inline double Value::as<double>() const { return asDouble(); }
template <> inline bool Value::is<double>() const { return isDouble(); }template <> inline String Value::as<String>() const { return asString(); }
template <> inline bool Value::is<String>() const { return isString(); }/// These `as` specializations are type conversions, and do not have a
/// corresponding `is`.
template <> inline float Value::as<float>() const { return asFloat(); }
template <> inline const char* Value::as<const char*>() const {return asCString();
}/** \brief Experimental and untested: represents an element of the "path" to* access a node.*/
class JSON_API PathArgument {
public:friend class Path;PathArgument();PathArgument(ArrayIndex index);PathArgument(const char* key);PathArgument(String key);private:enum Kind { kindNone = 0, kindIndex, kindKey };String key_;ArrayIndex index_{};Kind kind_{kindNone};
};/** \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 provided as parameter*/
class JSON_API Path {
public:Path(const 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:using InArgs = std::vector<const PathArgument*>;using Args = std::vector<PathArgument>;void makePath(const String& path, const InArgs& in);void addPathInArg(const String& path, const InArgs& in,InArgs::const_iterator& itInArg, PathArgument::Kind kind);static void invalidPath(const String& path, int location);Args args_;
};/** \brief base class for Value iterators.**/
class JSON_API ValueIteratorBase {
public:using iterator_category = std::bidirectional_iterator_tag;using size_t = unsigned int;using difference_type = int;using SelfType = ValueIteratorBase;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 other.computeDistance(*this);}/// 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, or -1 if it is not an/// arrayValue.UInt index() const;/// Return the member name of the referenced Value, or "" if it is not an/// objectValue./// \note Avoid `c_str()` on result, as embedded zeroes are possible.String name() const;/// Return the member name of the referenced Value. "" if it is not an/// objectValue./// \deprecated This cannot be used for UTF-8 strings, since there can be/// embedded nulls.JSONCPP_DEPRECATED("Use `key = name();` instead.")char const* memberName() const;/// Return the member name of the referenced Value, or NULL if it is not an/// objectValue./// \note Better version than memberName(). Allows embedded nulls.char const* memberName(char const** end) const;protected:/*! Internal utility functions to assist with implementing* other iterator functions. The const and non-const versions* of the "deref" protected methods expose the protected* current_ member variable in a way that can often be* optimized away by the compiler.*/const Value& deref() const;Value& deref();void increment();void decrement();difference_type computeDistance(const SelfType& other) const;bool isEqual(const SelfType& other) const;void copy(const SelfType& other);private:Value::ObjectValues::iterator current_;// Indicates that iterator is for a null value.bool isNull_{true};public:// For some reason, BORLAND needs these at the end, rather// than earlier. No idea why.ValueIteratorBase();explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
};/** \brief const iterator for object and array value.**/
class JSON_API ValueConstIterator : public ValueIteratorBase {friend class Value;public:using value_type = const Value;// typedef unsigned int size_t;// typedef int difference_type;using reference = const Value&;using pointer = const Value*;using SelfType = ValueConstIterator;ValueConstIterator();ValueConstIterator(ValueIterator const& other);private:/*! \internal Use by Value to create an iterator.*/explicit ValueConstIterator(const Value::ObjectValues::iterator& current);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(); }pointer operator->() const { return &deref(); }
};/** \brief Iterator for object and array value.*/
class JSON_API ValueIterator : public ValueIteratorBase {friend class Value;public:using value_type = Value;using size_t = unsigned int;using difference_type = int;using reference = Value&;using pointer = Value*;using SelfType = ValueIterator;ValueIterator();explicit ValueIterator(const ValueConstIterator& other);ValueIterator(const ValueIterator& other);private:/*! \internal Use by Value to create an iterator.*/explicit ValueIterator(const Value::ObjectValues::iterator& current);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;}/*! The return value of non-const iterators can be* changed, so the these functions are not const* because the returned references/pointers can be used* to change state of the base class.*/reference operator*() const { return const_cast<reference>(deref()); }pointer operator->() const { return const_cast<pointer>(&deref()); }
};inline void swap(Value& a, Value& b) { a.swap(b); }inline const Value& Value::front() const { return *begin(); }inline Value& Value::front() { return *begin(); }inline const Value& Value::back() const { return *(--end()); }inline Value& Value::back() { return *(--end()); }} // namespace Json#pragma pack(pop)#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)#endif // JSON_H_INCLUDED
json_value.cpp内容如下:
// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
// 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#if !defined(JSON_IS_AMALGAMATION)
#include <json/assertions.h>
#include <json/value.h>
#include <json/writer.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <sstream>
#include <utility>#ifdef JSONCPP_HAS_STRING_VIEW
#include <string_view>
#endif// Provide implementation equivalent of std::snprintf for older _MSC compilers
#if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdarg.h>
static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size,const char* format, va_list ap) {int count = -1;if (size != 0)count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);if (count == -1)count = _vscprintf(format, ap);return count;
}int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,const char* format, ...) {va_list ap;va_start(ap, format);const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);va_end(ap);return count;
}
#endif// Disable warning C4702 : unreachable code
#if defined(_MSC_VER)
#pragma warning(disable : 4702)
#endif#define JSON_ASSERT_UNREACHABLE assert(false)namespace Json {
template <typename T>
static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {std::unique_ptr<T> r; /*临时对象*/if (p) {/*unique_ptr不支持赋值运算符,这里只能是移动赋值运算符*/r = std::unique_ptr<T>(new T(*p));}return r;
}// This is a walkaround to avoid the static initialization of Value::null.
// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
// 8 (instead of 4) as a bit of future-proofing.
#if defined(__ARMEL__)
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#else
#define ALIGNAS(byte_alignment)
#endif// static
Value const& Value::nullSingleton() {static Value const nullStatic;return nullStatic;
}#if JSON_USE_NULLREF
// for backwards compatibility, we'll leave these global references around, but
// DO NOT use them in JSONCPP library code any more!
// static
Value const& Value::null = Value::nullSingleton();// static
Value const& Value::nullRef = Value::nullSingleton();
#endif#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
template <typename T, typename U>
static inline bool InRange(double d, T min, U max) {// The casts can lose precision, but we are looking only for// an approximate range. Might fail on edge cases though. ~cdunnreturn d >= static_cast<double>(min) && d <= static_cast<double>(max) &&!(static_cast<U>(d) == min && d != static_cast<double>(min));
}
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
static inline double integerToDouble(Json::UInt64 value) {/*double是64位浮点数,遵循IEEE 754标准,其有效数字约为15-17位十进制数。Json::UInt64是64位无符号整数,范围是0到18446744073709551615(约20位十进制数)。
结论:当value超过2^52 时,直接转换为double会丢失精度(因为 double的尾数部分只能精确表示52位二进制数)。这个代码写的很隐晦,将value拆分为整数部分和余数部分来处理,value / 2 ,value % 2(value & 1)但是还是不能避免精度丢失的情况 */return static_cast<double>(Int64(value / 2)) * 2.0 +static_cast<double>(Int64(value & 1));
}/*函数模板*/
template <typename T> static inline double integerToDouble(T value) {return static_cast<double>(value);
}/*函数模板*/
template <typename T, typename U>
static inline bool InRange(double d, T min, U max) {return d >= integerToDouble(min) && d <= integerToDouble(max)/*d在将min和max转换为double的范围内*/ &&!(static_cast<U>(d) == min/*将d转为min的类型*/ && d != integerToDouble(min)/*将min转换为d的double类型*/);
}
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)/** Duplicates the specified string value.* @param value Pointer to the string to duplicate. Must be zero-terminated if* length is "unknown".* @param length Length of the value. if equals to unknown, then it will be* computed using strlen(value).* @return Pointer on the duplicate instance of string.*/
/*将value所指内存中的数据拷贝到新内存中,并返回新内存空间地址*/
static inline char* duplicateStringValue(const char* value, size_t length) {// Avoid an integer overflow in the call to malloc below by limiting length// to a sane value.if (length >= static_cast<size_t>(Value::maxInt))length = Value::maxInt - 1;auto newString = static_cast<char*>(malloc(length + 1));if (newString == nullptr) {throwRuntimeError("in Json::Value::duplicateStringValue(): ""Failed to allocate string value buffer");}memcpy(newString, value, length);newString[length] = 0;return newString;
}/* Record the length as a prefix.*/
static inline char* duplicateAndPrefixStringValue(const char* value,unsigned int length) {// Avoid an integer overflow in the call to malloc below by limiting length// to a sane value.JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -sizeof(unsigned) - 1U,"in Json::Value::duplicateAndPrefixStringValue(): ""length too big for prefixing");size_t actualLength = sizeof(length) + length + 1;auto newString = static_cast<char*>(malloc(actualLength));if (newString == nullptr) {throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): ""Failed to allocate string value buffer");}/*先存放字符长度再存放字符串数据*/*reinterpret_cast<unsigned*>(newString) = length;memcpy(newString + sizeof(unsigned), value, length);newString[actualLength - 1U] =0; // to avoid buffer over-run accidents by users laterreturn newString;
}inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,unsigned* length, char const** value) {if (!isPrefixed) { /*不存在前缀长度字段*/*length = static_cast<unsigned>(strlen(prefixed));*value = prefixed;} else { /*存在前缀长度字段*/*length = *reinterpret_cast<unsigned const*>(prefixed); /*获取前缀长度*/*value = prefixed + sizeof(unsigned);}
}
/** Free the string duplicated by* duplicateStringValue()/duplicateAndPrefixStringValue().*/
#if JSONCPP_USE_SECURE_MEMORY
/*释放内存空间*/
static inline void releasePrefixedStringValue(char* value) {unsigned length = 0;char const* valueDecoded;decodePrefixedString(true, value, &length, &valueDecoded);size_t const size = sizeof(unsigned) + length + 1U;memset(value, 0, size);free(value);
}static inline void releaseStringValue(char* value, unsigned length) {// length==0 => we allocated the strings memorysize_t size = (length == 0) ? strlen(value) : length;memset(value, 0, size);free(value);
}#else // !JSONCPP_USE_SECURE_MEMORY
static inline void releasePrefixedStringValue(char* value) { free(value); }
static inline void releaseStringValue(char* value, unsigned) { free(value); }
#endif // JSONCPP_USE_SECURE_MEMORY} // namespace Json// //
// //
// //
// ValueInternals...
// //
// //
// //
#if !defined(JSON_IS_AMALGAMATION)#include "json_valueiterator.inl"
#endif // if !defined(JSON_IS_AMALGAMATION)namespace Json {#if JSON_USE_EXCEPTION
Exception::Exception(String msg) : msg_(std::move(msg)) {}
Exception::~Exception() noexcept = default;
char const* Exception::what() const noexcept { return msg_.c_str(); }
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
LogicError::LogicError(String const& msg) : Exception(msg) {}
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {throw RuntimeError(msg);
}
JSONCPP_NORETURN void throwLogicError(String const& msg) {throw LogicError(msg);
}
#else // !JSON_USE_EXCEPTION
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {std::cerr << msg << std::endl;abort();
}
JSONCPP_NORETURN void throwLogicError(String const& msg) {std::cerr << msg << std::endl;abort();
}
#endif// //
// //
// //
// class Value::CZString
// //
// //
// //// Notes: policy_ indicates if the string was allocated when
// a string is stored./*CZString类构造函数实现*/Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}Value::CZString::CZString(char const* str, unsigned length,DuplicationPolicy allocate): cstr_(str) {// allocate != duplicatestorage_.policy_ = allocate & 0x3;storage_.length_ = length & 0x3FFFFFFF;
}/*拷贝构造函数*/
Value::CZString::CZString(const CZString& other) {/*如果other的存储策略为不允许复制的化,则使用同一片存储空间,如果申请一块新的内存空间将other的值拷贝到该空间并返回空间地址*/cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr? duplicateStringValue(other.cstr_, other.storage_.length_): other.cstr_);storage_.policy_ =static_cast<unsigned>(other.cstr_? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==noDuplication? noDuplication: duplicate): static_cast<DuplicationPolicy>(other.storage_.policy_)) &3U;storage_.length_ = other.storage_.length_;
}/*移动构造函数*/
Value::CZString::CZString(CZString&& other) noexcept: cstr_(other.cstr_), index_(other.index_) {other.cstr_ = nullptr;
}/*析构函数*/
Value::CZString::~CZString() {if (cstr_ && storage_.policy_ == duplicate) { /*析构函数中只有policy为duplicate时才能释放分配的内存空间*/releaseStringValue(const_cast<char*>(cstr_),storage_.length_ + 1U); // +1 for null terminating// character for sake of// completeness but not actually// necessary}
}void Value::CZString::swap(CZString& other) {std::swap(cstr_, other.cstr_);std::swap(index_, other.index_);
}/*赋值运算符*/
Value::CZString& Value::CZString::operator=(const CZString& other) {cstr_ = other.cstr_;index_ = other.index_;return *this;
}/*移动赋值运算符*/
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {cstr_ = other.cstr_;index_ = other.index_;other.cstr_ = nullptr;return *this;
}/*因为Value类的map中的键值为CZString类,所以CZString类必须实现比较运算符*/
/*<运算符*/
bool Value::CZString::operator<(const CZString& other) const {if (!cstr_) /*如果cstr_无效则直接比较index*/return index_ < other.index_;// return strcmp(cstr_, other.cstr_) < 0;// Assume both are strings.unsigned this_len = this->storage_.length_;unsigned other_len = other.storage_.length_;/*取两者之间长度最小的长度作为比较长度*/unsigned min_len = std::min<unsigned>(this_len, other_len);JSON_ASSERT(this->cstr_ && other.cstr_);int comp = memcmp(this->cstr_, other.cstr_, min_len);if (comp < 0)return true;if (comp > 0)return false;return (this_len < other_len);
}/*==运算符*/
bool Value::CZString::operator==(const CZString& other) const {if (!cstr_) /*如果cstr_无效则直接比较index*/return index_ == other.index_;// return strcmp(cstr_, other.cstr_) == 0;// Assume both are strings.unsigned this_len = this->storage_.length_;unsigned other_len = other.storage_.length_;if (this_len != other_len)return false;JSON_ASSERT(this->cstr_ && other.cstr_);int comp = memcmp(this->cstr_, other.cstr_, this_len);return comp == 0;
}ArrayIndex Value::CZString::index() const { return index_; }// const char* Value::CZString::c_str() const { return cstr_; }
const char* Value::CZString::data() const { return cstr_; }
unsigned Value::CZString::length() const { return storage_.length_; }
bool Value::CZString::isStaticString() const {return storage_.policy_ == noDuplication;
}// //
// //
// //
// class Value::Value
// //
// //
// ///*! \internal Default constructor initialization must be equivalent to:* memset( this, 0, sizeof(Value) )* This optimization is used in ValueInternalMap fast allocator.*/
/*Value类构造函数实现*/
Value::Value(ValueType type) {static char const emptyString[] = "";initBasic(type);switch (type) {case nullValue:break;case intValue:case uintValue:value_.int_ = 0;break;case realValue:value_.real_ = 0.0;break;case stringValue:// allocated_ == false, so this is safe.value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));break;case arrayValue:case objectValue:value_.map_ = new ObjectValues();break;case booleanValue:value_.bool_ = false;break;default:JSON_ASSERT_UNREACHABLE;}
}Value::Value(Int value) {initBasic(intValue);value_.int_ = value;
}Value::Value(UInt value) {initBasic(uintValue);value_.uint_ = value;
}
#if defined(JSON_HAS_INT64)
Value::Value(Int64 value) {initBasic(intValue);value_.int_ = value;
}
Value::Value(UInt64 value) {initBasic(uintValue);value_.uint_ = value;
}
#endif // defined(JSON_HAS_INT64)Value::Value(double value) {initBasic(realValue);value_.real_ = value;
}Value::Value(const char* value) {initBasic(stringValue, true);JSON_ASSERT_MESSAGE(value != nullptr,"Null Value Passed to Value Constructor");/*存在前缀即字符串的长度*/value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value))/*使用C++的强制类型转换*/);
}Value::Value(const char* begin, const char* end) {initBasic(stringValue, true);value_.string_ =duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
}Value::Value(const String& value) {initBasic(stringValue, true);value_.string_ = duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
}#ifdef JSONCPP_HAS_STRING_VIEW
Value::Value(std::string_view value) {initBasic(stringValue, true);value_.string_ = duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
}
#endifValue::Value(const StaticString& value) {initBasic(stringValue);value_.string_ = const_cast<char*>(value.c_str());
}Value::Value(bool value) {initBasic(booleanValue);value_.bool_ = value;
}/*拷贝构造函数*/
Value::Value(const Value& other) {dupPayload(other);dupMeta(other);
}/*移动构造函数*/
Value::Value(Value&& other) noexcept {initBasic(nullValue);swap(other);
}/*析构函数*/
Value::~Value() {releasePayload();value_.uint_ = 0;
}/*赋值运算符*/
Value& Value::operator=(const Value& other) {Value(other).swap(*this);return *this;
}/*移动赋值运算符*/
Value& Value::operator=(Value&& other) noexcept {other.swap(*this);return *this;
}/*交换bits和value数据成员*/
void Value::swapPayload(Value& other) {std::swap(bits_, other.bits_);std::swap(value_, other.value_);
}void Value::copyPayload(const Value& other) {/*释放this中存放的数据*/releasePayload(); dupPayload(other);
}/*实现Value类的swap函数*/
void Value::swap(Value& other) {swapPayload(other);std::swap(comments_, other.comments_);std::swap(start_, other.start_);std::swap(limit_, other.limit_);
}void Value::copy(const Value& other) {copyPayload(other);dupMeta(other);
}ValueType Value::type() const {return static_cast<ValueType>(bits_.value_type_);
}int Value::compare(const Value& other) const {if (*this < other)return -1;if (*this > other)return 1;return 0;
}/*<运算符*/
bool Value::operator<(const Value& other) const {int typeDelta = type() - other.type();if (typeDelta) /*类型不同原则上不能进行比较*/return typeDelta < 0; switch (type()) {case nullValue:return false;case intValue:return value_.int_ < other.value_.int_;case uintValue:return value_.uint_ < other.value_.uint_;case realValue:return value_.real_ < other.value_.real_;case booleanValue:return value_.bool_ < other.value_.bool_;case stringValue: {if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {return other.value_.string_ != nullptr;}unsigned this_len;unsigned other_len;char const* this_str;char const* other_str;decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,&this_str);decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,&other_str);/*感觉具有一定的意义,先比较min长度部分的字符,再根据长度来判断*/unsigned min_len = std::min<unsigned>(this_len, other_len);JSON_ASSERT(this_str && other_str);int comp = memcmp(this_str, other_str, min_len);if (comp < 0)return true;if (comp > 0)return false;return (this_len < other_len);}case arrayValue:case objectValue: {auto thisSize = value_.map_->size();auto otherSize = other.value_.map_->size();if (thisSize != otherSize)return thisSize < otherSize;return (*value_.map_) < (*other.value_.map_);}default:JSON_ASSERT_UNREACHABLE;}return false; // unreachable
}/*下面运算符的实现基于前面的<小于运算符*/
bool Value::operator<=(const Value& other) const { return !(other < *this); }bool Value::operator>=(const Value& other) const { return !(*this < other); }bool Value::operator>(const Value& other) const { return other < *this; }bool Value::operator==(const Value& other) const {if (type() != other.type())return false; /*原则上类型相同才能进行比较*/switch (type()) {case nullValue:return true;case intValue:return value_.int_ == other.value_.int_;case uintValue:return value_.uint_ == other.value_.uint_;case realValue:return value_.real_ == other.value_.real_;case booleanValue:return value_.bool_ == other.value_.bool_;case stringValue: {if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {return (value_.string_ == other.value_.string_);}unsigned this_len;unsigned other_len;char const* this_str;char const* other_str;decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,&this_str);decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,&other_str);if (this_len != other_len)return false;JSON_ASSERT(this_str && other_str);int comp = memcmp(this_str, other_str, this_len);return comp == 0;}case arrayValue:case objectValue:return value_.map_->size() == other.value_.map_->size() &&(*value_.map_) == (*other.value_.map_);default:JSON_ASSERT_UNREACHABLE;}return false; // unreachable
}bool Value::operator!=(const Value& other) const { return !(*this == other); }/*返回Value中的字符串类型的数据*/
const char* Value::asCString() const {JSON_ASSERT_MESSAGE(type() == stringValue,"in Json::Value::asCString(): requires stringValue");if (value_.string_ == nullptr)return nullptr;unsigned this_len;char const* this_str;/*返回解码出有效字符串的位置*/decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,&this_str);return this_str;
}#if JSONCPP_USE_SECURE_MEMORY
unsigned Value::getCStringLength() const {JSON_ASSERT_MESSAGE(type() == stringValue,"in Json::Value::asCString(): requires stringValue");if (value_.string_ == 0)return 0;unsigned this_len;char const* this_str;decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,&this_str);return this_len;
}
#endif/*
返回Value中字符串类型数据的起始和结束位置
注意:begin和end为二级指针
*/
bool Value::getString(char const** begin, char const** end) const {if (type() != stringValue)return false;if (value_.string_ == nullptr)return false;unsigned length;decodePrefixedString(this->isAllocated(), this->value_.string_, &length,begin);*end = *begin + length;return true;
}#ifdef JSONCPP_HAS_STRING_VIEW
bool Value::getString(std::string_view* str) const {if (type() != stringValue)return false;if (value_.string_ == nullptr)return false;const char* begin;unsigned length;decodePrefixedString(this->isAllocated(), this->value_.string_, &length,&begin);*str = std::string_view(begin, length);return true;
}
#endif/*返回的类型为String*/
String Value::asString() const {switch (type()) {case nullValue:return "";case stringValue: {if (value_.string_ == nullptr)return "";unsigned this_len;char const* this_str;decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,&this_str);/*返回匿名对象String*/return String(this_str, this_len); }case booleanValue:return value_.bool_ ? "true" : "false";case intValue:return valueToString(value_.int_);case uintValue:return valueToString(value_.uint_);case realValue:return valueToString(value_.real_);default:JSON_FAIL_MESSAGE("Type is not convertible to string");}
}/*返回的类型为int*/
Value::Int Value::asInt() const {switch (type()) {case intValue:JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");return Int(value_.int_);case uintValue:JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");return Int(value_.uint_);case realValue:JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),"double out of Int range");return Int(value_.real_);case nullValue:return 0;case booleanValue:return value_.bool_ ? 1 : 0;default:break;}JSON_FAIL_MESSAGE("Value is not convertible to Int.");
}/*返回的类型为uint*/
Value::UInt Value::asUInt() const {switch (type()) {case intValue:JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");return UInt(value_.int_);case uintValue:JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");return UInt(value_.uint_);case realValue:JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt),"double out of UInt range");return UInt(value_.real_);case nullValue:return 0;case booleanValue:return value_.bool_ ? 1 : 0;default:break;}JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
}#if defined(JSON_HAS_INT64)Value::Int64 Value::asInt64() const {switch (type()) {case intValue:return Int64(value_.int_);case uintValue:JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");return Int64(value_.uint_);case realValue:// If the double value is in proximity to minInt64, it will be rounded to// minInt64. The correct value in this scenario is indeterminableJSON_ASSERT_MESSAGE(value_.real_ != minInt64,"Double value is minInt64, precise value cannot be determined");JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),"double out of Int64 range");return Int64(value_.real_);case nullValue:return 0;case booleanValue:return value_.bool_ ? 1 : 0;default:break;}JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
}Value::UInt64 Value::asUInt64() const {switch (type()) {case intValue:JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");return UInt64(value_.int_);case uintValue:return UInt64(value_.uint_);case realValue:JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt64),"double out of UInt64 range");return UInt64(value_.real_);case nullValue:return 0;case booleanValue:return value_.bool_ ? 1 : 0;default:break;}JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
}
#endif // if defined(JSON_HAS_INT64)LargestInt Value::asLargestInt() const {
#if defined(JSON_NO_INT64)return asInt();
#elsereturn asInt64();
#endif
}LargestUInt Value::asLargestUInt() const {
#if defined(JSON_NO_INT64)return asUInt();
#elsereturn asUInt64();
#endif
}double Value::asDouble() const {switch (type()) {case intValue:return static_cast<double>(value_.int_);case uintValue:
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)return static_cast<double>(value_.uint_);
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)return integerToDouble(value_.uint_);
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)case realValue:return value_.real_;case nullValue:return 0.0; /*空指针返回0.0*/case booleanValue:return value_.bool_ ? 1.0 : 0.0; /*bool类型*/default:break;}JSON_FAIL_MESSAGE("Value is not convertible to double.");
}float Value::asFloat() const {switch (type()) {case intValue:return static_cast<float>(value_.int_);case uintValue:
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)return static_cast<float>(value_.uint_);
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)// This can fail (silently?) if the value is bigger than MAX_FLOAT.return static_cast<float>(integerToDouble(value_.uint_));
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)case realValue:return static_cast<float>(value_.real_);case nullValue:return 0.0;case booleanValue:return value_.bool_ ? 1.0F : 0.0F;default:break;}JSON_FAIL_MESSAGE("Value is not convertible to float.");
}/*将value的值返回为bool类型*/
bool Value::asBool() const {switch (type()) {case booleanValue:return value_.bool_;case nullValue:return false;case intValue:return value_.int_ != 0;case uintValue:return value_.uint_ != 0;case realValue: {// According to JavaScript language zero or NaN is regarded as false/*NaN(Not a Number)是浮点数的特殊值,表示“未定义或不可表示的数值”(如 0/0、sqrt(-1))。在布尔上下文中,NaN会被隐式转换为false,但这是通过operator bool()的隐式转换规则实现的,而非直接比较。std::fpclassify是C++标准库(<cmath>)中的一个函数,用于对浮点数进行分类,判断其属于哪一类特殊值(如正常数、零、无穷大、NaN 等)。它是处理浮点数状态检测的核心工具之一。*//*浮点数是否为bool的判断方法*/const auto value_classification = std::fpclassify(value_.real_);return value_classification != FP_ZERO && value_classification != FP_NAN;}default:break;}JSON_FAIL_MESSAGE("Value is not convertible to bool.");
}/*Value的值能够转换为other的类型*/
bool Value::isConvertibleTo(ValueType other) const {switch (other) {case nullValue:return (isNumeric() && asDouble() == 0.0) ||(type() == booleanValue && !value_.bool_)/*bool类型,值为false*/ ||(type() == stringValue && asString().empty())/*字符串类型,为空*/ ||(type() == arrayValue && value_.map_->empty()) ||(type() == objectValue && value_.map_->empty()) ||type() == nullValue;case intValue:return isInt() ||(type() == realValue && InRange(value_.real_, minInt, maxInt)) ||type() == booleanValue || type() == nullValue;case uintValue:return isUInt() ||(type() == realValue && InRange(value_.real_, 0u, maxUInt)) ||type() == booleanValue || type() == nullValue;case realValue:return isNumeric() || type() == booleanValue || type() == nullValue;case booleanValue:return isNumeric() || type() == booleanValue || type() == nullValue;case stringValue:return isNumeric() || type() == booleanValue || type() == stringValue ||type() == nullValue;case arrayValue:return type() == arrayValue || type() == nullValue;case objectValue:return type() == objectValue || type() == nullValue;}JSON_ASSERT_UNREACHABLE;return false;
}/// Number of values in array or object
ArrayIndex Value::size() const {switch (type()) {case nullValue:case intValue:case uintValue:case realValue:case booleanValue:case stringValue:return 0;case arrayValue: // size of the array is highest index + 1if (!value_.map_->empty()) { /*map中存在数据*/ObjectValues::const_iterator itLast = value_.map_->end();--itLast;return (*itLast).first.index() + 1; /*+1?? index是从0开始计数*/}return 0;case objectValue:return ArrayIndex(value_.map_->size());}JSON_ASSERT_UNREACHABLE;return 0; // unreachable;
}bool Value::empty() const {if (isNull() || isArray() || isObject())return size() == 0U;return false;
}/*强制类型转换操作符bool*/
Value::operator bool() const { return !isNull(); }void Value::clear() {JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||type() == objectValue,"in Json::Value::clear(): requires complex value");start_ = 0;limit_ = 0;switch (type()) {case arrayValue:case objectValue:value_.map_->clear();break;default:break;}
}void Value::resize(ArrayIndex newSize) {JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,"in Json::Value::resize(): requires arrayValue");if (type() == nullValue)*this = Value(arrayValue);ArrayIndex oldSize = size();if (newSize == 0)clear();else if (newSize > oldSize)for (ArrayIndex i = oldSize; i < newSize; ++i)(*this)[i]; /*下标运算符的操作*/else {for (ArrayIndex index = newSize; index < oldSize; ++index) {value_.map_->erase(index);}JSON_ASSERT(size() == newSize);}
}/*[]下标运算符,通过index来查找对应下面四个函数构成下标运算符[]的重载
*/
Value& Value::operator[](ArrayIndex index) {JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,"in Json::Value::operator[](ArrayIndex): requires arrayValue");if (type() == nullValue)*this = Value(arrayValue);CZString key(index); /*使用index初始化CZString key*/auto it = value_.map_->lower_bound(key); /*再从map中查找key,那么类需要实现<等比较运算符*/if (it != value_.map_->end() && (*it).first == key)return (*it).second; /*返回key对应的Value值*//*没有找到则构造一个默认初始化的pair<key,value>到map中*/ObjectValues::value_type defaultValue(key, nullSingleton());it = value_.map_->insert(it, defaultValue);return (*it).second;
}/*[]下标运算符重载,这个[]调用前面实现的[]运算符*/
Value& Value::operator[](int index) {JSON_ASSERT_MESSAGE(index >= 0,"in Json::Value::operator[](int index): index cannot be negative");return (*this)[ArrayIndex(index)]; /*将index强转为ArrayIndex来调用前面实现的下标运算符[]*/
}const Value& Value::operator[](ArrayIndex index) const {JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");if (type() == nullValue)return nullSingleton();CZString key(index);ObjectValues::const_iterator it = value_.map_->find(key);if (it == value_.map_->end())return nullSingleton();return (*it).second;
}const Value& Value::operator[](int index) const {JSON_ASSERT_MESSAGE(index >= 0,"in Json::Value::operator[](int index) const: index cannot be negative");return (*this)[ArrayIndex(index)];
}void Value::initBasic(ValueType type, bool allocated) {setType(type);setIsAllocated(allocated);comments_ = Comments{}; /*匿名对象*/start_ = 0;limit_ = 0;
}void Value::dupPayload(const Value& other) {setType(other.type());setIsAllocated(false);switch (type()) {case nullValue:case intValue:case uintValue:case realValue:case booleanValue:value_ = other.value_;break;case stringValue:if (other.value_.string_ && other.isAllocated()) {unsigned len;char const* str;decodePrefixedString(other.isAllocated(), other.value_.string_, &len,&str);value_.string_ = duplicateAndPrefixStringValue(str, len);setIsAllocated(true);} else {value_.string_ = other.value_.string_;}break;case arrayValue:case objectValue:value_.map_ = new ObjectValues(*other.value_.map_);break;default:JSON_ASSERT_UNREACHABLE;}
}void Value::releasePayload() {switch (type()) {case nullValue:case intValue:case uintValue:case realValue:case booleanValue:break;case stringValue:if (isAllocated())releasePrefixedStringValue(value_.string_);break;case arrayValue:case objectValue:delete value_.map_; //使用new分配的空间,这里使用delete进行释放break;default:JSON_ASSERT_UNREACHABLE;}
}void Value::dupMeta(const Value& other) {comments_ = other.comments_;start_ = other.start_;limit_ = other.limit_;
}// Access an object value by name, create a null member if it does not exist.
// @pre Type of '*this' is object or null.
// @param key is null-terminated.
Value& Value::resolveReference(const char* key) {JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,"in Json::Value::resolveReference(): requires objectValue");if (type() == nullValue)*this = Value(objectValue);CZString actualKey(key, static_cast<unsigned>(strlen(key)),CZString::noDuplication); /*policy为noDuplication,不进行空间分配*/auto it = value_.map_->lower_bound(actualKey);if (it != value_.map_->end() && (*it).first == actualKey)return (*it).second;ObjectValues::value_type defaultValue(actualKey, nullSingleton());it = value_.map_->insert(it, defaultValue);Value& value = (*it).second;return value;
}// @param key is not null-terminated.
Value& Value::resolveReference(char const* key, char const* end) {JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,"in Json::Value::resolveReference(key, end): requires objectValue");if (type() == nullValue)*this = Value(objectValue);CZString actualKey(key, static_cast<unsigned>(end - key),CZString::duplicateOnCopy);auto it = value_.map_->lower_bound(actualKey);if (it != value_.map_->end() && (*it).first == actualKey)return (*it).second;ObjectValues::value_type defaultValue(actualKey, nullSingleton());it = value_.map_->insert(it, defaultValue);Value& value = (*it).second;return value;
}Value Value::get(ArrayIndex index, const Value& defaultValue) const {const Value* value = &((*this)[index]);return value == &nullSingleton() ? defaultValue : *value;
}bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }Value const* Value::find(char const* begin, char const* end) const {JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,"in Json::Value::find(begin, end): requires ""objectValue or nullValue");if (type() == nullValue)return nullptr;CZString actualKey(begin, static_cast<unsigned>(end - begin),CZString::noDuplication);ObjectValues::const_iterator it = value_.map_->find(actualKey);if (it == value_.map_->end())return nullptr;return &(*it).second;
}Value const* Value::find(const String& key) const {return find(key.data(), key.data() + key.length());
}Value const* Value::findNull(const String& key) const {return findValue<Value, &Value::isNull>(key);
}
Value const* Value::findBool(const String& key) const {return findValue<Value, &Value::isBool>(key);
}
Value const* Value::findInt(const String& key) const {return findValue<Value, &Value::isInt>(key);
}
Value const* Value::findInt64(const String& key) const {return findValue<Value, &Value::isInt64>(key);
}
Value const* Value::findUInt(const String& key) const {return findValue<Value, &Value::isUInt>(key);
}
Value const* Value::findUInt64(const String& key) const {return findValue<Value, &Value::isUInt64>(key);
}
Value const* Value::findIntegral(const String& key) const {return findValue<Value, &Value::isIntegral>(key);
}
Value const* Value::findDouble(const String& key) const {return findValue<Value, &Value::isDouble>(key);
}
Value const* Value::findNumeric(const String& key) const {return findValue<Value, &Value::isNumeric>(key);
}
Value const* Value::findString(const String& key) const {return findValue<Value, &Value::isString>(key);
}
Value const* Value::findArray(const String& key) const {return findValue<Value, &Value::isArray>(key);
}
Value const* Value::findObject(const String& key) const {return findValue<Value, &Value::isObject>(key);
}Value* Value::demand(char const* begin, char const* end) {JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,"in Json::Value::demand(begin, end): requires ""objectValue or nullValue");return &resolveReference(begin, end);
}
#ifdef JSONCPP_HAS_STRING_VIEW
const Value& Value::operator[](std::string_view key) const {Value const* found = find(key.data(), key.data() + key.length());if (!found)return nullSingleton();return *found;
}
Value& Value::operator[](std::string_view key) {return resolveReference(key.data(), key.data() + key.length());
}
#else/*const Value& 和 Value const& 写法上是等价的表示两者都表示一个对Value类型对象的常量引用
*/
const Value& Value::operator[](const char* key) const {Value const* found = find(key, key + strlen(key));if (!found)return nullSingleton();return *found;
}Value const& Value::operator[](const String& key) const {Value const* found = find(key);if (!found)return nullSingleton();return *found;
}Value& Value::operator[](const char* key) {return resolveReference(key, key + strlen(key));
}Value& Value::operator[](const String& key) {return resolveReference(key.data(), key.data() + key.length());
}
#endifValue& Value::operator[](const StaticString& key) {return resolveReference(key.c_str());
}Value& Value::append(const Value& value) { return append(Value(value)); }Value& Value::append(Value&& value) {JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,"in Json::Value::append: requires arrayValue");if (type() == nullValue) {*this = Value(arrayValue);}return this->value_.map_->emplace(size(), std::move(value)).first->second;
}bool Value::insert(ArrayIndex index, const Value& newValue) {return insert(index, Value(newValue));
}bool Value::insert(ArrayIndex index, Value&& newValue) {JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,"in Json::Value::insert: requires arrayValue");ArrayIndex length = size();if (index > length) { /*越界判断*/return false;}/*length处的数据是不是丢失了????*/for (ArrayIndex i = length; i > index; i--) {(*this)[i] = std::move((*this)[i - 1]);}(*this)[index] = std::move(newValue);return true;
}Value Value::get(char const* begin, char const* end,Value const& defaultValue) const {Value const* found = find(begin, end);return !found ? defaultValue : *found;
}
#ifdef JSONCPP_HAS_STRING_VIEW
Value Value::get(std::string_view key, const Value& defaultValue) const {return get(key.data(), key.data() + key.length(), defaultValue);
}
#else
Value Value::get(char const* key, Value const& defaultValue) const {return get(key, key + strlen(key), defaultValue);
}
Value Value::get(String const& key, Value const& defaultValue) const {return get(key.data(), key.data() + key.length(), defaultValue);
}
#endifbool Value::removeMember(const char* begin, const char* end, Value* removed) {if (type() != objectValue) {return false;}CZString actualKey(begin, static_cast<unsigned>(end - begin),CZString::noDuplication);auto it = value_.map_->find(actualKey);if (it == value_.map_->end())return false;if (removed)*removed = std::move(it->second);value_.map_->erase(it);return true;
}
#ifdef JSONCPP_HAS_STRING_VIEW
bool Value::removeMember(std::string_view key, Value* removed) {return removeMember(key.data(), key.data() + key.length(), removed);
}
#else
bool Value::removeMember(const char* key, Value* removed) {return removeMember(key, key + strlen(key), removed);
}
bool Value::removeMember(String const& key, Value* removed) {return removeMember(key.data(), key.data() + key.length(), removed);
}
#endif#ifdef JSONCPP_HAS_STRING_VIEW
void Value::removeMember(std::string_view key) {JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,"in Json::Value::removeMember(): requires objectValue");if (type() == nullValue)return;CZString actualKey(key.data(), unsigned(key.length()),CZString::noDuplication);value_.map_->erase(actualKey);
}
#else
void Value::removeMember(const char* key) {JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,"in Json::Value::removeMember(): requires objectValue");if (type() == nullValue)return;CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);value_.map_->erase(actualKey);
}
void Value::removeMember(const String& key) { removeMember(key.c_str()); }
#endifbool Value::removeIndex(ArrayIndex index, Value* removed) {if (type() != arrayValue) {return false;}CZString key(index);auto it = value_.map_->find(key);if (it == value_.map_->end()) {return false;}if (removed)*removed = std::move(it->second);ArrayIndex oldSize = size();// shift left all items left, into the place of the "removed"for (ArrayIndex i = index; i < (oldSize - 1); ++i) {CZString keey(i);(*value_.map_)[keey] = (*this)[i + 1];}// erase the last one ("leftover")CZString keyLast(oldSize - 1);auto itLast = value_.map_->find(keyLast);value_.map_->erase(itLast);return true;
}bool Value::isMember(char const* begin, char const* end) const {Value const* value = find(begin, end);return nullptr != value;
}
#ifdef JSONCPP_HAS_STRING_VIEW
bool Value::isMember(std::string_view key) const {return isMember(key.data(), key.data() + key.length());
}
#else
bool Value::isMember(char const* key) const {return isMember(key, key + strlen(key));
}
bool Value::isMember(String const& key) const {return isMember(key.data(), key.data() + key.length());
}
#endifValue::Members Value::getMemberNames() const {JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,"in Json::Value::getMemberNames(), value must be objectValue");if (type() == nullValue)return Value::Members();Members members;members.reserve(value_.map_->size());ObjectValues::const_iterator it = value_.map_->begin();ObjectValues::const_iterator itEnd = value_.map_->end();for (; it != itEnd; ++it) {members.push_back(String((*it).first.data(), (*it).first.length()));}return members;
}/*
modf是C/C++标准库中的一个数学函数,用于分解浮点数为整数部分和小数部分,两部分的符号与原浮点数相同。
double modf(double x, double* intpart);
float modff(float x, float* intpart);
long double modfl(long double x, long double* intpart);
*/static bool IsIntegral(double d) {double integral_part;/*将浮点数d的整数部分和小数部分进行拆分后来判断小数部分是不是等于0.0*/return modf(d, &integral_part) == 0.0;
}bool Value::isNull() const { return type() == nullValue; }bool Value::isBool() const { return type() == booleanValue; }bool Value::isInt() const {switch (type()) {case intValue:
#if defined(JSON_HAS_INT64)return value_.int_ >= minInt && value_.int_ <= maxInt;
#elsereturn true;
#endifcase uintValue:return value_.uint_ <= UInt(maxInt);case realValue:return value_.real_ >= minInt && value_.real_ <= maxInt &&IsIntegral(value_.real_); /*整数*/default:break;}return false;
}bool Value::isUInt() const {switch (type()) {case intValue:
#if defined(JSON_HAS_INT64)return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
#elsereturn value_.int_ >= 0;
#endifcase uintValue:
#if defined(JSON_HAS_INT64)return value_.uint_ <= maxUInt;
#elsereturn true;
#endifcase realValue:return value_.real_ >= 0 && value_.real_ <= maxUInt &&IsIntegral(value_.real_);default:break;}return false;
}bool Value::isInt64() const {
#if defined(JSON_HAS_INT64)switch (type()) {case intValue:return true;case uintValue:return value_.uint_ <= UInt64(maxInt64);case realValue:// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a// double, so double(maxInt64) will be rounded up to 2^63. Therefore we// require the value to be strictly less than the limit.// minInt64 is -2^63 which can be represented as a double, but since double// values in its proximity are also rounded to -2^63, we require the value// to be strictly greater than the limit to avoid returning 'true' for// values that are not in the rangereturn value_.real_ > double(minInt64) && value_.real_ < double(maxInt64) &&IsIntegral(value_.real_);default:break;}
#endif // JSON_HAS_INT64return false;
}bool Value::isUInt64() const {
#if defined(JSON_HAS_INT64)switch (type()) {case intValue:return value_.int_ >= 0;case uintValue:return true;case realValue:// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we// require the value to be strictly less than the limit.return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&IsIntegral(value_.real_);default:break;}
#endif // JSON_HAS_INT64return false;
}bool Value::isIntegral() const {switch (type()) {case intValue:case uintValue:return true;case realValue:
#if defined(JSON_HAS_INT64)// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we// require the value to be strictly less than the limit.// minInt64 is -2^63 which can be represented as a double, but since double// values in its proximity are also rounded to -2^63, we require the value// to be strictly greater than the limit to avoid returning 'true' for// values that are not in the rangereturn value_.real_ > double(minInt64) &&value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
#elsereturn value_.real_ >= minInt && value_.real_ <= maxUInt &&IsIntegral(value_.real_);
#endif // JSON_HAS_INT64default:break;}return false;
}bool Value::isDouble() const {/*整数也算double*/return type() == intValue || type() == uintValue || type() == realValue;
}bool Value::isNumeric() const { return isDouble(); }bool Value::isString() const { return type() == stringValue; }bool Value::isArray() const { return type() == arrayValue; }bool Value::isObject() const { return type() == objectValue; }Value::Comments::Comments(const Comments& that): ptr_{cloneUnique(that.ptr_)} {}Value::Comments::Comments(Comments&& that) noexcept: ptr_{std::move(that.ptr_)} {}Value::Comments& Value::Comments::operator=(const Comments& that) {ptr_ = cloneUnique(that.ptr_);return *this;
}Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {ptr_ = std::move(that.ptr_);return *this;
}bool Value::Comments::has(CommentPlacement slot) const {return ptr_ && !(*ptr_)[slot].empty();
}String Value::Comments::get(CommentPlacement slot) const {if (!ptr_)return {};return (*ptr_)[slot];
}void Value::Comments::set(CommentPlacement slot, String comment) {if (slot >= CommentPlacement::numberOfCommentPlacement)return;if (!ptr_)ptr_ = std::unique_ptr<Array>(new Array());(*ptr_)[slot] = std::move(comment);
}void Value::setComment(String comment, CommentPlacement placement) {if (!comment.empty() && (comment.back() == '\n')) {// Always discard trailing newline, to aid indentation.comment.pop_back();}JSON_ASSERT_MESSAGE(comment.empty() || comment[0] == '/',"in Json::Value::setComment(): Comments must start with /");comments_.set(placement, std::move(comment));
}bool Value::hasComment(CommentPlacement placement) const {return comments_.has(placement);
}String Value::getComment(CommentPlacement placement) const {return comments_.get(placement);
}void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }ptrdiff_t Value::getOffsetStart() const { return start_; }ptrdiff_t Value::getOffsetLimit() const { return limit_; }String Value::toStyledString() const {StreamWriterBuilder builder;String out = this->hasComment(commentBefore) ? "\n" : "";out += Json::writeString(builder, *this);out += '\n';return out;
}Value::const_iterator Value::begin() const {switch (type()) {case arrayValue:case objectValue:if (value_.map_)return const_iterator(value_.map_->begin());break;default:break;}return {};
}Value::const_iterator Value::end() const {switch (type()) {case arrayValue:case objectValue:if (value_.map_)return const_iterator(value_.map_->end());break;default:break;}return {};
}Value::iterator Value::begin() {switch (type()) {case arrayValue:case objectValue:if (value_.map_)return iterator(value_.map_->begin());break;default:break;}return iterator();
}Value::iterator Value::end() {switch (type()) {case arrayValue:case objectValue:if (value_.map_)return iterator(value_.map_->end());break;default:break;}return iterator();
}// class PathArgument
// //PathArgument::PathArgument() = default;PathArgument::PathArgument(ArrayIndex index): index_(index), kind_(kindIndex) {}PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {}// class Path
// //Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,const PathArgument& a3, const PathArgument& a4,const PathArgument& a5) {InArgs in;in.reserve(5);in.push_back(&a1);in.push_back(&a2);in.push_back(&a3);in.push_back(&a4);in.push_back(&a5);makePath(path, in);
}void Path::makePath(const String& path, const InArgs& in) {const char* current = path.c_str();const char* end = current + path.length();auto itInArg = in.begin();while (current != end) {if (*current == '[') {++current;if (*current == '%')addPathInArg(path, in, itInArg, PathArgument::kindIndex);else {ArrayIndex index = 0;for (; current != end && *current >= '0' && *current <= '9'; ++current)index = index * 10 + ArrayIndex(*current - '0');args_.push_back(index);}if (current == end || *++current != ']')invalidPath(path, int(current - path.c_str()));} else if (*current == '%') {addPathInArg(path, in, itInArg, PathArgument::kindKey);++current;} else if (*current == '.' || *current == ']') {++current;} else {const char* beginName = current;while (current != end && !strchr("[.", *current))++current;args_.push_back(String(beginName, current));}}
}void Path::addPathInArg(const String& /*path*/, const InArgs& in,InArgs::const_iterator& itInArg,PathArgument::Kind kind) {if (itInArg == in.end()) {// Error: missing argument %d} else if ((*itInArg)->kind_ != kind) {// Error: bad argument type} else {args_.push_back(**itInArg++);}
}void Path::invalidPath(const String& /*path*/, int /*location*/) {// Error: invalid path.
}const Value& Path::resolve(const Value& root) const {const Value* node = &root;for (const auto& arg : args_) {if (arg.kind_ == PathArgument::kindIndex) {if (!node->isArray() || !node->isValidIndex(arg.index_)) {// Error: unable to resolve path (array value expected at position... )return Value::nullSingleton();}node = &((*node)[arg.index_]);} else if (arg.kind_ == PathArgument::kindKey) {if (!node->isObject()) {// Error: unable to resolve path (object value expected at position...)return Value::nullSingleton();}node = &((*node)[arg.key_]);if (node == &Value::nullSingleton()) {// Error: unable to resolve path (object has no member named '' at// position...)return Value::nullSingleton();}}}return *node;
}Value Path::resolve(const Value& root, const Value& defaultValue) const {const Value* node = &root;for (const auto& arg : args_) {if (arg.kind_ == PathArgument::kindIndex) {if (!node->isArray() || !node->isValidIndex(arg.index_))return defaultValue;node = &((*node)[arg.index_]);} else if (arg.kind_ == PathArgument::kindKey) {if (!node->isObject())return defaultValue;node = &((*node)[arg.key_]);if (node == &Value::nullSingleton())return defaultValue;}}return *node;
}Value& Path::make(Value& root) const {Value* node = &root;for (const auto& arg : args_) {if (arg.kind_ == PathArgument::kindIndex) {if (!node->isArray()) {// Error: node is not an array at position ...}node = &((*node)[arg.index_]);} else if (arg.kind_ == PathArgument::kindKey) {if (!node->isObject()) {// Error: node is not an object at position...}node = &((*node)[arg.key_]);}}return *node;
}} // namespace Json
json_reader.cpp内容如下:
// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors
// Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
// 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#if !defined(JSON_IS_AMALGAMATION)
#include "json_tool.h"
#include <json/assertions.h>
#include <json/reader.h>
#include <json/value.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstring>
#include <iostream>
#include <istream>
#include <limits>
#include <memory>
#include <set>
#include <sstream>
#include <utility>#include <cstdio>#if defined(_MSC_VER)
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
#endif //_MSC_VER#if defined(_MSC_VER)
// Disable warning about strdup being deprecated.
#pragma warning(disable : 4996)
#endif// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
// time to change the stack limit
#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
#define JSONCPP_DEPRECATED_STACK_LIMIT 1000
#endifstatic size_t const stackLimit_g =JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()namespace Json {using CharReaderPtr = std::unique_ptr<CharReader>;// Implementation of class Features
// Features::Features() = default;Features Features::all() { return {}; }Features Features::strictMode() {Features features;features.allowComments_ = false;features.strictRoot_ = true;features.allowDroppedNullPlaceholders_ = false;features.allowNumericKeys_ = false;return features;
}// Implementation of class Reader
// /*内部使用了lambda表达式*/
bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
}// Class Reader
// //Reader::Reader() : features_(Features::all()) {}Reader::Reader(const Features& features) : features_(features) {}/*parse函数重载*/
bool Reader::parse(const std::string& document, Value& root,bool collectComments) {document_.assign(document.begin(), document.end());const char* begin = document_.c_str();const char* end = begin + document_.length();return parse(begin, end, root, collectComments);
}bool Reader::parse(std::istream& is, Value& root, bool collectComments) {// std::istream_iterator<char> begin(is);// std::istream_iterator<char> end;// Those would allow streamed input from a file, if parse() were a// template function.// Since String is reference-counted, this at least does not// create an extra copy.String doc(std::istreambuf_iterator<char>(is), {});return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
}/*JSON数据解析*/
bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,bool collectComments) {if (!features_.allowComments_) {collectComments = false;}begin_ = beginDoc;end_ = endDoc;collectComments_ = collectComments;current_ = begin_;lastValueEnd_ = nullptr;lastValue_ = nullptr;commentsBefore_.clear();errors_.clear();while (!nodes_.empty()) /*nodes不为空,这将nodes中数据pop()出去*/nodes_.pop();nodes_.push(&root); /*将root入栈*//*readValue中进行递归的解析*/bool successful = readValue();Token token;readTokenSkippingComments(token);if (collectComments_ && !commentsBefore_.empty())root.setComment(commentsBefore_, commentAfter);if (features_.strictRoot_) {/*有效的JSON数据必须是对象或者数字值*/if (!root.isArray() && !root.isObject()) {// Set error location to start of doc, ideally should be first token found// in doctoken.type_ = tokenError;token.start_ = beginDoc;token.end_ = endDoc;addError("A valid JSON document must be either an array or an object value.",token);return false;}}return successful;
}bool Reader::readValue() {// readValue() may call itself only if it calls readObject() or ReadArray().// These methods execute nodes_.push() just before and nodes_.pop)() just// after calling readValue(). parse() executes one nodes_.push(), so > instead// of >=.if (nodes_.size() > stackLimit_g)throwRuntimeError("Exceeded stackLimit in readValue().");Token token;/*读取JSON数据中的token,跳过其中的注释内容,即不获取注释内容*/readTokenSkippingComments(token);bool successful = true;if (collectComments_ && !commentsBefore_.empty()) {currentValue().setComment(commentsBefore_, commentBefore);commentsBefore_.clear();}/*识别出JSON token类型*/switch (token.type_) {case tokenObjectBegin: /*{*/successful = readObject(token);currentValue().setOffsetLimit(current_ - begin_);break;case tokenArrayBegin: /*[*/successful = readArray(token);currentValue().setOffsetLimit(current_ - begin_);break;case tokenNumber: /*数值*/successful = decodeNumber(token);break;case tokenString: /*字符串*/successful = decodeString(token);break;case tokenTrue: { /*bool类型*/Value v(true); /*直接使用true初始化*/currentValue().swapPayload(v);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);} break;case tokenFalse: {Value v(false); /*直接使用false初始化*/currentValue().swapPayload(v);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);} break;case tokenNull: {Value v;currentValue().swapPayload(v);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);} break;case tokenArraySeparator: /*,*/case tokenObjectEnd: /*}*/case tokenArrayEnd: /*]*/if (features_.allowDroppedNullPlaceholders_) {// "Un-read" the current token and mark the current value as a null// token.current_--;Value v;currentValue().swapPayload(v);currentValue().setOffsetStart(current_ - begin_ - 1);currentValue().setOffsetLimit(current_ - begin_);break;} // Else, fall through...default:currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);return addError("Syntax error: value, object or array expected.", token);}if (collectComments_) {lastValueEnd_ = current_;lastValue_ = ¤tValue();}return successful;
}/*读取JSON数据中的token,跳过其中的注释内容,即不获取注释内容*/
bool Reader::readTokenSkippingComments(Token& token) {/*JSON token读取,token内容存放在参数token中*/bool success = readToken(token);if (features_.allowComments_) {/*判断读到的token是否为注释内容,如果为注释内容的话继续读token直到不为注释内容*/while (success && token.type_ == tokenComment) {success = readToken(token);}}return success;
}/*将JSON数据每个单元数据解析出来*/
bool Reader::readToken(Token& token) {/*跳过开头的空白符*/skipSpaces();token.start_ = current_;Char c = getNextChar(); /*获取下一个字符内容*/bool ok = true;switch (c) {case '{':token.type_ = tokenObjectBegin;break;case '}':token.type_ = tokenObjectEnd;break;case '[':token.type_ = tokenArrayBegin;break;case ']':token.type_ = tokenArrayEnd;break;case '"':token.type_ = tokenString;ok = readString(); /*直到遇到"符号才退出*/break;case '/':token.type_ = tokenComment;ok = readComment();break;case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':case '-':token.type_ = tokenNumber;/*解析整数,小数,指数形式的数据*/readNumber();break;case 't':token.type_ = tokenTrue;ok = match("rue", 3);break;case 'f':token.type_ = tokenFalse;ok = match("alse", 4);break;case 'n':token.type_ = tokenNull;ok = match("ull", 3);break;case ',':token.type_ = tokenArraySeparator; /*分割符*/break;case ':':token.type_ = tokenMemberSeparator; /*age": 30,*/break;case 0:token.type_ = tokenEndOfStream;break;default:ok = false;break;}if (!ok)token.type_ = tokenError;token.end_ = current_;return ok;
}/*跳过开头的空白符*/
void Reader::skipSpaces() {while (current_ != end_) {Char c = *current_;if (c == ' ' || c == '\t' || c == '\r' || c == '\n')++current_;elsebreak;}
}/*匹配比较*/
bool Reader::match(const Char* pattern, int patternLength) {if (end_ - current_ < patternLength)return false;int index = patternLength;while (index--)if (current_[index] != pattern[index])return false;current_ += patternLength;return true;
}/*读取注释内容*/
bool Reader::readComment() {Location commentBegin = current_ - 1; /*commentBegin指向/*/Char c = getNextChar();bool successful = false;if (c == '*') // /**/风格的注释内容successful = readCStyleComment();else if (c == '/') /* //风格的注释内容 */successful = readCppStyleComment();if (!successful)return false;if (collectComments_) {CommentPlacement placement = commentBefore;if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {if (c != '*' || !containsNewLine(commentBegin, current_))placement = commentAfterOnSameLine;}/*记录注释部分的内容*/addComment(commentBegin, current_, placement);}return true;
}/*这里体现了C++ string操作的便捷*/
String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {String normalized;normalized.reserve(static_cast<size_t>(end - begin));Reader::Location current = begin;while (current != end) {char c = *current++;if (c == '\r') {if (current != end && *current == '\n')// convert dos EOL++current;// convert Mac EOLnormalized += '\n';} else {normalized += c;}}return normalized;
}void Reader::addComment(Location begin, Location end,CommentPlacement placement) {assert(collectComments_);/*将注释内容存放到normalized string中*/const String& normalized = normalizeEOL(begin, end);if (placement == commentAfterOnSameLine) {assert(lastValue_ != nullptr);lastValue_->setComment(normalized, placement);} else {commentsBefore_ += normalized;}
}// /**/风格的注释内容
bool Reader::readCStyleComment() {while ((current_ + 1) < end_) { /*这里判断current_+1 < end是因为最后的判断是判断的两个字符*和/ */Char c = getNextChar();if (c == '*' && *current_ == '/') //直到遇到注释的后半部分 */ 才退出break;}return getNextChar() == '/';
}/* //风格的注释内容 */
bool Reader::readCppStyleComment() {while (current_ != end_) {Char c = getNextChar(); /*以回车换行作为结束判断依据*/if (c == '\n')break;if (c == '\r') {// Consume DOS EOL. It will be normalized in addComment.if (current_ != end_ && *current_ == '\n') /*\r\n*/getNextChar();// Break on Moc OS 9 EOL.break;}}return true;
}/*解析整数,小数,指数形式的数据*/
void Reader::readNumber() {Location p = current_;char c = '0'; // stopgap for already consumed character// integral part/*整数部分*/while (c >= '0' && c <= '9')c = (current_ = p) < end_ ? *p++ : '\0';// fractional part/*小数部分*/if (c == '.') {c = (current_ = p) < end_ ? *p++ : '\0';while (c >= '0' && c <= '9')c = (current_ = p) < end_ ? *p++ : '\0';}// exponential part/*指数部分*/if (c == 'e' || c == 'E') {c = (current_ = p) < end_ ? *p++ : '\0';if (c == '+' || c == '-')c = (current_ = p) < end_ ? *p++ : '\0';while (c >= '0' && c <= '9')c = (current_ = p) < end_ ? *p++ : '\0';}
}/*获取"..."中的数据*/
bool Reader::readString() {Char c = '\0';while (current_ != end_) {c = getNextChar();if (c == '\\') /*\符号后面一般情况下后面接转义字符*/getNextChar(); /*没有获取字符数据,说明转义字符不处理*/else if (c == '"')break; /*直到"才退出*/}return c == '"';
}/*读对象数据*/
bool Reader::readObject(Token& token) {Token tokenName;String name;Value init(objectValue);currentValue().swapPayload(init);/*token起始位置相对于begin_的偏移量*/currentValue().setOffsetStart(token.start_ - begin_);/*读取JSON中的token 键值对集合(对象)数据,跳过注释内容*/while (readTokenSkippingComments(tokenName)) {if (tokenName.type_ == tokenObjectEnd && name.empty()) // { } 空objreturn true;name.clear();if (tokenName.type_ == tokenString) {if (!decodeString(tokenName, name)) /*对string中的数据进行解码,注意:需要对其中的转义字符进行处理*/return recoverFromError(tokenObjectEnd);} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {Value numberName;if (!decodeNumber(tokenName, numberName)) /*解码数据*/return recoverFromError(tokenObjectEnd);name = numberName.asString();} else {break; /*退出循环*/}Token colon; /*colon 冒号 :*/if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {return addErrorAndRecover("Missing ':' after object member name", colon,tokenObjectEnd);}/*Value类的下标运算符,如果[]中的数据不存在则默认初始化插入数据到map中,并返回插入的数据的引用,便于修改操作上面部分将json中键值对集合(对象){"key":value}中键值数据name解析出来,其作为Value的下标[name]插入到map中name数据其实已经保存到的map中,下面需要解析value的值并将其存入map中即可*/Value& value = currentValue()[name];nodes_.push(&value); /*需要设置哪个Value的内容就需要先将其放入到nodes_栈中*/bool ok = readValue(); /*获取其数据,递归获取JSON中的数据*/nodes_.pop(); /*弹出nodes_栈*/if (!ok) // error already setreturn recoverFromError(tokenObjectEnd);Token comma; /*comma 逗号 ,*/if (!readTokenSkippingComments(comma) ||(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {return addErrorAndRecover("Missing ',' or '}' in object declaration",comma, tokenObjectEnd);}if (comma.type_ == tokenObjectEnd)return true;}return addErrorAndRecover("Missing '}' or object member name", tokenName,tokenObjectEnd);
}/*读数组数据*/
bool Reader::readArray(Token& token) {Value init(arrayValue); /*变量init初始化*/currentValue().swapPayload(init);currentValue().setOffsetStart(token.start_ - begin_);skipSpaces();if (current_ != end_ && *current_ == ']') // empty array{Token endArray;readToken(endArray);return true;}int index = 0;for (;;) {Value& value = currentValue()[index++]; /*Value类的下标运算符[]*/nodes_.push(&value);bool ok = readValue();nodes_.pop();if (!ok) // error already setreturn recoverFromError(tokenArrayEnd);Token currentToken;// Accept Comment after last item in the array.ok = readTokenSkippingComments(currentToken);bool badTokenType = (currentToken.type_ != tokenArraySeparator &¤tToken.type_ != tokenArrayEnd);if (!ok || badTokenType) {return addErrorAndRecover("Missing ',' or ']' in array declaration",currentToken, tokenArrayEnd);}if (currentToken.type_ == tokenArrayEnd)break;}return true;
}bool Reader::decodeNumber(Token& token) {Value decoded;if (!decodeNumber(token, decoded))return false;currentValue().swapPayload(decoded);currentValue().setOffsetStart(token.start_ - begin_); /*Value开始相对于JSON数据开始位置的偏移*/currentValue().setOffsetLimit(token.end_ - begin_); /*Value结束相对于JSON数据结束位置的偏移*/return true;
}bool Reader::decodeNumber(Token& token, Value& decoded) {// Attempts to parse the number as an integer. If the number is// larger than the maximum supported value of an integer then// we decode the number as a double./*尝试将解析数据为整数,如果数据比整数的最大值还大则解码为浮点数,此时存在精度的丢失但是总比溢出好*/Location current = token.start_;bool isNegative = *current == '-';if (isNegative)++current;// TODO: Help the compiler do the div and mod at compile time or get rid of// them.Value::LargestUInt maxIntegerValue =isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 /*有符号数的最大值*/: Value::maxLargestUInt; /*无符号数的最大值*//*设置一个门限值,超过门限值*/Value::LargestUInt threshold = maxIntegerValue / 10; /*丢弃个数上的数值*/Value::LargestUInt value = 0;while (current < token.end_) {Char c = *current++;/*JSON整数或浮点数,不支持八进制或十六进制前缀(如 0x)*/if (c < '0' || c > '9') /*视为浮点数处理*/return decodeDouble(token, decoded);auto digit(static_cast<Value::UInt>(c - '0')); /*这是一个变量的定义,C++ 非常让人无解的地方*/if (value >= threshold) { /*累积的value超过门限值*/// We've hit or exceeded the max value divided by 10 (rounded down). If// a) we've only just touched the limit, b) this is the last digit, and// c) it's small enough to fit in that rounding delta, we're okay.// Otherwise treat this number as a double to avoid overflow.if (value > threshold || current != token.end_ ||digit > maxIntegerValue % 10 /*digit比最大值个位上数据还大,必然溢出*/) {return decodeDouble(token, decoded); /*视为浮点数处理,会丢失精度*/}}value = value * 10 + digit;}if (isNegative && value == maxIntegerValue)decoded = Value::minLargestInt;else if (isNegative)decoded = -Value::LargestInt(value);else if (value <= Value::LargestUInt(Value::maxInt))decoded = Value::LargestInt(value);elsedecoded = value;return true;
}bool Reader::decodeDouble(Token& token) {Value decoded;if (!decodeDouble(token, decoded))return false;currentValue().swapPayload(decoded);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);return true;
}bool Reader::decodeDouble(Token& token, Value& decoded) {double value = 0;IStringStream is(String(token.start_, token.end_));if (!(is >> value)) { /*double时出错*/if (value == std::numeric_limits<double>::max())value = std::numeric_limits<double>::infinity(); /*正无穷大*/else if (value == std::numeric_limits<double>::lowest())value = -std::numeric_limits<double>::infinity(); /*负无穷大*/else if (!std::isinf(value)) /*std::isinf 是 C++ 标准库 <cmath> 中提供的函数,用于检测一个浮点数是否为无穷大(Infinity)。*/return addError("'" + String(token.start_, token.end_) + "' is not a number.", token);}decoded = value; /*隐式类型转换*/return true;
}bool Reader::decodeString(Token& token) {String decoded_string;if (!decodeString(token, decoded_string))return false;Value decoded(decoded_string);currentValue().swapPayload(decoded);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);return true;
}/*注意:需要对其中的转义字符进行处理*/
bool Reader::decodeString(Token& token, String& decoded) {/*-2,"..."去除开始和结束的两个"符号*/decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));Location current = token.start_ + 1; // skip '"'Location end = token.end_ - 1; // do not include '"'while (current != end) {Char c = *current++;if (c == '"')break;if (c == '\\') { /*转义字符的处理*/if (current == end)return addError("Empty escape sequence in string", token, current);Char escape = *current++;switch (escape) { /*解析字符串中的转义字符*/case '"': // \"decoded += '"';break;case '/': // \/decoded += '/';break;case '\\': // \\decoded += '\\';break;case 'b': decoded += '\b';break;case 'f':decoded += '\f';break;case 'n':decoded += '\n';break;case 'r':decoded += '\r';break;case 't':decoded += '\t';break;
/*
在JSON(JavaScript Object Notation)中,\u是一种转义序列,用于表示Unicode字符。
它的作用是将Unicode码点(以十六进制表示)转换为对应的字符,
确保JSON数据可以包含各种语言的字符(如中文、表情符号等),同时保持纯文本格式的兼容性。
*/case 'u': { // \u:unicode编码unsigned int unicode;/*解码JSON中的unicode码*/if (!decodeUnicodeCodePoint(token, current, end, unicode))return false;decoded += codePointToUTF8(unicode); /*unicode码点转换为UTF-8*/} break;default:return addError("Bad escape sequence in string", token, current);}} else {decoded += c;}}return true;
}/*解码JSON中的unicode码*/
bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,Location end, unsigned int& unicode) {if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) /*解码4位16进制 unicode码*/return false;if (unicode >= 0xD800 && unicode <= 0xDBFF) {// surrogate pairs 代理对if (end - current < 6)return addError("additional six characters expected to parse unicode surrogate pair.",token, current);if (*(current++) == '\\' && *(current++) == 'u') {unsigned int surrogatePair;if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);} elsereturn false;} elsereturn addError("expecting another \\u token to begin the second half of ""a unicode surrogate pair",token, current);}return true;
}/*解码16进制 unicode码*/
bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,Location end,unsigned int& ret_unicode) {if (end - current < 4) /*非4位16进制则报错*/return addError("Bad unicode escape sequence in string: four digits expected.", token,current);int unicode = 0;for (int index = 0; index < 4; ++index) {Char c = *current++;unicode *= 16;if (c >= '0' && c <= '9')unicode += c - '0';else if (c >= 'a' && c <= 'f')unicode += c - 'a' + 10;else if (c >= 'A' && c <= 'F')unicode += c - 'A' + 10;elsereturn addError("Bad unicode escape sequence in string: hexadecimal digit expected.",token, current);}ret_unicode = static_cast<unsigned int>(unicode);return true;
}bool Reader::addError(const String& message, Token& token, Location extra) {ErrorInfo info;info.token_ = token;info.message_ = message;info.extra_ = extra;errors_.push_back(info);return false;
}bool Reader::recoverFromError(TokenType skipUntilToken) {size_t const errorCount = errors_.size();Token skip;for (;;) {if (!readToken(skip))errors_.resize(errorCount); // discard errors caused by recoveryif (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)break;}errors_.resize(errorCount);return false;
}bool Reader::addErrorAndRecover(const String& message, Token& token,TokenType skipUntilToken) {addError(message, token);return recoverFromError(skipUntilToken);
}Value& Reader::currentValue() { return *(nodes_.top()); }Reader::Char Reader::getNextChar() {if (current_ == end_)return 0;return *current_++;
}void Reader::getLocationLineAndColumn(Location location, int& line,int& column) const {Location current = begin_;Location lastLineStart = current;line = 0;while (current < location && current != end_) {Char c = *current++;if (c == '\r') {if (current != end_ && *current == '\n')++current;lastLineStart = current;++line;} else if (c == '\n') {lastLineStart = current;++line;}}// column & line start at 1column = int(location - lastLineStart) + 1;++line;
}String Reader::getLocationLineAndColumn(Location location) const {int line, column;getLocationLineAndColumn(location, line, column);char buffer[18 + 16 + 16 + 1];jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);return buffer;
}// Deprecated. Preserved for backward compatibility
String Reader::getFormatedErrorMessages() const {return getFormattedErrorMessages();
}String Reader::getFormattedErrorMessages() const {String formattedMessage;for (const auto& error : errors_) {formattedMessage +="* " + getLocationLineAndColumn(error.token_.start_) + "\n";formattedMessage += " " + error.message_ + "\n";if (error.extra_)formattedMessage +="See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";}return formattedMessage;
}std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {std::vector<Reader::StructuredError> allErrors;for (const auto& error : errors_) {Reader::StructuredError structured;structured.offset_start = error.token_.start_ - begin_;structured.offset_limit = error.token_.end_ - begin_;structured.message = error.message_;allErrors.push_back(structured);}return allErrors;
}bool Reader::pushError(const Value& value, const String& message) {ptrdiff_t const length = end_ - begin_;if (value.getOffsetStart() > length || value.getOffsetLimit() > length)return false;Token token;token.type_ = tokenError;token.start_ = begin_ + value.getOffsetStart();token.end_ = begin_ + value.getOffsetLimit();ErrorInfo info;info.token_ = token;info.message_ = message;info.extra_ = nullptr;errors_.push_back(info);return true;
}bool Reader::pushError(const Value& value, const String& message,const Value& extra) {ptrdiff_t const length = end_ - begin_;if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||extra.getOffsetLimit() > length)return false;Token token;token.type_ = tokenError;token.start_ = begin_ + value.getOffsetStart();token.end_ = begin_ + value.getOffsetLimit();ErrorInfo info;info.token_ = token;info.message_ = message;info.extra_ = begin_ + extra.getOffsetStart();errors_.push_back(info);return true;
}bool Reader::good() const { return errors_.empty(); }// Originally copied from the Features class (now deprecated), used internally
// for features implementation.
class OurFeatures {
public:static OurFeatures all();bool allowComments_;bool allowTrailingCommas_;bool strictRoot_;bool allowDroppedNullPlaceholders_;bool allowNumericKeys_;bool allowSingleQuotes_;bool failIfExtra_;bool rejectDupKeys_;bool allowSpecialFloats_;bool skipBom_;size_t stackLimit_;
}; // OurFeaturesOurFeatures OurFeatures::all() { return {}; }// Implementation of class Reader
// // Originally copied from the Reader class (now deprecated), used internally
// for implementing JSON reading.
/*最初是从Reader类(现已弃用)复制的,目前仅用于内部实现JSON读取功能。*/
class OurReader {
public:using Char = char;using Location = const Char*;explicit OurReader(OurFeatures const& features);bool parse(const char* beginDoc, const char* endDoc, Value& root,bool collectComments = true);String getFormattedErrorMessages() const;std::vector<CharReader::StructuredError> getStructuredErrors() const;private:OurReader(OurReader const&); // no implvoid operator=(OurReader const&); // no implenum TokenType {tokenEndOfStream = 0,tokenObjectBegin,tokenObjectEnd,tokenArrayBegin,tokenArrayEnd,tokenString,tokenNumber,tokenTrue,tokenFalse,tokenNull,tokenNaN,tokenPosInf,tokenNegInf,tokenArraySeparator,tokenMemberSeparator,tokenComment,tokenError};class Token {public:TokenType type_;Location start_;Location end_;};class ErrorInfo {public:Token token_;String message_;Location extra_;};using Errors = std::deque<ErrorInfo>;bool readToken(Token& token);bool readTokenSkippingComments(Token& token);void skipSpaces();void skipBom(bool skipBom);bool match(const Char* pattern, int patternLength);bool readComment();bool readCStyleComment(bool* containsNewLineResult);bool readCppStyleComment();bool readString();bool readStringSingleQuote();bool readNumber(bool checkInf);bool readValue();bool readObject(Token& token);bool readArray(Token& token);bool decodeNumber(Token& token);bool decodeNumber(Token& token, Value& decoded);bool decodeString(Token& token);bool decodeString(Token& token, String& decoded);bool decodeDouble(Token& token);bool decodeDouble(Token& token, Value& decoded);bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,unsigned int& unicode);bool decodeUnicodeEscapeSequence(Token& token, Location& current,Location end, unsigned int& unicode);bool addError(const String& message, Token& token, Location extra = nullptr);bool recoverFromError(TokenType skipUntilToken);bool addErrorAndRecover(const String& message, Token& token,TokenType skipUntilToken);void skipUntilSpace();Value& currentValue();Char getNextChar();void getLocationLineAndColumn(Location location, int& line,int& column) const;String getLocationLineAndColumn(Location location) const;void addComment(Location begin, Location end, CommentPlacement placement);static String normalizeEOL(Location begin, Location end);static bool containsNewLine(Location begin, Location end);using Nodes = std::stack<Value*>;Nodes nodes_{};Errors errors_{};String document_{};Location begin_ = nullptr;Location end_ = nullptr;Location current_ = nullptr;Location lastValueEnd_ = nullptr;Value* lastValue_ = nullptr;bool lastValueHasAComment_ = false;String commentsBefore_{};OurFeatures const features_;bool collectComments_ = false;
}; // OurReader// complete copy of Read impl, for OurReaderbool OurReader::containsNewLine(OurReader::Location begin,OurReader::Location end) {return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
}OurReader::OurReader(OurFeatures const& features) : features_(features) {}bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,bool collectComments) {if (!features_.allowComments_) {collectComments = false;}begin_ = beginDoc;end_ = endDoc;collectComments_ = collectComments;current_ = begin_;lastValueEnd_ = nullptr;lastValue_ = nullptr;commentsBefore_.clear();errors_.clear();while (!nodes_.empty())nodes_.pop();nodes_.push(&root);// skip byte order mark if it exists at the beginning of the UTF-8 text.skipBom(features_.skipBom_);bool successful = readValue();nodes_.pop();Token token;readTokenSkippingComments(token);if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {addError("Extra non-whitespace after JSON value.", token);return false;}if (collectComments_ && !commentsBefore_.empty())root.setComment(commentsBefore_, commentAfter);if (features_.strictRoot_) {if (!root.isArray() && !root.isObject()) {// Set error location to start of doc, ideally should be first token found// in doctoken.type_ = tokenError;token.start_ = beginDoc;token.end_ = endDoc;addError("A valid JSON document must be either an array or an object value.",token);return false;}}return successful;
}bool OurReader::readValue() {// To preserve the old behaviour we cast size_t to int.if (nodes_.size() > features_.stackLimit_)throwRuntimeError("Exceeded stackLimit in readValue().");Token token;readTokenSkippingComments(token);bool successful = true;if (collectComments_ && !commentsBefore_.empty()) {currentValue().setComment(commentsBefore_, commentBefore);commentsBefore_.clear();}switch (token.type_) {case tokenObjectBegin:successful = readObject(token);currentValue().setOffsetLimit(current_ - begin_);break;case tokenArrayBegin:successful = readArray(token);currentValue().setOffsetLimit(current_ - begin_);break;case tokenNumber:successful = decodeNumber(token);break;case tokenString:successful = decodeString(token);break;case tokenTrue: {Value v(true);currentValue().swapPayload(v);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);} break;case tokenFalse: {Value v(false);currentValue().swapPayload(v);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);} break;case tokenNull: {Value v;currentValue().swapPayload(v);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);} break;case tokenNaN: {Value v(std::numeric_limits<double>::quiet_NaN());currentValue().swapPayload(v);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);} break;case tokenPosInf: {Value v(std::numeric_limits<double>::infinity());currentValue().swapPayload(v);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);} break;case tokenNegInf: {Value v(-std::numeric_limits<double>::infinity());currentValue().swapPayload(v);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);} break;case tokenArraySeparator:case tokenObjectEnd:case tokenArrayEnd:if (features_.allowDroppedNullPlaceholders_) {// "Un-read" the current token and mark the current value as a null// token.current_--;Value v;currentValue().swapPayload(v);currentValue().setOffsetStart(current_ - begin_ - 1);currentValue().setOffsetLimit(current_ - begin_);break;} // else, fall through ...default:currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);return addError("Syntax error: value, object or array expected.", token);}if (collectComments_) {lastValueEnd_ = current_;lastValueHasAComment_ = false;lastValue_ = ¤tValue();}return successful;
}bool OurReader::readTokenSkippingComments(Token& token) {bool success = readToken(token);if (features_.allowComments_) {while (success && token.type_ == tokenComment) {success = readToken(token);}}return success;
}bool OurReader::readToken(Token& token) {skipSpaces();token.start_ = current_;Char c = getNextChar();bool ok = true;switch (c) {case '{':token.type_ = tokenObjectBegin;break;case '}':token.type_ = tokenObjectEnd;break;case '[':token.type_ = tokenArrayBegin;break;case ']':token.type_ = tokenArrayEnd;break;case '"':token.type_ = tokenString;ok = readString();break;case '\'':if (features_.allowSingleQuotes_) {token.type_ = tokenString;ok = readStringSingleQuote();} else {// If we don't allow single quotes, this is a failure case.ok = false;}break;case '/':token.type_ = tokenComment;ok = readComment();break;case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':token.type_ = tokenNumber;readNumber(false);break;case '-':if (readNumber(true)) {token.type_ = tokenNumber;} else {token.type_ = tokenNegInf;ok = features_.allowSpecialFloats_ && match("nfinity", 7);}break;case '+':if (readNumber(true)) {token.type_ = tokenNumber;} else {token.type_ = tokenPosInf;ok = features_.allowSpecialFloats_ && match("nfinity", 7);}break;case 't':token.type_ = tokenTrue;ok = match("rue", 3);break;case 'f':token.type_ = tokenFalse;ok = match("alse", 4);break;case 'n':token.type_ = tokenNull;ok = match("ull", 3);break;case 'N':if (features_.allowSpecialFloats_) {token.type_ = tokenNaN;ok = match("aN", 2);} else {ok = false;}break;case 'I':if (features_.allowSpecialFloats_) {token.type_ = tokenPosInf;ok = match("nfinity", 7);} else {ok = false;}break;case ',':token.type_ = tokenArraySeparator;break;case ':':token.type_ = tokenMemberSeparator;break;case 0:token.type_ = tokenEndOfStream;break;default:ok = false;break;}if (!ok)token.type_ = tokenError;token.end_ = current_;return ok;
}void OurReader::skipSpaces() {while (current_ != end_) {Char c = *current_;if (c == ' ' || c == '\t' || c == '\r' || c == '\n')++current_;elsebreak;}
}void OurReader::skipBom(bool skipBom) {// The default behavior is to skip BOM.if (skipBom) {if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {begin_ += 3;current_ = begin_;}}
}bool OurReader::match(const Char* pattern, int patternLength) {if (end_ - current_ < patternLength)return false;int index = patternLength;while (index--)if (current_[index] != pattern[index])return false;current_ += patternLength;return true;
}bool OurReader::readComment() {const Location commentBegin = current_ - 1;const Char c = getNextChar();bool successful = false;bool cStyleWithEmbeddedNewline = false;const bool isCStyleComment = (c == '*');const bool isCppStyleComment = (c == '/');if (isCStyleComment) {successful = readCStyleComment(&cStyleWithEmbeddedNewline);} else if (isCppStyleComment) {successful = readCppStyleComment();}if (!successful)return false;if (collectComments_) {CommentPlacement placement = commentBefore;if (!lastValueHasAComment_) {if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {if (isCppStyleComment || !cStyleWithEmbeddedNewline) {placement = commentAfterOnSameLine;lastValueHasAComment_ = true;}}}addComment(commentBegin, current_, placement);}return true;
}String OurReader::normalizeEOL(OurReader::Location begin,OurReader::Location end) {String normalized;normalized.reserve(static_cast<size_t>(end - begin));OurReader::Location current = begin;while (current != end) {char c = *current++;if (c == '\r') {if (current != end && *current == '\n')// convert dos EOL++current;// convert Mac EOLnormalized += '\n';} else {normalized += c;}}return normalized;
}void OurReader::addComment(Location begin, Location end,CommentPlacement placement) {assert(collectComments_);const String& normalized = normalizeEOL(begin, end);if (placement == commentAfterOnSameLine) {assert(lastValue_ != nullptr);lastValue_->setComment(normalized, placement);} else {commentsBefore_ += normalized;}
}bool OurReader::readCStyleComment(bool* containsNewLineResult) {*containsNewLineResult = false;while ((current_ + 1) < end_) {Char c = getNextChar();if (c == '*' && *current_ == '/')break;if (c == '\n')*containsNewLineResult = true;}return getNextChar() == '/';
}bool OurReader::readCppStyleComment() {while (current_ != end_) {Char c = getNextChar();if (c == '\n')break;if (c == '\r') {// Consume DOS EOL. It will be normalized in addComment.if (current_ != end_ && *current_ == '\n')getNextChar();// Break on Moc OS 9 EOL.break;}}return true;
}bool OurReader::readNumber(bool checkInf) {Location p = current_;if (checkInf && p != end_ && *p == 'I') {current_ = ++p;return false;}char c = '0'; // stopgap for already consumed character// integral partwhile (c >= '0' && c <= '9')c = (current_ = p) < end_ ? *p++ : '\0';// fractional partif (c == '.') {c = (current_ = p) < end_ ? *p++ : '\0';while (c >= '0' && c <= '9')c = (current_ = p) < end_ ? *p++ : '\0';}// exponential partif (c == 'e' || c == 'E') {c = (current_ = p) < end_ ? *p++ : '\0';if (c == '+' || c == '-')c = (current_ = p) < end_ ? *p++ : '\0';while (c >= '0' && c <= '9')c = (current_ = p) < end_ ? *p++ : '\0';}return true;
}
bool OurReader::readString() {Char c = 0;while (current_ != end_) {c = getNextChar();if (c == '\\')getNextChar();else if (c == '"')break;}return c == '"';
}bool OurReader::readStringSingleQuote() {Char c = 0;while (current_ != end_) {c = getNextChar();if (c == '\\')getNextChar();else if (c == '\'')break;}return c == '\'';
}bool OurReader::readObject(Token& token) {Token tokenName;String name;Value init(objectValue);currentValue().swapPayload(init);currentValue().setOffsetStart(token.start_ - begin_);while (readTokenSkippingComments(tokenName)) {if (tokenName.type_ == tokenObjectEnd &&(name.empty() ||features_.allowTrailingCommas_)) // empty object or trailing commareturn true;name.clear();if (tokenName.type_ == tokenString) {if (!decodeString(tokenName, name))return recoverFromError(tokenObjectEnd);} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {Value numberName;if (!decodeNumber(tokenName, numberName))return recoverFromError(tokenObjectEnd);name = numberName.asString();} else {break;}if (name.length() >= (1U << 30))throwRuntimeError("keylength >= 2^30");if (features_.rejectDupKeys_ && currentValue().isMember(name)) {String msg = "Duplicate key: '" + name + "'";return addErrorAndRecover(msg, tokenName, tokenObjectEnd);}Token colon;if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {return addErrorAndRecover("Missing ':' after object member name", colon,tokenObjectEnd);}Value& value = currentValue()[name];nodes_.push(&value);bool ok = readValue();nodes_.pop();if (!ok) // error already setreturn recoverFromError(tokenObjectEnd);Token comma;if (!readTokenSkippingComments(comma) ||(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {return addErrorAndRecover("Missing ',' or '}' in object declaration",comma, tokenObjectEnd);}if (comma.type_ == tokenObjectEnd)return true;}return addErrorAndRecover("Missing '}' or object member name", tokenName,tokenObjectEnd);
}bool OurReader::readArray(Token& token) {Value init(arrayValue);currentValue().swapPayload(init);currentValue().setOffsetStart(token.start_ - begin_);int index = 0;for (;;) {skipSpaces();if (current_ != end_ && *current_ == ']' &&(index == 0 ||(features_.allowTrailingCommas_ &&!features_.allowDroppedNullPlaceholders_))) // empty array or trailing// comma{Token endArray;readToken(endArray);return true;}Value& value = currentValue()[index++];nodes_.push(&value);bool ok = readValue();nodes_.pop();if (!ok) // error already setreturn recoverFromError(tokenArrayEnd);Token currentToken;// Accept Comment after last item in the array.ok = readTokenSkippingComments(currentToken);bool badTokenType = (currentToken.type_ != tokenArraySeparator &¤tToken.type_ != tokenArrayEnd);if (!ok || badTokenType) {return addErrorAndRecover("Missing ',' or ']' in array declaration",currentToken, tokenArrayEnd);}if (currentToken.type_ == tokenArrayEnd)break;}return true;
}bool OurReader::decodeNumber(Token& token) {Value decoded;if (!decodeNumber(token, decoded))return false;currentValue().swapPayload(decoded);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);return true;
}bool OurReader::decodeNumber(Token& token, Value& decoded) {// Attempts to parse the number as an integer. If the number is// larger than the maximum supported value of an integer then// we decode the number as a double.Location current = token.start_;const bool isNegative = *current == '-';if (isNegative) {++current;}// We assume we can represent the largest and smallest integer types as// unsigned integers with separate sign. This is only true if they can fit// into an unsigned integer.static_assert(Value::maxLargestInt <= Value::maxLargestUInt,"Int must be smaller than UInt");// We need to convert minLargestInt into a positive number. The easiest way// to do this conversion is to assume our "threshold" value of minLargestInt// divided by 10 can fit in maxLargestInt when absolute valued. This should// be a safe assumption.static_assert(Value::minLargestInt <= -Value::maxLargestInt,"The absolute value of minLargestInt must be greater than or ""equal to maxLargestInt");static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,"The absolute value of minLargestInt must be only 1 magnitude ""larger than maxLargest Int");static constexpr Value::LargestUInt positive_threshold =Value::maxLargestUInt / 10;static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;// For the negative values, we have to be more careful. Since typically// -Value::minLargestInt will cause an overflow, we first divide by 10 and// then take the inverse. This assumes that minLargestInt is only a single// power of 10 different in magnitude, which we check above. For the last// digit, we take the modulus before negating for the same reason.static constexpr auto negative_threshold =Value::LargestUInt(-(Value::minLargestInt / 10));static constexpr auto negative_last_digit =Value::UInt(-(Value::minLargestInt % 10));const Value::LargestUInt threshold =isNegative ? negative_threshold : positive_threshold;const Value::UInt max_last_digit =isNegative ? negative_last_digit : positive_last_digit;Value::LargestUInt value = 0;while (current < token.end_) {Char c = *current++;if (c < '0' || c > '9')return decodeDouble(token, decoded);const auto digit(static_cast<Value::UInt>(c - '0'));if (value >= threshold) {// We've hit or exceeded the max value divided by 10 (rounded down). If// a) we've only just touched the limit, meaning value == threshold,// b) this is the last digit, or// c) it's small enough to fit in that rounding delta, we're okay.// Otherwise treat this number as a double to avoid overflow.if (value > threshold || current != token.end_ ||digit > max_last_digit) {return decodeDouble(token, decoded);}}value = value * 10 + digit;}if (isNegative) {// We use the same magnitude assumption here, just in case.const auto last_digit = static_cast<Value::UInt>(value % 10);decoded = -Value::LargestInt(value / 10) * 10 - last_digit;} else if (value <= Value::LargestUInt(Value::maxLargestInt)) {decoded = Value::LargestInt(value);} else {decoded = value;}return true;
}bool OurReader::decodeDouble(Token& token) {Value decoded;if (!decodeDouble(token, decoded))return false;currentValue().swapPayload(decoded);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);return true;
}bool OurReader::decodeDouble(Token& token, Value& decoded) {double value = 0;IStringStream is(String(token.start_, token.end_));if (!(is >> value)) {if (value == std::numeric_limits<double>::max())value = std::numeric_limits<double>::infinity();else if (value == std::numeric_limits<double>::lowest())value = -std::numeric_limits<double>::infinity();else if (!std::isinf(value))return addError("'" + String(token.start_, token.end_) + "' is not a number.", token);}decoded = value;return true;
}bool OurReader::decodeString(Token& token) {String decoded_string;if (!decodeString(token, decoded_string))return false;Value decoded(decoded_string);currentValue().swapPayload(decoded);currentValue().setOffsetStart(token.start_ - begin_);currentValue().setOffsetLimit(token.end_ - begin_);return true;
}bool OurReader::decodeString(Token& token, String& decoded) {decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));Location current = token.start_ + 1; // skip '"'Location end = token.end_ - 1; // do not include '"'while (current != end) {Char c = *current++;if (c == '"')break;if (c == '\\') {if (current == end)return addError("Empty escape sequence in string", token, current);Char escape = *current++;switch (escape) {case '"':decoded += '"';break;case '/':decoded += '/';break;case '\\':decoded += '\\';break;case 'b':decoded += '\b';break;case 'f':decoded += '\f';break;case 'n':decoded += '\n';break;case 'r':decoded += '\r';break;case 't':decoded += '\t';break;case 'u': {unsigned int unicode;if (!decodeUnicodeCodePoint(token, current, end, unicode))return false;decoded += codePointToUTF8(unicode);} break;default:return addError("Bad escape sequence in string", token, current);}} else {decoded += c;}}return true;
}bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,Location end, unsigned int& unicode) {if (!decodeUnicodeEscapeSequence(token, current, end, unicode))return false;if (unicode >= 0xD800 && unicode <= 0xDBFF) {// surrogate pairsif (end - current < 6)return addError("additional six characters expected to parse unicode surrogate pair.",token, current);if (*(current++) == '\\' && *(current++) == 'u') {unsigned int surrogatePair;if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);} elsereturn false;} elsereturn addError("expecting another \\u token to begin the second half of ""a unicode surrogate pair",token, current);}return true;
}bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,Location end,unsigned int& ret_unicode) {if (end - current < 4)return addError("Bad unicode escape sequence in string: four digits expected.", token,current);int unicode = 0;for (int index = 0; index < 4; ++index) {Char c = *current++;unicode *= 16;if (c >= '0' && c <= '9')unicode += c - '0';else if (c >= 'a' && c <= 'f')unicode += c - 'a' + 10;else if (c >= 'A' && c <= 'F')unicode += c - 'A' + 10;elsereturn addError("Bad unicode escape sequence in string: hexadecimal digit expected.",token, current);}ret_unicode = static_cast<unsigned int>(unicode);return true;
}bool OurReader::addError(const String& message, Token& token, Location extra) {ErrorInfo info;info.token_ = token;info.message_ = message;info.extra_ = extra;errors_.push_back(info);return false;
}bool OurReader::recoverFromError(TokenType skipUntilToken) {size_t errorCount = errors_.size();Token skip;for (;;) {if (!readToken(skip))errors_.resize(errorCount); // discard errors caused by recoveryif (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)break;}errors_.resize(errorCount);return false;
}bool OurReader::addErrorAndRecover(const String& message, Token& token,TokenType skipUntilToken) {addError(message, token);return recoverFromError(skipUntilToken);
}Value& OurReader::currentValue() { return *(nodes_.top()); }OurReader::Char OurReader::getNextChar() {if (current_ == end_)return 0;return *current_++;
}void OurReader::getLocationLineAndColumn(Location location, int& line,int& column) const {Location current = begin_;Location lastLineStart = current;line = 0;while (current < location && current != end_) {Char c = *current++;if (c == '\r') {if (current != end_ && *current == '\n')++current;lastLineStart = current;++line;} else if (c == '\n') {lastLineStart = current;++line;}}// column & line start at 1column = int(location - lastLineStart) + 1;++line;
}String OurReader::getLocationLineAndColumn(Location location) const {int line, column;getLocationLineAndColumn(location, line, column);char buffer[18 + 16 + 16 + 1];jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);return buffer;
}String OurReader::getFormattedErrorMessages() const {String formattedMessage;for (const auto& error : errors_) {formattedMessage +="* " + getLocationLineAndColumn(error.token_.start_) + "\n";formattedMessage += " " + error.message_ + "\n";if (error.extra_)formattedMessage +="See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";}return formattedMessage;
}std::vector<CharReader::StructuredError>
OurReader::getStructuredErrors() const {std::vector<CharReader::StructuredError> allErrors;for (const auto& error : errors_) {CharReader::StructuredError structured;structured.offset_start = error.token_.start_ - begin_;structured.offset_limit = error.token_.end_ - begin_;structured.message = error.message_;allErrors.push_back(structured);}return allErrors;
}/*OurCharReader公开继承CharReader*/
class OurCharReader : public CharReader {public:OurCharReader(bool collectComments, OurFeatures const& features): CharReader( /*使用派生类OurImpl*/std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}protected:/*OurImpl类公开继承于Impl类*/class OurImpl : public Impl {public:OurImpl(bool collectComments, OurFeatures const& features): collectComments_(collectComments), reader_(features) {}bool parse(char const* beginDoc, char const* endDoc, Value* root,String* errs) override {/*内部调用OurReader的parse*/bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);if (errs) {*errs = reader_.getFormattedErrorMessages();}return ok;}std::vector<CharReader::StructuredError>getStructuredErrors() const override {return reader_.getStructuredErrors();}private:bool const collectComments_;/*OurReader拷贝自Reader,其是实现JSON解析的关键*/OurReader reader_;};
};CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
CharReaderBuilder::~CharReaderBuilder() = default;/*返回的是CharReader类型的地址*/
CharReader* CharReaderBuilder::newCharReader() const {/*通过settings_来对features进行赋值*/bool collectComments = settings_["collectComments"].asBool();OurFeatures features = OurFeatures::all();features.allowComments_ = settings_["allowComments"].asBool();features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();features.strictRoot_ = settings_["strictRoot"].asBool();features.allowDroppedNullPlaceholders_ =settings_["allowDroppedNullPlaceholders"].asBool();features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();// Stack limit is always a size_t, so we get this as an unsigned int// regardless of it we have 64-bit integer support enabled.features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());features.failIfExtra_ = settings_["failIfExtra"].asBool();features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();features.skipBom_ = settings_["skipBom"].asBool();/*返回派生类OurCharReader*/return new OurCharReader(collectComments, features);
}bool CharReaderBuilder::validate(Json::Value* invalid) const {static const auto& valid_keys = *new std::set<String>{"collectComments","allowComments","allowTrailingCommas","strictRoot","allowDroppedNullPlaceholders","allowNumericKeys","allowSingleQuotes","stackLimit","failIfExtra","rejectDupKeys","allowSpecialFloats","skipBom",};for (auto si = settings_.begin(); si != settings_.end(); ++si) {auto key = si.name();if (valid_keys.count(key))continue;if (invalid)(*invalid)[key] = *si;elsereturn false;}return invalid ? invalid->empty() : true;
}Value& CharReaderBuilder::operator[](const String& key) {return settings_[key];
}
// static
void CharReaderBuilder::strictMode(Json::Value* settings) {//! [CharReaderBuilderStrictMode](*settings)["allowComments"] = false;(*settings)["allowTrailingCommas"] = false;(*settings)["strictRoot"] = true;(*settings)["allowDroppedNullPlaceholders"] = false;(*settings)["allowNumericKeys"] = false;(*settings)["allowSingleQuotes"] = false;(*settings)["stackLimit"] = 1000;(*settings)["failIfExtra"] = true;(*settings)["rejectDupKeys"] = true;(*settings)["allowSpecialFloats"] = false;(*settings)["skipBom"] = true;//! [CharReaderBuilderStrictMode]
}
// static
void CharReaderBuilder::setDefaults(Json::Value* settings) {//! [CharReaderBuilderDefaults](*settings)["collectComments"] = true;(*settings)["allowComments"] = true;(*settings)["allowTrailingCommas"] = true;(*settings)["strictRoot"] = false;(*settings)["allowDroppedNullPlaceholders"] = false;(*settings)["allowNumericKeys"] = false;(*settings)["allowSingleQuotes"] = false;(*settings)["stackLimit"] = 1000;(*settings)["failIfExtra"] = false;(*settings)["rejectDupKeys"] = false;(*settings)["allowSpecialFloats"] = false;(*settings)["skipBom"] = true;//! [CharReaderBuilderDefaults]
}
// static
void CharReaderBuilder::ecma404Mode(Json::Value* settings) {//! [CharReaderBuilderECMA404Mode](*settings)["allowComments"] = false;(*settings)["allowTrailingCommas"] = false;(*settings)["strictRoot"] = false;(*settings)["allowDroppedNullPlaceholders"] = false;(*settings)["allowNumericKeys"] = false;(*settings)["allowSingleQuotes"] = false;(*settings)["stackLimit"] = 1000;(*settings)["failIfExtra"] = true;(*settings)["rejectDupKeys"] = false;(*settings)["allowSpecialFloats"] = false;(*settings)["skipBom"] = false;//! [CharReaderBuilderECMA404Mode]
}std::vector<CharReader::StructuredError>
CharReader::getStructuredErrors() const {return _impl->getStructuredErrors();
}/*CharReader的解析函数*/
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,String* errs) {/*调用内部Impl类的parse*/ return _impl->parse(beginDoc, endDoc, root, errs);
}//
// global functionsbool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,String* errs) {OStringStream ssin;ssin << sin.rdbuf();String doc = std::move(ssin).str();char const* begin = doc.data();char const* end = begin + doc.size();// Note that we do not actually need a null-terminator.CharReaderPtr const reader(fact.newCharReader());return reader->parse(begin, end, root, errs);
}IStream& operator>>(IStream& sin, Value& root) {CharReaderBuilder b;String errs;bool ok = parseFromStream(b, sin, &root, &errs);if (!ok) {throwRuntimeError(errs);}return sin;
}} // namespace Json