summaryrefslogtreecommitdiff
path: root/third-party
diff options
context:
space:
mode:
Diffstat (limited to 'third-party')
-rw-r--r--third-party/fbson/FbsonDocument.h768
-rw-r--r--third-party/fbson/FbsonJsonParser.h748
-rw-r--r--third-party/fbson/FbsonStream.h173
-rw-r--r--third-party/fbson/FbsonUtil.h173
-rw-r--r--third-party/fbson/FbsonWriter.h438
-rw-r--r--third-party/rapidjson/document.h821
-rw-r--r--third-party/rapidjson/filestream.h46
-rw-r--r--third-party/rapidjson/internal/pow10.h54
-rw-r--r--third-party/rapidjson/internal/stack.h82
-rw-r--r--third-party/rapidjson/internal/strfunc.h24
-rw-r--r--third-party/rapidjson/license.txt19
-rw-r--r--third-party/rapidjson/prettywriter.h156
-rw-r--r--third-party/rapidjson/rapidjson.h525
-rw-r--r--third-party/rapidjson/reader.h683
-rw-r--r--third-party/rapidjson/stringbuffer.h49
-rw-r--r--third-party/rapidjson/writer.h241
16 files changed, 2700 insertions, 2300 deletions
diff --git a/third-party/fbson/FbsonDocument.h b/third-party/fbson/FbsonDocument.h
deleted file mode 100644
index 9850acf6c..000000000
--- a/third-party/fbson/FbsonDocument.h
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * Copyright (c) 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
-
-/*
- * This header defines FbsonDocument, FbsonKeyValue, and various value classes
- * which are derived from FbsonValue, and a forward iterator for container
- * values - essentially everything that is related to FBSON binary data
- * structures.
- *
- * Implementation notes:
- *
- * None of the classes in this header file can be instantiated directly (i.e.
- * you cannot create a FbsonKeyValue or FbsonValue object - all constructors
- * are declared non-public). We use the classes as wrappers on the packed FBSON
- * bytes (serialized), and cast the classes (types) to the underlying packed
- * byte array.
- *
- * For the same reason, we cannot define any FBSON value class to be virtual,
- * since we never call constructors, and will not instantiate vtbl and vptrs.
- *
- * Therefore, the classes are defined as packed structures (i.e. no data
- * alignment and padding), and the private member variables of the classes are
- * defined precisely in the same order as the FBSON spec. This ensures we
- * access the packed FBSON bytes correctly.
- *
- * The packed structures are highly optimized for in-place operations with low
- * overhead. The reads (and in-place writes) are performed directly on packed
- * bytes. There is no memory allocation at all at runtime.
- *
- * For updates/writes of values that will expand the original FBSON size, the
- * write will fail, and the caller needs to handle buffer increase.
- *
- * ** Iterator **
- * Both ObjectVal class and ArrayVal class have iterator type that you can use
- * to declare an iterator on a container object to go through the key-value
- * pairs or value list. The iterator has both non-const and const types.
- *
- * Note: iterators are forward direction only.
- *
- * ** Query **
- * Querying into containers is through the member functions find (for key/value
- * pairs) and get (for array elements), and is in streaming style. We don't
- * need to read/scan the whole FBSON packed bytes in order to return results.
- * Once the key/index is found, we will stop search. You can use text to query
- * both objects and array (for array, text will be converted to integer index),
- * and use index to retrieve from array. Array index is 0-based.
- *
- * ** External dictionary **
- * During query processing, you can also pass a call-back function, so the
- * search will first try to check if the key string exists in the dictionary.
- * If so, search will be based on the id instead of the key string.
- *
- * @author Tian Xia <tianx@fb.com>
- */
-#ifndef FBSON_FBSONDOCUMENT_H
-#define FBSON_FBSONDOCUMENT_H
-
-#ifndef ROCKSDB_LITE
-
-#include <string.h>
-#include <assert.h>
-
-namespace fbson {
-
-#pragma pack(push, 1)
-
-#define FBSON_VER 1
-
-// forward declaration
-class FbsonValue;
-class ObjectVal;
-
-/*
- * FbsonDocument is the main object that accesses and queries FBSON packed
- * bytes. NOTE: FbsonDocument only allows object container as the top level
- * FBSON value. However, you can use the static method "createValue" to get any
- * FbsonValue object from the packed bytes.
- *
- * FbsonDocument object also dereferences to an object container value
- * (ObjectVal) once FBSON is loaded.
- *
- * ** Load **
- * FbsonDocument is usable after loading packed bytes (memory location) into
- * the object. We only need the header and first few bytes of the payload after
- * header to verify the FBSON.
- *
- * Note: creating an FbsonDocument (through createDocument) does not allocate
- * any memory. The document object is an efficient wrapper on the packed bytes
- * which is accessed directly.
- *
- * ** Query **
- * Query is through dereferencing into ObjectVal.
- */
-class FbsonDocument {
- public:
- // create an FbsonDocument object from FBSON packed bytes
- static FbsonDocument *createDocument(const char *pb, uint32_t size);
-
- // create an FbsonValue from FBSON packed bytes
- static FbsonValue *createValue(const char *pb, uint32_t size);
-
- uint8_t version() { return header_.ver_; }
-
- FbsonValue *getValue() { return ((FbsonValue *)payload_); }
-
- ObjectVal *operator->() { return ((ObjectVal *)payload_); }
-
- const ObjectVal *operator->() const { return ((const ObjectVal *)payload_); }
-
- private:
- /*
- * FbsonHeader class defines FBSON header (internal to FbsonDocument).
- *
- * Currently it only contains version information (1-byte). We may expand the
- * header to include checksum of the FBSON binary for more security.
- */
- struct FbsonHeader {
- uint8_t ver_;
- } header_;
-
- char payload_[0];
-
- FbsonDocument();
-};
-
-/*
- * FbsonFwdIteratorT implements FBSON's iterator template.
- *
- * Note: it is an FORWARD iterator only due to the design of FBSON format.
- */
-template <class Iter_Type, class Cont_Type>
-class FbsonFwdIteratorT {
- typedef Iter_Type iterator;
- typedef typename std::iterator_traits<Iter_Type>::pointer pointer;
- typedef typename std::iterator_traits<Iter_Type>::reference reference;
-
- public:
- explicit FbsonFwdIteratorT(const iterator &i) : current_(i) {}
-
- // allow non-const to const iterator conversion (same container type)
- template <class Iter_Ty>
- FbsonFwdIteratorT(const FbsonFwdIteratorT<Iter_Ty, Cont_Type> &rhs)
- : current_(rhs.base()) {}
-
- bool operator==(const FbsonFwdIteratorT &rhs) const {
- return (current_ == rhs.current_);
- }
-
- bool operator!=(const FbsonFwdIteratorT &rhs) const {
- return !operator==(rhs);
- }
-
- bool operator<(const FbsonFwdIteratorT &rhs) const {
- return (current_ < rhs.current_);
- }
-
- bool operator>(const FbsonFwdIteratorT &rhs) const { return !operator<(rhs); }
-
- FbsonFwdIteratorT &operator++() {
- current_ = (iterator)(((char *)current_) + current_->numPackedBytes());
- return *this;
- }
-
- FbsonFwdIteratorT operator++(int) {
- auto tmp = *this;
- current_ = (iterator)(((char *)current_) + current_->numPackedBytes());
- return tmp;
- }
-
- explicit operator pointer() { return current_; }
-
- reference operator*() const { return *current_; }
-
- pointer operator->() const { return current_; }
-
- iterator base() const { return current_; }
-
- private:
- iterator current_;
-};
-
-typedef int (*hDictInsert)(const char *key, unsigned len);
-typedef int (*hDictFind)(const char *key, unsigned len);
-
-/*
- * FbsonType defines 10 primitive types and 2 container types, as described
- * below.
- *
- * primitive_value ::=
- * 0x00 //null value (0 byte)
- * | 0x01 //boolean true (0 byte)
- * | 0x02 //boolean false (0 byte)
- * | 0x03 int8 //char/int8 (1 byte)
- * | 0x04 int16 //int16 (2 bytes)
- * | 0x05 int32 //int32 (4 bytes)
- * | 0x06 int64 //int64 (8 bytes)
- * | 0x07 double //floating point (8 bytes)
- * | 0x08 string //variable length string
- * | 0x09 binary //variable length binary
- *
- * container ::=
- * 0x0A int32 key_value_list //object, int32 is the total bytes of the object
- * | 0x0B int32 value_list //array, int32 is the total bytes of the array
- */
-enum class FbsonType : char {
- T_Null = 0x00,
- T_True = 0x01,
- T_False = 0x02,
- T_Int8 = 0x03,
- T_Int16 = 0x04,
- T_Int32 = 0x05,
- T_Int64 = 0x06,
- T_Double = 0x07,
- T_String = 0x08,
- T_Binary = 0x09,
- T_Object = 0x0A,
- T_Array = 0x0B,
- NUM_TYPES,
-};
-
-typedef std::underlying_type<FbsonType>::type FbsonTypeUnder;
-
-/*
- * FbsonKeyValue class defines FBSON key type, as described below.
- *
- * key ::=
- * 0x00 int8 //1-byte dictionary id
- * | int8 (byte*) //int8 (>0) is the size of the key string
- *
- * value ::= primitive_value | container
- *
- * FbsonKeyValue can be either an id mapping to the key string in an external
- * dictionary, or it is the original key string. Whether to read an id or a
- * string is decided by the first byte (size_).
- *
- * Note: a key object must be followed by a value object. Therefore, a key
- * object implicitly refers to a key-value pair, and you can get the value
- * object right after the key object. The function numPackedBytes hence
- * indicates the total size of the key-value pair, so that we will be able go
- * to next pair from the key.
- *
- * ** Dictionary size **
- * By default, the dictionary size is 255 (1-byte). Users can define
- * "USE_LARGE_DICT" to increase the dictionary size to 655535 (2-byte).
- */
-class FbsonKeyValue {
- public:
-#ifdef USE_LARGE_DICT
- static const int sMaxKeyId = 65535;
- typedef uint16_t keyid_type;
-#else
- static const int sMaxKeyId = 255;
- typedef uint8_t keyid_type;
-#endif // #ifdef USE_LARGE_DICT
-
- static const uint8_t sMaxKeyLen = 64;
-
- // size of the key. 0 indicates it is stored as id
- uint8_t klen() const { return size_; }
-
- // get the key string. Note the string may not be null terminated.
- const char *getKeyStr() const { return key_.str_; }
-
- keyid_type getKeyId() const { return key_.id_; }
-
- unsigned int keyPackedBytes() const {
- return size_ ? (sizeof(size_) + size_)
- : (sizeof(size_) + sizeof(keyid_type));
- }
-
- FbsonValue *value() const {
- return (FbsonValue *)(((char *)this) + keyPackedBytes());
- }
-
- // size of the total packed bytes (key+value)
- unsigned int numPackedBytes() const;
-
- private:
- uint8_t size_;
-
- union key_ {
- keyid_type id_;
- char str_[1];
- } key_;
-
- FbsonKeyValue();
-};
-
-/*
- * FbsonValue is the base class of all FBSON types. It contains only one member
- * variable - type info, which can be retrieved by member functions is[Type]()
- * or type().
- */
-class FbsonValue {
- public:
- static const uint32_t sMaxValueLen = 1 << 24; // 16M
-
- bool isNull() const { return (type_ == FbsonType::T_Null); }
- bool isTrue() const { return (type_ == FbsonType::T_True); }
- bool isFalse() const { return (type_ == FbsonType::T_False); }
- bool isInt8() const { return (type_ == FbsonType::T_Int8); }
- bool isInt16() const { return (type_ == FbsonType::T_Int16); }
- bool isInt32() const { return (type_ == FbsonType::T_Int32); }
- bool isInt64() const { return (type_ == FbsonType::T_Int64); }
- bool isDouble() const { return (type_ == FbsonType::T_Double); }
- bool isString() const { return (type_ == FbsonType::T_String); }
- bool isBinary() const { return (type_ == FbsonType::T_Binary); }
- bool isObject() const { return (type_ == FbsonType::T_Object); }
- bool isArray() const { return (type_ == FbsonType::T_Array); }
-
- FbsonType type() const { return type_; }
-
- // size of the total packed bytes
- unsigned int numPackedBytes() const;
-
- // size of the value in bytes
- unsigned int size() const;
-
- // get the raw byte array of the value
- const char *getValuePtr() const;
-
- protected:
- FbsonType type_; // type info
-
- FbsonValue();
-};
-
-/*
- * NumerValT is the template class (derived from FbsonValue) of all number
- * types (integers and double).
- */
-template <class T>
-class NumberValT : public FbsonValue {
- public:
- T val() const { return num_; }
-
- unsigned int numPackedBytes() const { return sizeof(FbsonValue) + sizeof(T); }
-
- // catch all unknow specialization of the template class
- bool setVal(T value) { return false; }
-
- private:
- T num_;
-
- NumberValT();
-};
-
-typedef NumberValT<int8_t> Int8Val;
-
-// override setVal for Int8Val
-template <>
-inline bool Int8Val::setVal(int8_t value) {
- if (!isInt8()) {
- return false;
- }
-
- num_ = value;
- return true;
-}
-
-typedef NumberValT<int16_t> Int16Val;
-
-// override setVal for Int16Val
-template <>
-inline bool Int16Val::setVal(int16_t value) {
- if (!isInt16()) {
- return false;
- }
-
- num_ = value;
- return true;
-}
-
-typedef NumberValT<int32_t> Int32Val;
-
-// override setVal for Int32Val
-template <>
-inline bool Int32Val::setVal(int32_t value) {
- if (!isInt32()) {
- return false;
- }
-
- num_ = value;
- return true;
-}
-
-typedef NumberValT<int64_t> Int64Val;
-
-// override setVal for Int64Val
-template <>
-inline bool Int64Val::setVal(int64_t value) {
- if (!isInt64()) {
- return false;
- }
-
- num_ = value;
- return true;
-}
-
-typedef NumberValT<double> DoubleVal;
-
-// override setVal for DoubleVal
-template <>
-inline bool DoubleVal::setVal(double value) {
- if (!isDouble()) {
- return false;
- }
-
- num_ = value;
- return true;
-}
-
-/*
- * BlobVal is the base class (derived from FbsonValue) for string and binary
- * types. The size_ indicates the total bytes of the payload_.
- */
-class BlobVal : public FbsonValue {
- public:
- // size of the blob payload only
- unsigned int getBlobLen() const { return size_; }
-
- // return the blob as byte array
- const char *getBlob() const { return payload_; }
-
- // size of the total packed bytes
- unsigned int numPackedBytes() const {
- return sizeof(FbsonValue) + sizeof(size_) + size_;
- }
-
- protected:
- uint32_t size_;
- char payload_[0];
-
- // set new blob bytes
- bool internalSetVal(const char *blob, uint32_t blobSize) {
- // if we cannot fit the new blob, fail the operation
- if (blobSize > size_) {
- return false;
- }
-
- memcpy(payload_, blob, blobSize);
-
- // Set the reset of the bytes to 0. Note we cannot change the size_ of the
- // current payload, as all values are packed.
- memset(payload_ + blobSize, 0, size_ - blobSize);
-
- return true;
- }
-
- BlobVal();
-};
-
-/*
- * Binary type
- */
-class BinaryVal : public BlobVal {
- public:
- bool setVal(const char *blob, uint32_t blobSize) {
- if (!isBinary()) {
- return false;
- }
-
- return internalSetVal(blob, blobSize);
- }
-
- private:
- BinaryVal();
-};
-
-/*
- * String type
- * Note: FBSON string may not be a c-string (NULL-terminated)
- */
-class StringVal : public BlobVal {
- public:
- bool setVal(const char *str, uint32_t blobSize) {
- if (!isString()) {
- return false;
- }
-
- return internalSetVal(str, blobSize);
- }
-
- private:
- StringVal();
-};
-
-/*
- * ContainerVal is the base class (derived from FbsonValue) for object and
- * array types. The size_ indicates the total bytes of the payload_.
- */
-class ContainerVal : public FbsonValue {
- public:
- // size of the container payload only
- unsigned int getContainerSize() const { return size_; }
-
- // return the container payload as byte array
- const char *getPayload() const { return payload_; }
-
- // size of the total packed bytes
- unsigned int numPackedBytes() const {
- return sizeof(FbsonValue) + sizeof(size_) + size_;
- }
-
- protected:
- uint32_t size_;
- char payload_[0];
-
- ContainerVal();
-};
-
-/*
- * Object type
- */
-class ObjectVal : public ContainerVal {
- public:
- // find the FBSON value by a key string
- FbsonValue *find(const char *key, hDictFind handler = nullptr) const {
- int key_id = -1;
- unsigned int klen = strlen(key);
- if (handler && (key_id = handler(key, klen)) >= 0) {
- return find(key_id);
- }
-
- const char *pch = payload_;
- const char *fence = payload_ + size_;
-
- while (pch < fence) {
- FbsonKeyValue *pkey = (FbsonKeyValue *)(pch);
- if (klen == pkey->klen() && strncmp(key, pkey->getKeyStr(), klen) == 0) {
- return pkey->value();
- }
- pch += pkey->numPackedBytes();
- }
-
- assert(pch == fence);
-
- return nullptr;
- }
-
- // find the FBSON value by a key dictionary ID
- FbsonValue *find(int key_id) const {
- if (key_id < 0 || key_id > FbsonKeyValue::sMaxKeyId)
- return nullptr;
-
- const char *pch = payload_;
- const char *fence = payload_ + size_;
-
- while (pch < fence) {
- FbsonKeyValue *pkey = (FbsonKeyValue *)(pch);
- if (!pkey->klen() && key_id == pkey->getKeyId()) {
- return pkey->value();
- }
- pch += pkey->numPackedBytes();
- }
-
- assert(pch == fence);
-
- return nullptr;
- }
-
- typedef FbsonKeyValue value_type;
- typedef value_type *pointer;
- typedef const value_type *const_pointer;
- typedef FbsonFwdIteratorT<pointer, ObjectVal> iterator;
- typedef FbsonFwdIteratorT<const_pointer, ObjectVal> const_iterator;
-
- iterator begin() { return iterator((pointer)payload_); }
-
- const_iterator begin() const { return const_iterator((pointer)payload_); }
-
- iterator end() { return iterator((pointer)(payload_ + size_)); }
-
- const_iterator end() const {
- return const_iterator((pointer)(payload_ + size_));
- }
-
- private:
- ObjectVal();
-};
-
-/*
- * Array type
- */
-class ArrayVal : public ContainerVal {
- public:
- // get the FBSON value at index
- FbsonValue *get(int idx) const {
- if (idx < 0)
- return nullptr;
-
- const char *pch = payload_;
- const char *fence = payload_ + size_;
-
- while (pch < fence && idx-- > 0)
- pch += ((FbsonValue *)pch)->numPackedBytes();
-
- if (idx == -1)
- return (FbsonValue *)pch;
- else {
- assert(pch == fence);
- return nullptr;
- }
- }
-
- // Get number of elements in array
- unsigned int numElem() const {
- const char *pch = payload_;
- const char *fence = payload_ + size_;
-
- unsigned int num = 0;
- while (pch < fence) {
- ++num;
- pch += ((FbsonValue *)pch)->numPackedBytes();
- }
-
- assert(pch == fence);
-
- return num;
- }
-
- typedef FbsonValue value_type;
- typedef value_type *pointer;
- typedef const value_type *const_pointer;
- typedef FbsonFwdIteratorT<pointer, ArrayVal> iterator;
- typedef FbsonFwdIteratorT<const_pointer, ArrayVal> const_iterator;
-
- iterator begin() { return iterator((pointer)payload_); }
-
- const_iterator begin() const { return const_iterator((pointer)payload_); }
-
- iterator end() { return iterator((pointer)(payload_ + size_)); }
-
- const_iterator end() const {
- return const_iterator((pointer)(payload_ + size_));
- }
-
- private:
- ArrayVal();
-};
-
-inline FbsonDocument *FbsonDocument::createDocument(const char *pb,
- uint32_t size) {
- if (!pb || size < sizeof(FbsonHeader) + sizeof(FbsonValue)) {
- return nullptr;
- }
-
- FbsonDocument *doc = (FbsonDocument *)pb;
- if (doc->header_.ver_ != FBSON_VER) {
- return nullptr;
- }
-
- FbsonValue *val = (FbsonValue *)doc->payload_;
- if (!val->isObject() || size != sizeof(FbsonHeader) + val->numPackedBytes()) {
- return nullptr;
- }
-
- return doc;
-}
-
-inline FbsonValue *FbsonDocument::createValue(const char *pb, uint32_t size) {
- if (!pb || size < sizeof(FbsonHeader) + sizeof(FbsonValue)) {
- return nullptr;
- }
-
- FbsonDocument *doc = (FbsonDocument *)pb;
- if (doc->header_.ver_ != FBSON_VER) {
- return nullptr;
- }
-
- FbsonValue *val = (FbsonValue *)doc->payload_;
- if (size != sizeof(FbsonHeader) + val->numPackedBytes()) {
- return nullptr;
- }
-
- return val;
-}
-
-inline unsigned int FbsonKeyValue::numPackedBytes() const {
- unsigned int ks = keyPackedBytes();
- FbsonValue *val = (FbsonValue *)(((char *)this) + ks);
- return ks + val->numPackedBytes();
-}
-
-// Poor man's "virtual" function FbsonValue::numPackedBytes
-inline unsigned int FbsonValue::numPackedBytes() const {
- switch (type_) {
- case FbsonType::T_Null:
- case FbsonType::T_True:
- case FbsonType::T_False: { return sizeof(type_); }
-
- case FbsonType::T_Int8: { return sizeof(type_) + sizeof(int8_t); }
- case FbsonType::T_Int16: { return sizeof(type_) + sizeof(int16_t); }
- case FbsonType::T_Int32: { return sizeof(type_) + sizeof(int32_t); }
- case FbsonType::T_Int64: { return sizeof(type_) + sizeof(int64_t); }
- case FbsonType::T_Double: { return sizeof(type_) + sizeof(double); }
- case FbsonType::T_String:
- case FbsonType::T_Binary: { return ((BlobVal *)(this))->numPackedBytes(); }
-
- case FbsonType::T_Object:
- case FbsonType::T_Array: {
- return ((ContainerVal *)(this))->numPackedBytes();
- }
- default:
- return 0;
- }
-}
-
-inline unsigned int FbsonValue::size() const {
- switch (type_) {
- case FbsonType::T_Int8: { return sizeof(int8_t); }
- case FbsonType::T_Int16: { return sizeof(int16_t); }
- case FbsonType::T_Int32: { return sizeof(int32_t); }
- case FbsonType::T_Int64: { return sizeof(int64_t); }
- case FbsonType::T_Double: { return sizeof(double); }
- case FbsonType::T_String:
- case FbsonType::T_Binary: { return ((BlobVal *)(this))->getBlobLen(); }
-
- case FbsonType::T_Object:
- case FbsonType::T_Array: {
- return ((ContainerVal *)(this))->getContainerSize();
- }
- case FbsonType::T_Null:
- case FbsonType::T_True:
- case FbsonType::T_False:
- default:
- return 0;
- }
-}
-
-inline const char *FbsonValue::getValuePtr() const {
- switch (type_) {
- case FbsonType::T_Int8:
- case FbsonType::T_Int16:
- case FbsonType::T_Int32:
- case FbsonType::T_Int64:
- case FbsonType::T_Double:
- return ((char *)this) + sizeof(FbsonType);
-
- case FbsonType::T_String:
- case FbsonType::T_Binary:
- return ((BlobVal *)(this))->getBlob();
-
- case FbsonType::T_Object:
- case FbsonType::T_Array:
- return ((ContainerVal *)(this))->getPayload();
-
- case FbsonType::T_Null:
- case FbsonType::T_True:
- case FbsonType::T_False:
- default:
- return nullptr;
- }
-}
-
-#pragma pack(pop)
-
-} // namespace fbson
-
-#endif // ROCKSDB_LITE
-#endif // FBSON_FBSONDOCUMENT_H
diff --git a/third-party/fbson/FbsonJsonParser.h b/third-party/fbson/FbsonJsonParser.h
deleted file mode 100644
index 6424038cf..000000000
--- a/third-party/fbson/FbsonJsonParser.h
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- * Copyright (c) 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
-
-/*
- * This file defines FbsonJsonParserT (template) and FbsonJsonParser.
- *
- * FbsonJsonParserT is a template class which implements a JSON parser.
- * FbsonJsonParserT parses JSON text, and serialize it to FBSON binary format
- * by using FbsonWriterT object. By default, FbsonJsonParserT creates a new
- * FbsonWriterT object with an output stream object. However, you can also
- * pass in your FbsonWriterT or any stream object that implements some basic
- * interface of std::ostream (see FbsonStream.h).
- *
- * FbsonJsonParser specializes FbsonJsonParserT with FbsonOutStream type (see
- * FbsonStream.h). So unless you want to provide own a different output stream
- * type, use FbsonJsonParser object.
- *
- * ** Parsing JSON **
- * FbsonJsonParserT parses JSON string, and directly serializes into FBSON
- * packed bytes. There are three ways to parse a JSON string: (1) using
- * c-string, (2) using string with len, (3) using std::istream object. You can
- * use custome streambuf to redirect output. FbsonOutBuffer is a streambuf used
- * internally if the input is raw character buffer.
- *
- * You can reuse an FbsonJsonParserT object to parse/serialize multiple JSON
- * strings, and the previous FBSON will be overwritten.
- *
- * If parsing fails (returned false), the error code will be set to one of
- * FbsonErrType, and can be retrieved by calling getErrorCode().
- *
- * ** External dictionary **
- * During parsing a JSON string, you can pass a call-back function to map a key
- * string to an id, and store the dictionary id in FBSON to save space. The
- * purpose of using an external dictionary is more towards a collection of
- * documents (which has common keys) rather than a single document, so that
- * space saving will be siginificant.
- *
- * ** Endianness **
- * Note: FBSON serialization doesn't assume endianness of the server. However
- * you will need to ensure that the endianness at the reader side is the same
- * as that at the writer side (if they are on different machines). Otherwise,
- * proper conversion is needed when a number value is returned to the
- * caller/writer.
- *
- * @author Tian Xia <tianx@fb.com>
- */
-
-#ifndef FBSON_FBSONPARSER_H
-#define FBSON_FBSONPARSER_H
-
-#ifndef ROCKSDB_LITE
-
-#include <cmath>
-#include "FbsonDocument.h"
-#include "FbsonWriter.h"
-
-namespace fbson {
-
-const char *const kJsonDelim = " ,]}\t\r\n";
-const char *const kWhiteSpace = " \t\n\r";
-
-/*
- * Error codes
- */
-enum class FbsonErrType {
- E_NONE = 0,
- E_INVALID_VER,
- E_EMPTY_STR,
- E_OUTPUT_FAIL,
- E_INVALID_DOCU,
- E_INVALID_VALUE,
- E_INVALID_KEY,
- E_INVALID_STR,
- E_INVALID_OBJ,
- E_INVALID_ARR,
- E_INVALID_HEX,
- E_INVALID_OCTAL,
- E_INVALID_DECIMAL,
- E_INVALID_EXPONENT,
- E_HEX_OVERFLOW,
- E_OCTAL_OVERFLOW,
- E_DECIMAL_OVERFLOW,
- E_DOUBLE_OVERFLOW,
- E_EXPONENT_OVERFLOW,
-};
-
-/*
- * Template FbsonJsonParserT
- */
-template <class OS_TYPE>
-class FbsonJsonParserT {
- public:
- FbsonJsonParserT() : err_(FbsonErrType::E_NONE) {}
-
- explicit FbsonJsonParserT(OS_TYPE &os)
- : writer_(os), err_(FbsonErrType::E_NONE) {}
-
- // parse a UTF-8 JSON string
- bool parse(const std::string &str, hDictInsert handler = nullptr) {
- return parse(str.c_str(), str.size(), handler);
- }
-
- // parse a UTF-8 JSON c-style string (NULL terminated)
- bool parse(const char *c_str, hDictInsert handler = nullptr) {
- return parse(c_str, strlen(c_str), handler);
- }
-
- // parse a UTF-8 JSON string with length
- bool parse(const char *pch, uint32_t len, hDictInsert handler = nullptr) {
- if (!pch || len == 0) {
- err_ = FbsonErrType::E_EMPTY_STR;
- return false;
- }
-
- FbsonInBuffer sb(pch, len);
- std::istream in(&sb);
- return parse(in, handler);
- }
-
- // parse UTF-8 JSON text from an input stream
- bool parse(std::istream &in, hDictInsert handler = nullptr) {
- bool res = false;
-
- // reset output stream
- writer_.reset();
-
- trim(in);
-
- if (in.peek() == '{') {
- in.ignore();
- res = parseObject(in, handler);
- } else if (in.peek() == '[') {
- in.ignore();
- res = parseArray(in, handler);
- } else {
- err_ = FbsonErrType::E_INVALID_DOCU;
- }
-
- trim(in);
- if (res && !in.eof()) {
- err_ = FbsonErrType::E_INVALID_DOCU;
- return false;
- }
-
- return res;
- }
-
- FbsonWriterT<OS_TYPE> &getWriter() { return writer_; }
-
- FbsonErrType getErrorCode() { return err_; }
-
- // clear error code
- void clearErr() { err_ = FbsonErrType::E_NONE; }
-
- private:
- // parse a JSON object (comma-separated list of key-value pairs)
- bool parseObject(std::istream &in, hDictInsert handler) {
- if (!writer_.writeStartObject()) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
-
- trim(in);
-
- if (in.peek() == '}') {
- in.ignore();
- // empty object
- if (!writer_.writeEndObject()) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
- return true;
- }
-
- while (in.good()) {
- if (in.get() != '"') {
- err_ = FbsonErrType::E_INVALID_KEY;
- return false;
- }
-
- if (!parseKVPair(in, handler)) {
- return false;
- }
-
- trim(in);
-
- char ch = in.get();
- if (ch == '}') {
- // end of the object
- if (!writer_.writeEndObject()) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
- return true;
- } else if (ch != ',') {
- err_ = FbsonErrType::E_INVALID_OBJ;
- return false;
- }
-
- trim(in);
- }
-
- err_ = FbsonErrType::E_INVALID_OBJ;
- return false;
- }
-
- // parse a JSON array (comma-separated list of values)
- bool parseArray(std::istream &in, hDictInsert handler) {
- if (!writer_.writeStartArray()) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
-
- trim(in);
-
- if (in.peek() == ']') {
- in.ignore();
- // empty array
- if (!writer_.writeEndArray()) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
- return true;
- }
-
- while (in.good()) {
- if (!parseValue(in, handler)) {
- return false;
- }
-
- trim(in);
-
- char ch = in.get();
- if (ch == ']') {
- // end of the array
- if (!writer_.writeEndArray()) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
- return true;
- } else if (ch != ',') {
- err_ = FbsonErrType::E_INVALID_ARR;
- return false;
- }
-
- trim(in);
- }
-
- err_ = FbsonErrType::E_INVALID_ARR;
- return false;
- }
-
- // parse a key-value pair, separated by ":"
- bool parseKVPair(std::istream &in, hDictInsert handler) {
- if (parseKey(in, handler) && parseValue(in, handler)) {
- return true;
- }
-
- return false;
- }
-
- // parse a key (must be string)
- bool parseKey(std::istream &in, hDictInsert handler) {
- char key[FbsonKeyValue::sMaxKeyLen];
- int i = 0;
- while (in.good() && in.peek() != '"' && i < FbsonKeyValue::sMaxKeyLen) {
- key[i++] = in.get();
- }
-
- if (!in.good() || in.peek() != '"' || i == 0) {
- err_ = FbsonErrType::E_INVALID_KEY;
- return false;
- }
-
- in.ignore(); // discard '"'
-
- int key_id = -1;
- if (handler) {
- key_id = handler(key, i);
- }
-
- if (key_id < 0) {
- writer_.writeKey(key, i);
- } else {
- writer_.writeKey(key_id);
- }
-
- trim(in);
-
- if (in.get() != ':') {
- err_ = FbsonErrType::E_INVALID_OBJ;
- return false;
- }
-
- return true;
- }
-
- // parse a value
- bool parseValue(std::istream &in, hDictInsert handler) {
- bool res = false;
-
- trim(in);
-
- switch (in.peek()) {
- case 'N':
- case 'n': {
- in.ignore();
- res = parseNull(in);
- break;
- }
- case 'T':
- case 't': {
- in.ignore();
- res = parseTrue(in);
- break;
- }
- case 'F':
- case 'f': {
- in.ignore();
- res = parseFalse(in);
- break;
- }
- case '"': {
- in.ignore();
- res = parseString(in);
- break;
- }
- case '{': {
- in.ignore();
- res = parseObject(in, handler);
- break;
- }
- case '[': {
- in.ignore();
- res = parseArray(in, handler);
- break;
- }
- default: {
- res = parseNumber(in);
- break;
- }
- }
-
- return res;
- }
-
- // parse NULL value
- bool parseNull(std::istream &in) {
- if (tolower(in.get()) == 'u' && tolower(in.get()) == 'l' &&
- tolower(in.get()) == 'l') {
- writer_.writeNull();
- return true;
- }
-
- err_ = FbsonErrType::E_INVALID_VALUE;
- return false;
- }
-
- // parse TRUE value
- bool parseTrue(std::istream &in) {
- if (tolower(in.get()) == 'r' && tolower(in.get()) == 'u' &&
- tolower(in.get()) == 'e') {
- writer_.writeBool(true);
- return true;
- }
-
- err_ = FbsonErrType::E_INVALID_VALUE;
- return false;
- }
-
- // parse FALSE value
- bool parseFalse(std::istream &in) {
- if (tolower(in.get()) == 'a' && tolower(in.get()) == 'l' &&
- tolower(in.get()) == 's' && tolower(in.get()) == 'e') {
- writer_.writeBool(false);
- return true;
- }
-
- err_ = FbsonErrType::E_INVALID_VALUE;
- return false;
- }
-
- // parse a string
- bool parseString(std::istream &in) {
- if (!writer_.writeStartString()) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
-
- bool escaped = false;
- char buffer[4096]; // write 4KB at a time
- int nread = 0;
- while (in.good()) {
- char ch = in.get();
- if (ch != '"' || escaped) {
- buffer[nread++] = ch;
- if (nread == 4096) {
- // flush buffer
- if (!writer_.writeString(buffer, nread)) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
- nread = 0;
- }
- // set/reset escape
- if (ch == '\\' || escaped) {
- escaped = !escaped;
- }
- } else {
- // write all remaining bytes in the buffer
- if (nread > 0) {
- if (!writer_.writeString(buffer, nread)) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
- }
- // end writing string
- if (!writer_.writeEndString()) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
- return true;
- }
- }
-
- err_ = FbsonErrType::E_INVALID_STR;
- return false;
- }
-
- // parse a number
- // Number format can be hex, octal, or decimal (including float).
- // Only decimal can have (+/-) sign prefix.
- bool parseNumber(std::istream &in) {
- bool ret = false;
- switch (in.peek()) {
- case '0': {
- in.ignore();
-
- if (in.peek() == 'x' || in.peek() == 'X') {
- in.ignore();
- ret = parseHex(in);
- } else if (in.peek() == '.') {
- in.ignore();
- ret = parseDouble(in, 0, 0, 1);
- } else {
- ret = parseOctal(in);
- }
-
- break;
- }
- case '-': {
- in.ignore();
- ret = parseDecimal(in, -1);
- break;
- }
- case '+':
- in.ignore();
- // fall through
- default:
- ret = parseDecimal(in, 1);
- break;
- }
-
- return ret;
- }
-
- // parse a number in hex format
- bool parseHex(std::istream &in) {
- uint64_t val = 0;
- int num_digits = 0;
- char ch = tolower(in.peek());
- while (in.good() && !strchr(kJsonDelim, ch) && (++num_digits) <= 16) {
- if (ch >= '0' && ch <= '9') {
- val = (val << 4) + (ch - '0');
- } else if (ch >= 'a' && ch <= 'f') {
- val = (val << 4) + (ch - 'a' + 10);
- } else { // unrecognized hex digit
- err_ = FbsonErrType::E_INVALID_HEX;
- return false;
- }
-
- in.ignore();
- ch = tolower(in.peek());
- }
-
- int size = 0;
- if (num_digits <= 2) {
- size = writer_.writeInt8(val);
- } else if (num_digits <= 4) {
- size = writer_.writeInt16(val);
- } else if (num_digits <= 8) {
- size = writer_.writeInt32(val);
- } else if (num_digits <= 16) {
- size = writer_.writeInt64(val);
- } else {
- err_ = FbsonErrType::E_HEX_OVERFLOW;
- return false;
- }
-
- if (size == 0) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
-
- return true;
- }
-
- // parse a number in octal format
- bool parseOctal(std::istream &in) {
- int64_t val = 0;
- char ch = in.peek();
- while (in.good() && !strchr(kJsonDelim, ch)) {
- if (ch >= '0' && ch <= '7') {
- val = val * 8 + (ch - '0');
- } else {
- err_ = FbsonErrType::E_INVALID_OCTAL;
- return false;
- }
-
- // check if the number overflows
- if (val < 0) {
- err_ = FbsonErrType::E_OCTAL_OVERFLOW;
- return false;
- }
-
- in.ignore();
- ch = in.peek();
- }
-
- int size = 0;
- if (val <= std::numeric_limits<int8_t>::max()) {
- size = writer_.writeInt8(val);
- } else if (val <= std::numeric_limits<int16_t>::max()) {
- size = writer_.writeInt16(val);
- } else if (val <= std::numeric_limits<int32_t>::max()) {
- size = writer_.writeInt32(val);
- } else { // val <= INT64_MAX
- size = writer_.writeInt64(val);
- }
-
- if (size == 0) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
-
- return true;
- }
-
- // parse a number in decimal (including float)
- bool parseDecimal(std::istream &in, int sign) {
- int64_t val = 0;
- int precision = 0;
-
- char ch = 0;
- while (in.good() && (ch = in.peek()) == '0')
- in.ignore();
-
- while (in.good() && !strchr(kJsonDelim, ch)) {
- if (ch >= '0' && ch <= '9') {
- val = val * 10 + (ch - '0');
- ++precision;
- } else if (ch == '.') {
- // note we don't pop out '.'
- return parseDouble(in, val, precision, sign);
- } else {
- err_ = FbsonErrType::E_INVALID_DECIMAL;
- return false;
- }
-
- in.ignore();
-
- // if the number overflows int64_t, first parse it as double iff we see a
- // decimal point later. Otherwise, will treat it as overflow
- if (val < 0 && val > std::numeric_limits<int64_t>::min()) {
- return parseDouble(in, (uint64_t)val, precision, sign);
- }
-
- ch = in.peek();
- }
-
- if (sign < 0) {
- val = -val;
- }
-
- int size = 0;
- if (val >= std::numeric_limits<int8_t>::min() &&
- val <= std::numeric_limits<int8_t>::max()) {
- size = writer_.writeInt8(val);
- } else if (val >= std::numeric_limits<int16_t>::min() &&
- val <= std::numeric_limits<int16_t>::max()) {
- size = writer_.writeInt16(val);
- } else if (val >= std::numeric_limits<int32_t>::min() &&
- val <= std::numeric_limits<int32_t>::max()) {
- size = writer_.writeInt32(val);
- } else { // val <= INT64_MAX
- size = writer_.writeInt64(val);
- }
-
- if (size == 0) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
-
- return true;
- }
-
- // parse IEEE745 double precision:
- // Significand precision length - 15
- // Maximum exponent value - 308
- //
- // "If a decimal string with at most 15 significant digits is converted to
- // IEEE 754 double precision representation and then converted back to a
- // string with the same number of significant digits, then the final string
- // should match the original"
- bool parseDouble(std::istream &in, double val, int precision, int sign) {
- int integ = precision;
- int frac = 0;
- bool is_frac = false;
-
- char ch = in.peek();
- if (ch == '.') {
- is_frac = true;
- in.ignore();
- ch = in.peek();
- }
-
- int exp = 0;
- while (in.good() && !strchr(kJsonDelim, ch)) {
- if (ch >= '0' && ch <= '9') {
- if (precision < 15) {
- val = val * 10 + (ch - '0');
- if (is_frac) {
- ++frac;
- } else {
- ++integ;
- }
- ++precision;
- } else if (!is_frac) {
- ++exp;
- }
- } else if (ch == 'e' || ch == 'E') {
- in.ignore();
- int exp2;
- if (!parseExponent(in, exp2)) {
- return false;
- }
-
- exp += exp2;
- // check if exponent overflows
- if (exp > 308 || exp < -308) {
- err_ = FbsonErrType::E_EXPONENT_OVERFLOW;
- return false;
- }
-
- is_frac = true;
- break;
- }
-
- in.ignore();
- ch = in.peek();
- }
-
- if (!is_frac) {
- err_ = FbsonErrType::E_DECIMAL_OVERFLOW;
- return false;
- }
-
- val *= std::pow(10, exp - frac);
- if (std::isnan(val) || std::isinf(val)) {
- err_ = FbsonErrType::E_DOUBLE_OVERFLOW;
- return false;
- }
-
- if (sign < 0) {
- val = -val;
- }
-
- if (writer_.writeDouble(val) == 0) {
- err_ = FbsonErrType::E_OUTPUT_FAIL;
- return false;
- }
-
- return true;
- }
-
- // parse the exponent part of a double number
- bool parseExponent(std::istream &in, int &exp) {
- bool neg = false;
-
- char ch = in.peek();
- if (ch == '+') {
- in.ignore();
- ch = in.peek();
- } else if (ch == '-') {
- neg = true;
- in.ignore();
- ch = in.peek();
- }
-
- exp = 0;
- while (in.good() && !strchr(kJsonDelim, ch)) {
- if (ch >= '0' && ch <= '9') {
- exp = exp * 10 + (ch - '0');
- } else {
- err_ = FbsonErrType::E_INVALID_EXPONENT;
- return false;
- }
-
- if (exp > 308) {
- err_ = FbsonErrType::E_EXPONENT_OVERFLOW;
- return false;
- }
-
- in.ignore();
- ch = in.peek();
- }
-
- if (neg) {
- exp = -exp;
- }
-
- return true;
- }
-
- void trim(std::istream &in) {
- while (in.good() && strchr(kWhiteSpace, in.peek())) {
- in.ignore();
- }
- }
-
- private:
- FbsonWriterT<OS_TYPE> writer_;
- FbsonErrType err_;
-};
-
-typedef FbsonJsonParserT<FbsonOutStream> FbsonJsonParser;
-
-} // namespace fbson
-
-#endif // ROCKSDB_LITE
-#endif // FBSON_FBSONPARSER_H
diff --git a/third-party/fbson/FbsonStream.h b/third-party/fbson/FbsonStream.h
deleted file mode 100644
index 0c78c0fe6..000000000
--- a/third-party/fbson/FbsonStream.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (c) 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
-
-/*
- * This header file defines FbsonInBuffer and FbsonOutStream classes.
- *
- * ** Input Buffer **
- * FbsonInBuffer is a customer input buffer to wrap raw character buffer. Its
- * object instances are used to create std::istream objects interally.
- *
- * ** Output Stream **
- * FbsonOutStream is a custom output stream classes, to contain the FBSON
- * serialized binary. The class is conveniently used to specialize templates of
- * FbsonParser and FbsonWriter.
- *
- * @author Tian Xia <tianx@fb.com>
- */
-
-#ifndef FBSON_FBSONSTREAM_H
-#define FBSON_FBSONSTREAM_H
-
-#ifndef ROCKSDB_LITE
-
-#include <iostream>
-
-namespace fbson {
-
-// lengths includes sign
-#define MAX_INT_DIGITS 11
-#define MAX_INT64_DIGITS 20
-#define MAX_DOUBLE_DIGITS 23 // 1(sign)+16(significant)+1(decimal)+5(exponent)
-
-/*
- * FBSON's implementation of input buffer
- */
-class FbsonInBuffer : public std::streambuf {
- public:
- FbsonInBuffer(const char *str, uint32_t len) {
- // this is read buffer and the str will not be changed
- // so we use const_cast (ugly!) to remove constness
- char *pch(const_cast<char *>(str));
- setg(pch, pch, pch + len);
- }
-};
-
-/*
- * FBSON's implementation of output stream.
- *
- * This is a wrapper of a char buffer. By default, the buffer capacity is 1024
- * bytes. We will double the buffer if realloc is needed for writes.
- */
-class FbsonOutStream : public std::ostream {
- public:
- explicit FbsonOutStream(uint32_t capacity = 1024)
- : head_(nullptr), size_(0), capacity_(capacity), alloc_(true) {
- if (capacity_ == 0) {
- capacity_ = 1024;
- }
-
- head_ = (char *)malloc(capacity_);
- }
-
- FbsonOutStream(char *buffer, uint32_t capacity)
- : head_(buffer), size_(0), capacity_(capacity), alloc_(false) {
- assert(buffer && capacity_ > 0);
- }
-
- ~FbsonOutStream() {
- if (alloc_) {
- free(head_);
- }
- }
-
- void put(char c) { write(&c, 1); }
-
- void write(const char *c_str) { write(c_str, strlen(c_str)); }
-
- void write(const char *bytes, uint32_t len) {
- if (len == 0)
- return;
-
- if (size_ + len > capacity_) {
- realloc(len);
- }
-
- memcpy(head_ + size_, bytes, len);
- size_ += len;
- }
-
- // write the integer to string
- void write(int i) {
- // snprintf automatically adds a NULL, so we need one more char
- if (size_ + MAX_INT_DIGITS + 1 > capacity_) {
- realloc(MAX_INT_DIGITS + 1);
- }
-
- int len = snprintf(head_ + size_, MAX_INT_DIGITS + 1, "%d", i);
- assert(len > 0);
- size_ += len;
- }
-
- // write the 64bit integer to string
- void write(int64_t l) {
- // snprintf automatically adds a NULL, so we need one more char
- if (size_ + MAX_INT64_DIGITS + 1 > capacity_) {
- realloc(MAX_INT64_DIGITS + 1);
- }
-
- int len = snprintf(head_ + size_, MAX_INT64_DIGITS + 1, "%ld", l);
- assert(len > 0);
- size_ += len;
- }
-
- // write the double to string
- void write(double d) {
- // snprintf automatically adds a NULL, so we need one more char
- if (size_ + MAX_DOUBLE_DIGITS + 1 > capacity_) {
- realloc(MAX_DOUBLE_DIGITS + 1);
- }
-
- int len = snprintf(head_ + size_, MAX_DOUBLE_DIGITS + 1, "%.15g", d);
- assert(len > 0);
- size_ += len;
- }
-
- pos_type tellp() const { return size_; }
-
- void seekp(pos_type pos) { size_ = pos; }
-
- const char *getBuffer() const { return head_; }
-
- pos_type getSize() const { return tellp(); }
-
- private:
- void realloc(uint32_t len) {
- assert(capacity_ > 0);
-
- capacity_ *= 2;
- while (capacity_ < size_ + len) {
- capacity_ *= 2;
- }
-
- if (alloc_) {
- char *new_buf = (char *)::realloc(head_, capacity_);
- assert(new_buf);
- head_ = new_buf;
- } else {
- char *new_buf = (char *)::malloc(capacity_);
- assert(new_buf);
- memcpy(new_buf, head_, size_);
- head_ = new_buf;
- alloc_ = true;
- }
- }
-
- private:
- char *head_;
- uint32_t size_;
- uint32_t capacity_;
- bool alloc_;
-};
-
-} // namespace fbson
-
-#endif // ROCKSDB_LITE
-#endif // FBSON_FBSONSTREAM_H
diff --git a/third-party/fbson/FbsonUtil.h b/third-party/fbson/FbsonUtil.h
deleted file mode 100644
index f2d5133f6..000000000
--- a/third-party/fbson/FbsonUtil.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (c) 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
-
-/*
- * This header file defines miscellaneous utility classes.
- *
- * @author Tian Xia <tianx@fb.com>
- */
-
-#ifndef FBSON_FBSONUTIL_H
-#define FBSON_FBSONUTIL_H
-
-#ifndef ROCKSDB_LITE
-
-#include <sstream>
-#include "FbsonDocument.h"
-
-namespace fbson {
-
-#define OUT_BUF_SIZE 1024
-
-/*
- * FbsonToJson converts an FbsonValue object to a JSON string.
- */
-class FbsonToJson {
- public:
- FbsonToJson() : os_(buffer_, OUT_BUF_SIZE) {}
-
- // get json string
- const char *json(const FbsonValue *pval) {
- os_.clear();
- os_.seekp(0);
-
- if (pval) {
- intern_json(pval);
- }
-
- os_.put(0);
- return os_.getBuffer();
- }
-
- private:
- // recursively convert FbsonValue
- void intern_json(const FbsonValue *val) {
- switch (val->type()) {
- case FbsonType::T_Null: {
- os_.write("null", 4);
- break;
- }
- case FbsonType::T_True: {
- os_.write("true", 4);
- break;
- }
- case FbsonType::T_False: {
- os_.write("false", 5);
- break;
- }
- case FbsonType::T_Int8: {
- os_.write(((Int8Val *)val)->val());
- break;
- }
- case FbsonType::T_Int16: {
- os_.write(((Int16Val *)val)->val());
- break;
- }
- case FbsonType::T_Int32: {
- os_.write(((Int32Val *)val)->val());
- break;
- }
- case FbsonType::T_Int64: {
- os_.write(((Int64Val *)val)->val());
- break;
- }
- case FbsonType::T_Double: {
- os_.write(((DoubleVal *)val)->val());
- break;
- }
- case FbsonType::T_String: {
- os_.put('"');
- os_.write(((StringVal *)val)->getBlob(),
- ((StringVal *)val)->getBlobLen());
- os_.put('"');
- break;
- }
- case FbsonType::T_Binary: {
- os_.write("\"<BINARY>", 9);
- os_.write(((BinaryVal *)val)->getBlob(),
- ((BinaryVal *)val)->getBlobLen());
- os_.write("<BINARY>\"", 9);
- break;
- }
- case FbsonType::T_Object: {
- object_to_json((ObjectVal *)val);
- break;
- }
- case FbsonType::T_Array: {
- array_to_json((ArrayVal *)val);
- break;
- }
- default:
- break;
- }
- }
-
- // convert object
- void object_to_json(const ObjectVal *val) {
- os_.put('{');
-
- auto iter = val->begin();
- auto iter_fence = val->end();
-
- while (iter < iter_fence) {
- // write key
- if (iter->klen()) {
- os_.put('"');
- os_.write(iter->getKeyStr(), iter->klen());
- os_.put('"');
- } else {
- os_.write(iter->getKeyId());
- }
- os_.put(':');
-
- // convert value
- intern_json(iter->value());
-
- ++iter;
- if (iter != iter_fence) {
- os_.put(',');
- }
- }
-
- assert(iter == iter_fence);
-
- os_.put('}');
- }
-
- // convert array to json
- void array_to_json(const ArrayVal *val) {
- os_.put('[');
-
- auto iter = val->begin();
- auto iter_fence = val->end();
-
- while (iter != iter_fence) {
- // convert value
- intern_json((const FbsonValue *)iter);
- ++iter;
- if (iter != iter_fence) {
- os_.put(',');
- }
- }
-
- assert(iter == iter_fence);
-
- os_.put(']');
- }
-
- private:
- FbsonOutStream os_;
- char buffer_[OUT_BUF_SIZE];
-};
-
-} // namespace fbson
-
-#endif // ROCKSDB_LITE
-#endif // FBSON_FBSONUTIL_H
diff --git a/third-party/fbson/FbsonWriter.h b/third-party/fbson/FbsonWriter.h
deleted file mode 100644
index 031c09f98..000000000
--- a/third-party/fbson/FbsonWriter.h
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (c) 2014, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
-
-/*
- * This file defines FbsonWriterT (template) and FbsonWriter.
- *
- * FbsonWriterT is a template class which implements an FBSON serializer.
- * Users call various write functions of FbsonWriterT object to write values
- * directly to FBSON packed bytes. All write functions of value or key return
- * the number of bytes written to FBSON, or 0 if there is an error. To write an
- * object, an array, or a string, you must call writeStart[..] before writing
- * values or key, and call writeEnd[..] after finishing at the end.
- *
- * By default, an FbsonWriterT object creates an output stream buffer.
- * Alternatively, you can also pass any output stream object to a writer, as
- * long as the stream object implements some basic functions of std::ostream
- * (such as FbsonOutStream, see FbsonStream.h).
- *
- * FbsonWriter specializes FbsonWriterT with FbsonOutStream type (see
- * FbsonStream.h). So unless you want to provide own a different output stream
- * type, use FbsonParser object.
- *
- * @author Tian Xia <tianx@fb.com>
- */
-
-#ifndef FBSON_FBSONWRITER_H
-#define FBSON_FBSONWRITER_H
-
-#ifndef ROCKSDB_LITE
-
-#include <stack>
-#include "FbsonDocument.h"
-#include "FbsonStream.h"
-
-namespace fbson {
-
-template <class OS_TYPE>
-class FbsonWriterT {
- public:
- FbsonWriterT()
- : alloc_(true), hasHdr_(false), kvState_(WS_Value), str_pos_(0) {
- os_ = new OS_TYPE();
- }
-
- explicit FbsonWriterT(OS_TYPE &os)
- : os_(&os),
- alloc_(false),
- hasHdr_(false),
- kvState_(WS_Value),
- str_pos_(0) {}
-
- ~FbsonWriterT() {
- if (alloc_) {
- delete os_;
- }
- }
-
- void reset() {
- os_->clear();
- os_->seekp(0);
- hasHdr_ = false;
- kvState_ = WS_Value;
- for (; !stack_.empty(); stack_.pop())
- ;
- }
-
- // write a key string (or key id if an external dict is provided)
- uint32_t writeKey(const char *key,
- uint8_t len,
- hDictInsert handler = nullptr) {
- if (len && !stack_.empty() && verifyKeyState()) {
- int key_id = -1;
- if (handler) {
- key_id = handler(key, len);
- }
-
- uint32_t size = sizeof(uint8_t);
- if (key_id < 0) {
- os_->put(len);
- os_->write(key, len);
- size += len;
- } else if (key_id <= FbsonKeyValue::sMaxKeyId) {
- FbsonKeyValue::keyid_type idx = key_id;
- os_->put(0);
- os_->write((char *)&idx, sizeof(FbsonKeyValue::keyid_type));
- size += sizeof(FbsonKeyValue::keyid_type);
- } else { // key id overflow
- assert(0);
- return 0;
- }
-
- kvState_ = WS_Key;
- return size;
- }
-
- return 0;
- }
-
- // write a key id
- uint32_t writeKey(FbsonKeyValue::keyid_type idx) {
- if (!stack_.empty() && verifyKeyState()) {
- os_->put(0);
- os_->write((char *)&idx, sizeof(FbsonKeyValue::keyid_type));
- kvState_ = WS_Key;
- return sizeof(uint8_t) + sizeof(FbsonKeyValue::keyid_type);
- }
-
- return 0;
- }
-
- uint32_t writeNull() {
- if (!stack_.empty() && verifyValueState()) {
- os_->put((FbsonTypeUnder)FbsonType::T_Null);
- kvState_ = WS_Value;
- return sizeof(FbsonValue);
- }
-
- return 0;
- }
-
- uint32_t writeBool(bool b) {
- if (!stack_.empty() && verifyValueState()) {
- if (b) {
- os_->put((FbsonTypeUnder)FbsonType::T_True);
- } else {
- os_->put((FbsonTypeUnder)FbsonType::T_False);
- }
-
- kvState_ = WS_Value;
- return sizeof(FbsonValue);
- }
-
- return 0;
- }
-
- uint32_t writeInt8(int8_t v) {
- if (!stack_.empty() && verifyValueState()) {
- os_->put((FbsonTypeUnder)FbsonType::T_Int8);
- os_->put(v);
- kvState_ = WS_Value;
- return sizeof(Int8Val);
- }
-
- return 0;
- }
-
- uint32_t writeInt16(int16_t v) {
- if (!stack_.empty() && verifyValueState()) {
- os_->put((FbsonTypeUnder)FbsonType::T_Int16);
- os_->write((char *)&v, sizeof(int16_t));
- kvState_ = WS_Value;
- return sizeof(Int16Val);
- }
-
- return 0;
- }
-
- uint32_t writeInt32(int32_t v) {
- if (!stack_.empty() && verifyValueState()) {
- os_->put((FbsonTypeUnder)FbsonType::T_Int32);
- os_->write((char *)&v, sizeof(int32_t));
- kvState_ = WS_Value;
- return sizeof(Int32Val);
- }
-
- return 0;
- }
-
- uint32_t writeInt64(int64_t v) {
- if (!stack_.empty() && verifyValueState()) {
- os_->put((FbsonTypeUnder)FbsonType::T_Int64);
- os_->write((char *)&v, sizeof(int64_t));
- kvState_ = WS_Value;
- return sizeof(Int64Val);
- }
-
- return 0;
- }
-
- uint32_t writeDouble(double v) {
- if (!stack_.empty() && verifyValueState()) {
- os_->put((FbsonTypeUnder)FbsonType::T_Double);
- os_->write((char *)&v, sizeof(double));
- kvState_ = WS_Value;
- return sizeof(DoubleVal);
- }
-
- return 0;
- }
-
- // must call writeStartString before writing a string val
- bool writeStartString() {
- if (!stack_.empty() && verifyValueState()) {
- os_->put((FbsonTypeUnder)FbsonType::T_String);
- str_pos_ = os_->tellp();
-
- // fill the size bytes with 0 for now
- uint32_t size = 0;
- os_->write((char *)&size, sizeof(uint32_t));
-
- kvState_ = WS_String;
- return true;
- }
-
- return false;
- }
-
- // finish writing a string val
- bool writeEndString() {
- if (kvState_ == WS_String) {
- std::streampos cur_pos = os_->tellp();
- int32_t size = cur_pos - str_pos_ - sizeof(uint32_t);
- assert(size >= 0);
-
- os_->seekp(str_pos_);
- os_->write((char *)&size, sizeof(uint32_t));
- os_->seekp(cur_pos);
-
- kvState_ = WS_Value;
- return true;
- }
-
- return false;
- }
-
- uint32_t writeString(const char *str, uint32_t len) {
- if (kvState_ == WS_String) {
- os_->write(str, len);
- return len;
- }
-
- return 0;
- }
-
- uint32_t writeString(char ch) {
- if (kvState_ == WS_String) {
- os_->put(ch);
- return 1;
- }
-
- return 0;
- }
-
- // must call writeStartBinary before writing a binary val
- bool writeStartBinary() {
- if (!stack_.empty() && verifyValueState()) {
- os_->put((FbsonTypeUnder)FbsonType::T_Binary);
- str_pos_ = os_->tellp();
-
- // fill the size bytes with 0 for now
- uint32_t size = 0;
- os_->write((char *)&size, sizeof(uint32_t));
-
- kvState_ = WS_Binary;
- return true;
- }
-
- return false;
- }
-
- // finish writing a binary val
- bool writeEndBinary() {
- if (kvState_ == WS_Binary) {
- std::streampos cur_pos = os_->tellp();
- int32_t size = cur_pos - str_pos_ - sizeof(uint32_t);
- assert(size >= 0);
-
- os_->seekp(str_pos_);
- os_->write((char *)&size, sizeof(uint32_t));
- os_->seekp(cur_pos);
-
- kvState_ = WS_Value;
- return true;
- }
-
- return false;
- }
-
- uint32_t writeBinary(const char *bin, uint32_t len) {
- if (kvState_ == WS_Binary) {
- os_->write(bin, len);
- return len;
- }
-
- return 0;
- }
-
- // must call writeStartObject before writing an object val
- bool writeStartObject() {
- if (stack_.empty() || verifyValueState()) {
- if (stack_.empty()) {
- // if this is a new FBSON, write the header
- if (!hasHdr_) {
- writeHeader();
- } else
- return false;
- }
-
- os_->put((FbsonTypeUnder)FbsonType::T_Object);
- // save the size position
- stack_.push(WriteInfo({WS_Object, os_->tellp()}));
-
- // fill the size bytes with 0 for now
- uint32_t size = 0;
- os_->write((char *)&size, sizeof(uint32_t));
-
- kvState_ = WS_Value;
- return true;
- }
-
- return false;
- }
-
- // finish writing an object val
- bool writeEndObject() {
- if (!stack_.empty() && stack_.top().state == WS_Object &&
- kvState_ == WS_Value) {
- WriteInfo &ci = stack_.top();
- std::streampos cur_pos = os_->tellp();
- int32_t size = cur_pos - ci.sz_pos - sizeof(uint32_t);
- assert(size >= 0);
-
- os_->seekp(ci.sz_pos);
- os_->write((char *)&size, sizeof(uint32_t));
- os_->seekp(cur_pos);
- stack_.pop();
-
- return true;
- }
-
- return false;
- }
-
- // must call writeStartArray before writing an array val
- bool writeStartArray() {
- if (stack_.empty() || verifyValueState()) {
- if (stack_.empty()) {
- // if this is a new FBSON, write the header
- if (!hasHdr_) {
- writeHeader();
- } else
- return false;
- }
-
- os_->put((FbsonTypeUnder)FbsonType::T_Array);
- // save the size position
- stack_.push(WriteInfo({WS_Array, os_->tellp()}));
-
- // fill the size bytes with 0 for now
- uint32_t size = 0;
- os_->write((char *)&size, sizeof(uint32_t));
-
- kvState_ = WS_Value;
- return true;
- }
-
- return false;
- }
-
- // finish writing an array val
- bool writeEndArray() {
- if (!stack_.empty() && stack_.top().state == WS_Array &&
- kvState_ == WS_Value) {
- WriteInfo &ci = stack_.top();
- std::streampos cur_pos = os_->tellp();
- int32_t size = cur_pos - ci.sz_pos - sizeof(uint32_t);
- assert(size >= 0);
-
- os_->seekp(ci.sz_pos);
- os_->write((char *)&size, sizeof(uint32_t));
- os_->seekp(cur_pos);
- stack_.pop();
-
- return true;
- }
-
- return false;
- }
-
- OS_TYPE *getOutput() { return os_; }
-
- private:
- // verify we are in the right state before writing a value
- bool verifyValueState() {
- assert(!stack_.empty());
- return (stack_.top().state == WS_Object && kvState_ == WS_Key) ||
- (stack_.top().state == WS_Array && kvState_ == WS_Value);
- }
-
- // verify we are in the right state before writing a key
- bool verifyKeyState() {
- assert(!stack_.empty());
- return stack_.top().state == WS_Object && kvState_ == WS_Value;
- }
-
- void writeHeader() {
- os_->put(FBSON_VER);
- hasHdr_ = true;
- }
-
- private:
- enum WriteState {
- WS_NONE,
- WS_Array,
- WS_Object,
- WS_Key,
- WS_Value,
- WS_String,
- WS_Binary,
- };
-
- struct WriteInfo {
- WriteState state;
- std::streampos sz_pos;
- };
-
- private:
- OS_TYPE *os_;
- bool alloc_;
- bool hasHdr_;
- WriteState kvState_; // key or value state
- std::streampos str_pos_;
- std::stack<WriteInfo> stack_;
-};
-
-typedef FbsonWriterT<FbsonOutStream> FbsonWriter;
-
-} // namespace fbson
-
-#endif // ROCKSDB_LITE
-#endif // FBSON_FBSONWRITER_H
diff --git a/third-party/rapidjson/document.h b/third-party/rapidjson/document.h
new file mode 100644
index 000000000..83d95a33d
--- /dev/null
+++ b/third-party/rapidjson/document.h
@@ -0,0 +1,821 @@
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+#include "reader.h"
+#include "internal/strfunc.h"
+#include <new> // placement new
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+#endif
+
+namespace rapidjson {
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+ A JSON value can be one of 7 types. This class is a variant type supporting
+ these types.
+
+ Use the Value if UTF8 and default allocator
+
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+*/
+#pragma pack (push, 4)
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericValue {
+public:
+ //! Name-value pair in an object.
+ struct Member {
+ GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
+ GenericValue<Encoding, Allocator> value; //!< value of member.
+ };
+
+ typedef Encoding EncodingType; //!< Encoding type from template parameter.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef Member* MemberIterator; //!< Member iterator for iterating in object.
+ typedef const Member* ConstMemberIterator; //!< Constant member iterator for iterating in object.
+ typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
+ typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor creates a null value.
+ GenericValue() : flags_(kNullFlag) {}
+
+ //! Copy constructor is not permitted.
+private:
+ GenericValue(const GenericValue& rhs);
+
+public:
+
+ //! Constructor with JSON value type.
+ /*! This creates a Value of specified type with default content.
+ \param type Type of the value.
+ \note Default content for number is zero.
+ */
+ GenericValue(Type type) {
+ static const unsigned defaultFlags[7] = {
+ kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,
+ kNumberFlag | kIntFlag | kUintFlag | kInt64Flag | kUint64Flag | kDoubleFlag
+ };
+ RAPIDJSON_ASSERT(type <= kNumberType);
+ flags_ = defaultFlags[type];
+ memset(&data_, 0, sizeof(data_));
+ }
+
+ //! Constructor for boolean value.
+ GenericValue(bool b) : flags_(b ? kTrueFlag : kFalseFlag) {}
+
+ //! Constructor for int value.
+ GenericValue(int i) : flags_(kNumberIntFlag) {
+ data_.n.i64 = i;
+ if (i >= 0)
+ flags_ |= kUintFlag | kUint64Flag;
+ }
+
+ //! Constructor for unsigned value.
+ GenericValue(unsigned u) : flags_(kNumberUintFlag) {
+ data_.n.u64 = u;
+ if (!(u & 0x80000000))
+ flags_ |= kIntFlag | kInt64Flag;
+ }
+
+ //! Constructor for int64_t value.
+ GenericValue(int64_t i64) : flags_(kNumberInt64Flag) {
+ data_.n.i64 = i64;
+ if (i64 >= 0) {
+ flags_ |= kNumberUint64Flag;
+ if (!(i64 & 0xFFFFFFFF00000000LL))
+ flags_ |= kUintFlag;
+ if (!(i64 & 0xFFFFFFFF80000000LL))
+ flags_ |= kIntFlag;
+ }
+ else if (i64 >= -2147483648LL)
+ flags_ |= kIntFlag;
+ }
+
+ //! Constructor for uint64_t value.
+ GenericValue(uint64_t u64) : flags_(kNumberUint64Flag) {
+ data_.n.u64 = u64;
+ if (!(u64 & 0x8000000000000000ULL))
+ flags_ |= kInt64Flag;
+ if (!(u64 & 0xFFFFFFFF00000000ULL))
+ flags_ |= kUintFlag;
+ if (!(u64 & 0xFFFFFFFF80000000ULL))
+ flags_ |= kIntFlag;
+ }
+
+ //! Constructor for double value.
+ GenericValue(double d) : flags_(kNumberDoubleFlag) { data_.n.d = d; }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ GenericValue(const Ch* s, SizeType length) {
+ RAPIDJSON_ASSERT(s != NULL);
+ flags_ = kConstStringFlag;
+ data_.s.str = s;
+ data_.s.length = length;
+ }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ GenericValue(const Ch* s) { SetStringRaw(s, internal::StrLen(s)); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch* s, SizeType length, Allocator& allocator) { SetStringRaw(s, length, allocator); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch*s, Allocator& allocator) { SetStringRaw(s, internal::StrLen(s), allocator); }
+
+ //! Destructor.
+ /*! Need to destruct elements of array, members of object, or copy-string.
+ */
+ ~GenericValue() {
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ switch(flags_) {
+ case kArrayFlag:
+ for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+ v->~GenericValue();
+ Allocator::Free(data_.a.elements);
+ break;
+
+ case kObjectFlag:
+ for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
+ m->name.~GenericValue();
+ m->value.~GenericValue();
+ }
+ Allocator::Free(data_.o.members);
+ break;
+
+ case kCopyStringFlag:
+ Allocator::Free(const_cast<Ch*>(data_.s.str));
+ break;
+ }
+ }
+ }
+
+ //@}
+
+ //!@name Assignment operators
+ //@{
+
+ //! Assignment with move semantics.
+ /*! \param rhs Source of the assignment. It will become a null value after assignment.
+ */
+ GenericValue& operator=(GenericValue& rhs) {
+ RAPIDJSON_ASSERT(this != &rhs);
+ this->~GenericValue();
+ memcpy(this, &rhs, sizeof(GenericValue));
+ rhs.flags_ = kNullFlag;
+ return *this;
+ }
+
+ //! Assignment with primitive types.
+ /*! \tparam T Either Type, int, unsigned, int64_t, uint64_t, const Ch*
+ \param value The value to be assigned.
+ */
+ template <typename T>
+ GenericValue& operator=(T value) {
+ this->~GenericValue();
+ new (this) GenericValue(value);
+ return *this;
+ }
+ //@}
+
+ //!@name Type
+ //@{
+
+ Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); }
+ bool IsNull() const { return flags_ == kNullFlag; }
+ bool IsFalse() const { return flags_ == kFalseFlag; }
+ bool IsTrue() const { return flags_ == kTrueFlag; }
+ bool IsBool() const { return (flags_ & kBoolFlag) != 0; }
+ bool IsObject() const { return flags_ == kObjectFlag; }
+ bool IsArray() const { return flags_ == kArrayFlag; }
+ bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
+ bool IsInt() const { return (flags_ & kIntFlag) != 0; }
+ bool IsUint() const { return (flags_ & kUintFlag) != 0; }
+ bool IsInt64() const { return (flags_ & kInt64Flag) != 0; }
+ bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }
+ bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
+ bool IsString() const { return (flags_ & kStringFlag) != 0; }
+
+ //@}
+
+ //!@name Null
+ //@{
+
+ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
+
+ //@}
+
+ //!@name Bool
+ //@{
+
+ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
+ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
+
+ //@}
+
+ //!@name Object
+ //@{
+
+ //! Set this value as an empty object.
+ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
+
+ //! Get the value associated with the object's name.
+ GenericValue& operator[](const Ch* name) {
+ if (Member* member = FindMember(name))
+ return member->value;
+ else {
+ static GenericValue NullValue;
+ return NullValue;
+ }
+ }
+ const GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+ //! Member iterators.
+ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
+ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
+ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
+ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
+
+ //! Check whether a member exists in the object.
+ bool HasMember(const Ch* name) const { return FindMember(name) != 0; }
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory.
+ \return The value itself for fluent API.
+ \note The ownership of name and value will be transfered to this object if success.
+ */
+ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+ Object& o = data_.o;
+ if (o.size >= o.capacity) {
+ if (o.capacity == 0) {
+ o.capacity = kDefaultObjectCapacity;
+ o.members = (Member*)allocator.Malloc(o.capacity * sizeof(Member));
+ }
+ else {
+ SizeType oldCapacity = o.capacity;
+ o.capacity *= 2;
+ o.members = (Member*)allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member));
+ }
+ }
+ o.members[o.size].name.RawAssign(name);
+ o.members[o.size].value.RawAssign(value);
+ o.size++;
+ return *this;
+ }
+
+ GenericValue& AddMember(const Ch* name, Allocator& nameAllocator, GenericValue& value, Allocator& allocator) {
+ GenericValue n(name, internal::StrLen(name), nameAllocator);
+ return AddMember(n, value, allocator);
+ }
+
+ GenericValue& AddMember(const Ch* name, GenericValue& value, Allocator& allocator) {
+ GenericValue n(name, internal::StrLen(name));
+ return AddMember(n, value, allocator);
+ }
+
+ template <typename T>
+ GenericValue& AddMember(const Ch* name, T value, Allocator& allocator) {
+ GenericValue n(name, internal::StrLen(name));
+ GenericValue v(value);
+ return AddMember(n, v, allocator);
+ }
+
+ //! Remove a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note Removing member is implemented by moving the last member. So the ordering of members is changed.
+ */
+ bool RemoveMember(const Ch* name) {
+ RAPIDJSON_ASSERT(IsObject());
+ if (Member* m = FindMember(name)) {
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(data_.o.members != 0);
+
+ Member* last = data_.o.members + (data_.o.size - 1);
+ if (data_.o.size > 1 && m != last) {
+ // Move the last one to this place
+ m->name = last->name;
+ m->value = last->value;
+ }
+ else {
+ // Only one left, just destroy
+ m->name.~GenericValue();
+ m->value.~GenericValue();
+ }
+ --data_.o.size;
+ return true;
+ }
+ return false;
+ }
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Set this value as an empty array.
+ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
+
+ //! Get the number of elements in array.
+ SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
+
+ //! Get the capacity of array.
+ SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
+
+ //! Check whether the array is empty.
+ bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
+
+ //! Remove all elements in the array.
+ /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
+ */
+ void Clear() {
+ RAPIDJSON_ASSERT(IsArray());
+ for (SizeType i = 0; i < data_.a.size; ++i)
+ data_.a.elements[i].~GenericValue();
+ data_.a.size = 0;
+ }
+
+ //! Get an element from array by index.
+ /*! \param index Zero-based index of element.
+ \note
+\code
+Value a(kArrayType);
+a.PushBack(123);
+int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
+int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
+int z = a[0u].GetInt(); // This works too.
+\endcode
+ */
+ GenericValue& operator[](SizeType index) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(index < data_.a.size);
+ return data_.a.elements[index];
+ }
+ const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
+
+ //! Element iterator
+ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
+ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
+ ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
+ ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
+
+ //! Request the array to have enough capacity to store elements.
+ /*! \param newCapacity The capacity that the array at least need to have.
+ \param allocator The allocator for allocating memory. It must be the same one use previously.
+ \return The value itself for fluent API.
+ */
+ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (newCapacity > data_.a.capacity) {
+ data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));
+ data_.a.capacity = newCapacity;
+ }
+ return *this;
+ }
+
+ //! Append a value at the end of the array.
+ /*! \param value The value to be appended.
+ \param allocator The allocator for allocating memory. It must be the same one use previously.
+ \return The value itself for fluent API.
+ \note The ownership of the value will be transfered to this object if success.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ */
+ GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (data_.a.size >= data_.a.capacity)
+ Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator);
+ data_.a.elements[data_.a.size++].RawAssign(value);
+ return *this;
+ }
+
+ template <typename T>
+ GenericValue& PushBack(T value, Allocator& allocator) {
+ GenericValue v(value);
+ return PushBack(v, allocator);
+ }
+
+ //! Remove the last element in the array.
+ GenericValue& PopBack() {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(!Empty());
+ data_.a.elements[--data_.a.size].~GenericValue();
+ return *this;
+ }
+ //@}
+
+ //!@name Number
+ //@{
+
+ int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; }
+ unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; }
+ int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
+ uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
+
+ double GetDouble() const {
+ RAPIDJSON_ASSERT(IsNumber());
+ if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
+ if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
+ if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
+ if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision)
+ RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision)
+ }
+
+ GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
+ GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
+ GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
+ GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
+ GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
+
+ //@}
+
+ //!@name String
+ //@{
+
+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
+
+ //! Get the length of string.
+ /*! Since rapidjson permits "\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
+ */
+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; }
+
+ //! Set this value as a string without copying source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string pointer.
+ \param length The length of source string, excluding the trailing null terminator.
+ \return The value itself for fluent API.
+ */
+ GenericValue& SetString(const Ch* s, SizeType length) { this->~GenericValue(); SetStringRaw(s, length); return *this; }
+
+ //! Set this value as a string without copying source string.
+ /*! \param s source string pointer.
+ \return The value itself for fluent API.
+ */
+ GenericValue& SetString(const Ch* s) { return SetString(s, internal::StrLen(s)); }
+
+ //! Set this value as a string by copying from source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string.
+ \param length The length of source string, excluding the trailing null terminator.
+ \param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
+ \return The value itself for fluent API.
+ */
+ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, length, allocator); return *this; }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
+ \return The value itself for fluent API.
+ */
+ GenericValue& SetString(const Ch* s, Allocator& allocator) { SetString(s, internal::StrLen(s), allocator); return *this; }
+
+ //@}
+
+ //! Generate events of this value to a Handler.
+ /*! This function adopts the GoF visitor pattern.
+ Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
+ It can also be used to deep clone this value via GenericDocument, which is also a Handler.
+ \tparam Handler type of handler.
+ \param handler An object implementing concept Handler.
+ */
+ template <typename Handler>
+ const GenericValue& Accept(Handler& handler) const {
+ switch(GetType()) {
+ case kNullType: handler.Null(); break;
+ case kFalseType: handler.Bool(false); break;
+ case kTrueType: handler.Bool(true); break;
+
+ case kObjectType:
+ handler.StartObject();
+ for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
+ handler.String(m->name.data_.s.str, m->name.data_.s.length, false);
+ m->value.Accept(handler);
+ }
+ handler.EndObject(data_.o.size);
+ break;
+
+ case kArrayType:
+ handler.StartArray();
+ for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+ v->Accept(handler);
+ handler.EndArray(data_.a.size);
+ break;
+
+ case kStringType:
+ handler.String(data_.s.str, data_.s.length, false);
+ break;
+
+ case kNumberType:
+ if (IsInt()) handler.Int(data_.n.i.i);
+ else if (IsUint()) handler.Uint(data_.n.u.u);
+ else if (IsInt64()) handler.Int64(data_.n.i64);
+ else if (IsUint64()) handler.Uint64(data_.n.u64);
+ else handler.Double(data_.n.d);
+ break;
+ }
+ return *this;
+ }
+
+private:
+ template <typename, typename>
+ friend class GenericDocument;
+
+ enum {
+ kBoolFlag = 0x100,
+ kNumberFlag = 0x200,
+ kIntFlag = 0x400,
+ kUintFlag = 0x800,
+ kInt64Flag = 0x1000,
+ kUint64Flag = 0x2000,
+ kDoubleFlag = 0x4000,
+ kStringFlag = 0x100000,
+ kCopyFlag = 0x200000,
+
+ // Initial flags of different types.
+ kNullFlag = kNullType,
+ kTrueFlag = kTrueType | kBoolFlag,
+ kFalseFlag = kFalseType | kBoolFlag,
+ kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+ kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+ kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+ kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+ kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+ kConstStringFlag = kStringType | kStringFlag,
+ kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+ kObjectFlag = kObjectType,
+ kArrayFlag = kArrayType,
+
+ kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
+ };
+
+ static const SizeType kDefaultArrayCapacity = 16;
+ static const SizeType kDefaultObjectCapacity = 16;
+
+ struct String {
+ const Ch* str;
+ SizeType length;
+ unsigned hashcode; //!< reserved
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // By using proper binary layout, retrieval of different integer types do not need conversions.
+ union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+ struct I {
+ int i;
+ char padding[4];
+ }i;
+ struct U {
+ unsigned u;
+ char padding2[4];
+ }u;
+#else
+ struct I {
+ char padding[4];
+ int i;
+ }i;
+ struct U {
+ char padding2[4];
+ unsigned u;
+ }u;
+#endif
+ int64_t i64;
+ uint64_t u64;
+ double d;
+ }; // 8 bytes
+
+ struct Object {
+ Member* members;
+ SizeType size;
+ SizeType capacity;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ struct Array {
+ GenericValue<Encoding, Allocator>* elements;
+ SizeType size;
+ SizeType capacity;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ union Data {
+ String s;
+ Number n;
+ Object o;
+ Array a;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ //! Find member by name.
+ Member* FindMember(const Ch* name) {
+ RAPIDJSON_ASSERT(name);
+ RAPIDJSON_ASSERT(IsObject());
+
+ SizeType length = internal::StrLen(name);
+
+ Object& o = data_.o;
+ for (Member* member = o.members; member != data_.o.members + data_.o.size; ++member)
+ if (length == member->name.data_.s.length && memcmp(member->name.data_.s.str, name, length * sizeof(Ch)) == 0)
+ return member;
+
+ return 0;
+ }
+ const Member* FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+ // Initialize this value as array with initial data, without calling destructor.
+ void SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) {
+ flags_ = kArrayFlag;
+ data_.a.elements = (GenericValue*)alloctaor.Malloc(count * sizeof(GenericValue));
+ memcpy(data_.a.elements, values, count * sizeof(GenericValue));
+ data_.a.size = data_.a.capacity = count;
+ }
+
+ //! Initialize this value as object with initial data, without calling destructor.
+ void SetObjectRaw(Member* members, SizeType count, Allocator& alloctaor) {
+ flags_ = kObjectFlag;
+ data_.o.members = (Member*)alloctaor.Malloc(count * sizeof(Member));
+ memcpy(data_.o.members, members, count * sizeof(Member));
+ data_.o.size = data_.o.capacity = count;
+ }
+
+ //! Initialize this value as constant string, without calling destructor.
+ void SetStringRaw(const Ch* s, SizeType length) {
+ RAPIDJSON_ASSERT(s != NULL);
+ flags_ = kConstStringFlag;
+ data_.s.str = s;
+ data_.s.length = length;
+ }
+
+ //! Initialize this value as copy string with initial data, without calling destructor.
+ void SetStringRaw(const Ch* s, SizeType length, Allocator& allocator) {
+ RAPIDJSON_ASSERT(s != NULL);
+ flags_ = kCopyStringFlag;
+ data_.s.str = (Ch *)allocator.Malloc((length + 1) * sizeof(Ch));
+ data_.s.length = length;
+ memcpy(const_cast<Ch*>(data_.s.str), s, length * sizeof(Ch));
+ const_cast<Ch*>(data_.s.str)[length] = '\0';
+ }
+
+ //! Assignment without calling destructor
+ void RawAssign(GenericValue& rhs) {
+ memcpy(this, &rhs, sizeof(GenericValue));
+ rhs.flags_ = kNullFlag;
+ }
+
+ Data data_;
+ unsigned flags_;
+};
+#pragma pack (pop)
+
+//! Value with UTF8 encoding.
+typedef GenericValue<UTF8<> > Value;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericDocument
+
+//! A document for parsing JSON text as DOM.
+/*!
+ \implements Handler
+ \tparam Encoding encoding for both parsing and string storage.
+ \tparam Alloactor allocator for allocating memory for the DOM, and the stack during parsing.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+public:
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+
+ //! Constructor
+ /*! \param allocator Optional allocator for allocating stack memory.
+ \param stackCapacity Initial capacity of stack in bytes.
+ */
+ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
+
+ //! Parse JSON text from an input stream.
+ /*! \tparam parseFlags Combination of ParseFlag.
+ \param stream Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename Stream>
+ GenericDocument& ParseStream(Stream& stream) {
+ ValueType::SetNull(); // Remove existing root if exist
+ GenericReader<Encoding, Allocator> reader;
+ if (reader.template Parse<parseFlags>(stream, *this)) {
+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+ this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13.
+ parseError_ = 0;
+ errorOffset_ = 0;
+ }
+ else {
+ parseError_ = reader.GetParseError();
+ errorOffset_ = reader.GetErrorOffset();
+ ClearStack();
+ }
+ return *this;
+ }
+
+ //! Parse JSON text from a mutable string.
+ /*! \tparam parseFlags Combination of ParseFlag.
+ \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& ParseInsitu(Ch* str) {
+ GenericInsituStringStream<Encoding> s(str);
+ return ParseStream<parseFlags | kParseInsituFlag>(s);
+ }
+
+ //! Parse JSON text from a read-only string.
+ /*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag).
+ \param str Read-only zero-terminated string to be parsed.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const Ch* str) {
+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+ GenericStringStream<Encoding> s(str);
+ return ParseStream<parseFlags>(s);
+ }
+
+ //! Whether a parse error was occured in the last parsing.
+ bool HasParseError() const { return parseError_ != 0; }
+
+ //! Get the message of parsing error.
+ const char* GetParseError() const { return parseError_; }
+
+ //! Get the offset in character of the parsing error.
+ size_t GetErrorOffset() const { return errorOffset_; }
+
+ //! Get the allocator of this document.
+ Allocator& GetAllocator() { return stack_.GetAllocator(); }
+
+ //! Get the capacity of stack in bytes.
+ size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+
+private:
+ // Prohibit assignment
+ GenericDocument& operator=(const GenericDocument&);
+
+ friend class GenericReader<Encoding, Allocator>; // for Reader to call the following private handler functions
+
+ // Implementation of Handler
+ void Null() { new (stack_.template Push<ValueType>()) ValueType(); }
+ void Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); }
+ void Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+ void Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+ void Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+ void Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
+ void Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); }
+
+ void String(const Ch* str, SizeType length, bool copy) {
+ if (copy)
+ new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+ else
+ new (stack_.template Push<ValueType>()) ValueType(str, length);
+ }
+
+ void StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); }
+
+ void EndObject(SizeType memberCount) {
+ typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
+ stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
+ }
+
+ void StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); }
+
+ void EndArray(SizeType elementCount) {
+ ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+ stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
+ }
+
+ void ClearStack() {
+ if (Allocator::kNeedFree)
+ while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
+ (stack_.template Pop<ValueType>(1))->~ValueType();
+ else
+ stack_.Clear();
+ }
+
+ static const size_t kDefaultStackCapacity = 1024;
+ internal::Stack<Allocator> stack_;
+ const char* parseError_;
+ size_t errorOffset_;
+};
+
+typedef GenericDocument<UTF8<> > Document;
+
+} // namespace rapidjson
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/third-party/rapidjson/filestream.h b/third-party/rapidjson/filestream.h
new file mode 100644
index 000000000..885894963
--- /dev/null
+++ b/third-party/rapidjson/filestream.h
@@ -0,0 +1,46 @@
+#ifndef RAPIDJSON_FILESTREAM_H_
+#define RAPIDJSON_FILESTREAM_H_
+
+#include <cstdio>
+
+namespace rapidjson {
+
+//! Wrapper of C file stream for input or output.
+/*!
+ This simple wrapper does not check the validity of the stream.
+ \implements Stream
+*/
+class FileStream {
+public:
+ typedef char Ch; //!< Character type. Only support char.
+
+ FileStream(FILE* fp) : fp_(fp), count_(0) { Read(); }
+ char Peek() const { return current_; }
+ char Take() { char c = current_; Read(); return c; }
+ size_t Tell() const { return count_; }
+ void Put(char c) { fputc(c, fp_); }
+
+ // Not implemented
+ char* PutBegin() { return 0; }
+ size_t PutEnd(char*) { return 0; }
+
+private:
+ void Read() {
+ RAPIDJSON_ASSERT(fp_ != 0);
+ int c = fgetc(fp_);
+ if (c != EOF) {
+ current_ = (char)c;
+ count_++;
+ }
+ else
+ current_ = '\0';
+ }
+
+ FILE* fp_;
+ char current_;
+ size_t count_;
+};
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/third-party/rapidjson/internal/pow10.h b/third-party/rapidjson/internal/pow10.h
new file mode 100644
index 000000000..bf3a9afb0
--- /dev/null
+++ b/third-party/rapidjson/internal/pow10.h
@@ -0,0 +1,54 @@
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+namespace rapidjson {
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+ \param n positive/negative exponent. Must <= 308.
+ \return 10.0^n
+*/
+inline double Pow10(int n) {
+ static const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes
+ 1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300,
+ 1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280,
+ 1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260,
+ 1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240,
+ 1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220,
+ 1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200,
+ 1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180,
+ 1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160,
+ 1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140,
+ 1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120,
+ 1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100,
+ 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80,
+ 1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60,
+ 1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40,
+ 1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20,
+ 1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e+0,
+ 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
+ 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
+ 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
+ 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+ 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
+ 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
+ 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
+ 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
+ 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
+ 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
+ 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
+ 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
+ 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
+ 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
+ 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
+ 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
+ };
+ RAPIDJSON_ASSERT(n <= 308);
+ return n < -308 ? 0.0 : e[n + 308];
+}
+
+} // namespace internal
+} // namespace rapidjson
+
+#endif // RAPIDJSON_POW10_
diff --git a/third-party/rapidjson/internal/stack.h b/third-party/rapidjson/internal/stack.h
new file mode 100644
index 000000000..966893b3f
--- /dev/null
+++ b/third-party/rapidjson/internal/stack.h
@@ -0,0 +1,82 @@
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+namespace rapidjson {
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+*/
+template <typename Allocator>
+class Stack {
+public:
+ Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {
+ RAPIDJSON_ASSERT(stack_capacity_ > 0);
+ if (!allocator_)
+ own_allocator_ = allocator_ = new Allocator();
+ stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);
+ stack_end_ = stack_ + stack_capacity_;
+ }
+
+ ~Stack() {
+ Allocator::Free(stack_);
+ delete own_allocator_; // Only delete if it is owned by the stack
+ }
+
+ void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
+
+ template<typename T>
+ T* Push(size_t count = 1) {
+ // Expand the stack if needed
+ if (stack_top_ + sizeof(T) * count >= stack_end_) {
+ size_t new_capacity = stack_capacity_ * 2;
+ size_t size = GetSize();
+ size_t new_size = GetSize() + sizeof(T) * count;
+ if (new_capacity < new_size)
+ new_capacity = new_size;
+ stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity);
+ stack_capacity_ = new_capacity;
+ stack_top_ = stack_ + size;
+ stack_end_ = stack_ + stack_capacity_;
+ }
+ T* ret = (T*)stack_top_;
+ stack_top_ += sizeof(T) * count;
+ return ret;
+ }
+
+ template<typename T>
+ T* Pop(size_t count) {
+ RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+ stack_top_ -= count * sizeof(T);
+ return (T*)stack_top_;
+ }
+
+ template<typename T>
+ T* Top() {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return (T*)(stack_top_ - sizeof(T));
+ }
+
+ template<typename T>
+ T* Bottom() { return (T*)stack_; }
+
+ Allocator& GetAllocator() { return *allocator_; }
+ size_t GetSize() const { return stack_top_ - stack_; }
+ size_t GetCapacity() const { return stack_capacity_; }
+
+private:
+ Allocator* allocator_;
+ Allocator* own_allocator_;
+ char *stack_;
+ char *stack_top_;
+ char *stack_end_;
+ size_t stack_capacity_;
+};
+
+} // namespace internal
+} // namespace rapidjson
+
+#endif // RAPIDJSON_STACK_H_
diff --git a/third-party/rapidjson/internal/strfunc.h b/third-party/rapidjson/internal/strfunc.h
new file mode 100644
index 000000000..bbf444fe6
--- /dev/null
+++ b/third-party/rapidjson/internal/strfunc.h
@@ -0,0 +1,24 @@
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+namespace rapidjson {
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+ \param s Null-terminated input string.
+ \return Number of characters in the string.
+ \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+ const Ch* p = s;
+ while (*p != '\0')
+ ++p;
+ return SizeType(p - s);
+}
+
+} // namespace internal
+} // namespace rapidjson
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
diff --git a/third-party/rapidjson/license.txt b/third-party/rapidjson/license.txt
new file mode 100644
index 000000000..03d97d163
--- /dev/null
+++ b/third-party/rapidjson/license.txt
@@ -0,0 +1,19 @@
+Copyright (C) 2011 Milo Yip
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. \ No newline at end of file
diff --git a/third-party/rapidjson/prettywriter.h b/third-party/rapidjson/prettywriter.h
new file mode 100644
index 000000000..238ff5ff6
--- /dev/null
+++ b/third-party/rapidjson/prettywriter.h
@@ -0,0 +1,156 @@
+#ifndef RAPIDJSON_PRETTYWRITER_H_
+#define RAPIDJSON_PRETTYWRITER_H_
+
+#include "writer.h"
+
+namespace rapidjson {
+
+//! Writer with indentation and spacing.
+/*!
+ \tparam Stream Type of ouptut stream.
+ \tparam Encoding Encoding of both source strings and output.
+ \tparam Allocator Type of allocator for allocating memory of stack.
+*/
+template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
+class PrettyWriter : public Writer<Stream, Encoding, Allocator> {
+public:
+ typedef Writer<Stream, Encoding, Allocator> Base;
+ typedef typename Base::Ch Ch;
+
+ //! Constructor
+ /*! \param stream Output stream.
+ \param allocator User supplied allocator. If it is null, it will create a private one.
+ \param levelDepth Initial capacity of
+ */
+ PrettyWriter(Stream& stream, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
+ Base(stream, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+
+ //! Set custom indentation.
+ /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
+ \param indentCharCount Number of indent characters for each indentation level.
+ \note The default indentation is 4 spaces.
+ */
+ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
+ RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
+ indentChar_ = indentChar;
+ indentCharCount_ = indentCharCount;
+ return *this;
+ }
+
+ //@name Implementation of Handler.
+ //@{
+
+ PrettyWriter& Null() { PrettyPrefix(kNullType); Base::WriteNull(); return *this; }
+ PrettyWriter& Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; }
+ PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; }
+ PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; }
+ PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; }
+ PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; }
+ PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; }
+
+ PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ PrettyPrefix(kStringType);
+ Base::WriteString(str, length);
+ return *this;
+ }
+
+ PrettyWriter& StartObject() {
+ PrettyPrefix(kObjectType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
+ Base::WriteStartObject();
+ return *this;
+ }
+
+ PrettyWriter& EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty) {
+ Base::stream_.Put('\n');
+ WriteIndent();
+ }
+ Base::WriteEndObject();
+ return *this;
+ }
+
+ PrettyWriter& StartArray() {
+ PrettyPrefix(kArrayType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
+ Base::WriteStartArray();
+ return *this;
+ }
+
+ PrettyWriter& EndArray(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty) {
+ Base::stream_.Put('\n');
+ WriteIndent();
+ }
+ Base::WriteEndArray();
+ return *this;
+ }
+
+ //@}
+
+ //! Simpler but slower overload.
+ PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); }
+
+protected:
+ void PrettyPrefix(Type type) {
+ (void)type;
+ if (Base::level_stack_.GetSize() != 0) { // this value is not at root
+ typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
+
+ if (level->inArray) {
+ if (level->valueCount > 0) {
+ Base::stream_.Put(','); // add comma if it is not the first element in array
+ Base::stream_.Put('\n');
+ }
+ else
+ Base::stream_.Put('\n');
+ WriteIndent();
+ }
+ else { // in object
+ if (level->valueCount > 0) {
+ if (level->valueCount % 2 == 0) {
+ Base::stream_.Put(',');
+ Base::stream_.Put('\n');
+ }
+ else {
+ Base::stream_.Put(':');
+ Base::stream_.Put(' ');
+ }
+ }
+ else
+ Base::stream_.Put('\n');
+
+ if (level->valueCount % 2 == 0)
+ WriteIndent();
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else
+ RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
+ }
+
+ void WriteIndent() {
+ size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
+ PutN(Base::stream_, indentChar_, count);
+ }
+
+ Ch indentChar_;
+ unsigned indentCharCount_;
+};
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/third-party/rapidjson/rapidjson.h b/third-party/rapidjson/rapidjson.h
new file mode 100644
index 000000000..7acb2aa4f
--- /dev/null
+++ b/third-party/rapidjson/rapidjson.h
@@ -0,0 +1,525 @@
+#ifndef RAPIDJSON_RAPIDJSON_H_
+#define RAPIDJSON_RAPIDJSON_H_
+
+// Copyright (c) 2011-2012 Milo Yip (miloyip@gmail.com)
+// Version 0.11
+
+#include <cstdlib> // malloc(), realloc(), free()
+#include <cstring> // memcpy()
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_INT64DEFINE
+
+// Here defines int64_t and uint64_t types in global namespace.
+// If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this.
+#ifndef RAPIDJSON_NO_INT64DEFINE
+#ifdef _MSC_VER
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <inttypes.h>
+#endif
+#endif // RAPIDJSON_NO_INT64TYPEDEF
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ENDIAN
+#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
+#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
+
+//! Endianness of the machine.
+/*! GCC provided macro for detecting endianness of the target machine. But other
+ compilers may not have this. User can define RAPIDJSON_ENDIAN to either
+ RAPIDJSON_LITTLEENDIAN or RAPIDJSON_BIGENDIAN.
+*/
+#ifndef RAPIDJSON_ENDIAN
+#ifdef __BYTE_ORDER__
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#else
+#define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+#endif // __BYTE_ORDER__
+#else
+#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN // Assumes little endian otherwise.
+#endif
+#endif // RAPIDJSON_ENDIAN
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
+
+// Enable SSE2 optimization.
+//#define RAPIDJSON_SSE2
+
+// Enable SSE4.2 optimization.
+//#define RAPIDJSON_SSE42
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+#define RAPIDJSON_SIMD
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_SIZETYPEDEFINE
+
+#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
+namespace rapidjson {
+//! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t.
+/*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE.
+*/
+typedef unsigned SizeType;
+} // namespace rapidjson
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ASSERT
+
+//! Assertion.
+/*! By default, rapidjson uses C assert() for assertion.
+ User can override it by defining RAPIDJSON_ASSERT(x) macro.
+*/
+#ifndef RAPIDJSON_ASSERT
+#include <cassert>
+#define RAPIDJSON_ASSERT(x) assert(x)
+#endif // RAPIDJSON_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
+#define RAPIDJSON_MULTILINEMACRO_END \
+} while((void)0, 0)
+
+namespace rapidjson {
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+ \brief Concept for allocating, resizing and freeing memory block.
+
+ Note that Malloc() and Realloc() are non-static but Free() is static.
+
+ So if an allocator need to support Free(), it needs to put its pointer in
+ the header of memory block.
+
+\code
+concept Allocator {
+ static const bool kNeedFree; //!< Whether this allocator needs to call Free().
+
+ // Allocate a memory block.
+ // \param size of the memory block in bytes.
+ // \returns pointer to the memory block.
+ void* Malloc(size_t size);
+
+ // Resize a memory block.
+ // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+ // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+ // \param newSize the new size in bytes.
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+ // Free a memory block.
+ // \param pointer to the memory block. Null pointer is permitted.
+ static void Free(void *ptr);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+ \implements Allocator
+*/
+class CrtAllocator {
+public:
+ static const bool kNeedFree = true;
+ void* Malloc(size_t size) { return malloc(size); }
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); }
+ static void Free(void *ptr) { free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks.
+
+ It does not free memory blocks. And Realloc() only allocate new memory.
+
+ The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+ User may also supply a buffer as the first chunk.
+
+ If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+ The user-buffer is not deallocated by this allocator.
+
+ \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+ \implements Allocator
+*/
+template <typename BaseAllocator = CrtAllocator>
+class MemoryPoolAllocator {
+public:
+ static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+ //! Constructor with chunkSize.
+ /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ if (!baseAllocator_)
+ ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
+ AddChunk(chunk_capacity_);
+ }
+
+ //! Constructor with user-supplied buffer.
+ /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+ The user buffer will not be deallocated when this allocator is destructed.
+
+ \param buffer User supplied buffer.
+ \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+ \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ RAPIDJSON_ASSERT(buffer != 0);
+ RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+ chunkHead_ = (ChunkHeader*)buffer;
+ chunkHead_->capacity = size - sizeof(ChunkHeader);
+ chunkHead_->size = 0;
+ chunkHead_->next = 0;
+ }
+
+ //! Destructor.
+ /*! This deallocates all memory chunks, excluding the user-supplied buffer.
+ */
+ ~MemoryPoolAllocator() {
+ Clear();
+ delete ownBaseAllocator_;
+ }
+
+ //! Deallocates all memory chunks, excluding the user-supplied buffer.
+ void Clear() {
+ while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) {
+ ChunkHeader* next = chunkHead_->next;
+ baseAllocator_->Free(chunkHead_);
+ chunkHead_ = next;
+ }
+ }
+
+ //! Computes the total capacity of allocated memory chunks.
+ /*! \return total capacity in bytes.
+ */
+ size_t Capacity() {
+ size_t capacity = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ capacity += c->capacity;
+ return capacity;
+ }
+
+ //! Computes the memory blocks allocated.
+ /*! \return total used bytes.
+ */
+ size_t Size() {
+ size_t size = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ size += c->size;
+ return size;
+ }
+
+ //! Allocates a memory block. (concept Allocator)
+ void* Malloc(size_t size) {
+ size = (size + 3) & ~3; // Force aligning size to 4
+
+ if (chunkHead_->size + size > chunkHead_->capacity)
+ AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
+
+ char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size;
+ RAPIDJSON_ASSERT(((uintptr_t)buffer & 3) == 0); // returned buffer is aligned to 4
+ chunkHead_->size += size;
+
+ return buffer;
+ }
+
+ //! Resizes a memory block (concept Allocator)
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ if (originalPtr == 0)
+ return Malloc(newSize);
+
+ // Do not shrink if new size is smaller than original
+ if (originalSize >= newSize)
+ return originalPtr;
+
+ // Simply expand it if it is the last allocation and there is sufficient space
+ if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
+ size_t increment = newSize - originalSize;
+ increment = (increment + 3) & ~3; // Force aligning size to 4
+ if (chunkHead_->size + increment <= chunkHead_->capacity) {
+ chunkHead_->size += increment;
+ RAPIDJSON_ASSERT(((uintptr_t)originalPtr & 3) == 0); // returned buffer is aligned to 4
+ return originalPtr;
+ }
+ }
+
+ // Realloc process: allocate and copy memory, do not free original buffer.
+ void* newBuffer = Malloc(newSize);
+ RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
+ return memcpy(newBuffer, originalPtr, originalSize);
+ }
+
+ //! Frees a memory block (concept Allocator)
+ static void Free(void *) {} // Do nothing
+
+private:
+ //! Creates a new chunk.
+ /*! \param capacity Capacity of the chunk in bytes.
+ */
+ void AddChunk(size_t capacity) {
+ ChunkHeader* chunk = (ChunkHeader*)baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity);
+ chunk->capacity = capacity;
+ chunk->size = 0;
+ chunk->next = chunkHead_;
+ chunkHead_ = chunk;
+ }
+
+ static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
+
+ //! Chunk header for perpending to each chunk.
+ /*! Chunks are stored as a singly linked list.
+ */
+ struct ChunkHeader {
+ size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
+ size_t size; //!< Current size of allocated memory in bytes.
+ ChunkHeader *next; //!< Next chunk in the linked list.
+ };
+
+ ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+ size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
+ char *userBuffer_; //!< User supplied buffer.
+ BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
+ BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Encoding
+
+/*! \class rapidjson::Encoding
+ \brief Concept for encoding of Unicode characters.
+
+\code
+concept Encoding {
+ typename Ch; //! Type of character.
+
+ //! \brief Encode a Unicode codepoint to a buffer.
+ //! \param buffer pointer to destination buffer to store the result. It should have sufficient size of encoding one character.
+ //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
+ //! \returns the pointer to the next character after the encoded data.
+ static Ch* Encode(Ch *buffer, unsigned codepoint);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8
+
+//! UTF-8 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-8
+ \tparam CharType Type for storing 8-bit UTF-8 data. Default is char.
+ \implements Encoding
+*/
+template<typename CharType = char>
+struct UTF8 {
+ typedef CharType Ch;
+
+ static Ch* Encode(Ch *buffer, unsigned codepoint) {
+ if (codepoint <= 0x7F)
+ *buffer++ = codepoint & 0xFF;
+ else if (codepoint <= 0x7FF) {
+ *buffer++ = 0xC0 | ((codepoint >> 6) & 0xFF);
+ *buffer++ = 0x80 | ((codepoint & 0x3F));
+ }
+ else if (codepoint <= 0xFFFF) {
+ *buffer++ = 0xE0 | ((codepoint >> 12) & 0xFF);
+ *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
+ *buffer++ = 0x80 | (codepoint & 0x3F);
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ *buffer++ = 0xF0 | ((codepoint >> 18) & 0xFF);
+ *buffer++ = 0x80 | ((codepoint >> 12) & 0x3F);
+ *buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
+ *buffer++ = 0x80 | (codepoint & 0x3F);
+ }
+ return buffer;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF16
+
+//! UTF-16 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-16
+ \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
+ \implements Encoding
+*/
+template<typename CharType = wchar_t>
+struct UTF16 {
+ typedef CharType Ch;
+
+ static Ch* Encode(Ch* buffer, unsigned codepoint) {
+ if (codepoint <= 0xFFFF) {
+ RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
+ *buffer++ = static_cast<Ch>(codepoint);
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ unsigned v = codepoint - 0x10000;
+ *buffer++ = static_cast<Ch>((v >> 10) + 0xD800);
+ *buffer++ = (v & 0x3FF) + 0xDC00;
+ }
+ return buffer;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF32
+
+//! UTF-32 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-32
+ \tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
+ \implements Encoding
+*/
+template<typename CharType = unsigned>
+struct UTF32 {
+ typedef CharType Ch;
+
+ static Ch *Encode(Ch* buffer, unsigned codepoint) {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ *buffer++ = codepoint;
+ return buffer;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Stream
+
+/*! \class rapidjson::Stream
+ \brief Concept for reading and writing characters.
+
+ For read-only stream, no need to implement PutBegin(), Put() and PutEnd().
+
+ For write-only stream, only need to implement Put().
+
+\code
+concept Stream {
+ typename Ch; //!< Character type of the stream.
+
+ //! Read the current character from stream without moving the read cursor.
+ Ch Peek() const;
+
+ //! Read the current character from stream and moving the read cursor to next character.
+ Ch Take();
+
+ //! Get the current read cursor.
+ //! \return Number of characters read from start.
+ size_t Tell();
+
+ //! Begin writing operation at the current read pointer.
+ //! \return The begin writer pointer.
+ Ch* PutBegin();
+
+ //! Write a character.
+ void Put(Ch c);
+
+ //! End the writing operation.
+ //! \param begin The begin write pointer returned by PutBegin().
+ //! \return Number of characters written.
+ size_t PutEnd(Ch* begin);
+}
+\endcode
+*/
+
+//! Put N copies of a character to a stream.
+template<typename Stream, typename Ch>
+inline void PutN(Stream& stream, Ch c, size_t n) {
+ for (size_t i = 0; i < n; i++)
+ stream.Put(c);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream
+
+//! Read-only string stream.
+/*! \implements Stream
+*/
+template <typename Encoding>
+struct GenericStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringStream(const Ch *src) : src_(src), head_(src) {}
+
+ Ch Peek() const { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() const { return src_ - head_; }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ const Ch* src_; //!< Current read position.
+ const Ch* head_; //!< Original head of the string.
+};
+
+typedef GenericStringStream<UTF8<> > StringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// InsituStringStream
+
+//! A read-write string stream.
+/*! This string stream is particularly designed for in-situ parsing.
+ \implements Stream
+*/
+template <typename Encoding>
+struct GenericInsituStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
+
+ // Read
+ Ch Peek() { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() { return src_ - head_; }
+
+ // Write
+ Ch* PutBegin() { return dst_ = src_; }
+ void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
+ size_t PutEnd(Ch* begin) { return dst_ - begin; }
+
+ Ch* src_;
+ Ch* dst_;
+ Ch* head_;
+};
+
+typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// Type
+
+//! Type of JSON value
+enum Type {
+ kNullType = 0, //!< null
+ kFalseType = 1, //!< false
+ kTrueType = 2, //!< true
+ kObjectType = 3, //!< object
+ kArrayType = 4, //!< array
+ kStringType = 5, //!< string
+ kNumberType = 6, //!< number
+};
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/third-party/rapidjson/reader.h b/third-party/rapidjson/reader.h
new file mode 100644
index 000000000..78391add3
--- /dev/null
+++ b/third-party/rapidjson/reader.h
@@ -0,0 +1,683 @@
+#ifndef RAPIDJSON_READER_H_
+#define RAPIDJSON_READER_H_
+
+// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
+// Version 0.1
+
+#include "rapidjson.h"
+#include "internal/pow10.h"
+#include "internal/stack.h"
+#include <csetjmp>
+
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+#endif
+
+#ifndef RAPIDJSON_PARSE_ERROR
+#define RAPIDJSON_PARSE_ERROR(msg, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ parseError_ = msg; \
+ errorOffset_ = offset; \
+ longjmp(jmpbuf_, 1); \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+namespace rapidjson {
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseFlag
+
+//! Combination of parseFlags
+enum ParseFlag {
+ kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.
+ kParseInsituFlag = 1 //!< In-situ(destructive) parsing.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Handler
+
+/*! \class rapidjson::Handler
+ \brief Concept for receiving events from GenericReader upon parsing.
+\code
+concept Handler {
+ typename Ch;
+
+ void Null();
+ void Bool(bool b);
+ void Int(int i);
+ void Uint(unsigned i);
+ void Int64(int64_t i);
+ void Uint64(uint64_t i);
+ void Double(double d);
+ void String(const Ch* str, SizeType length, bool copy);
+ void StartObject();
+ void EndObject(SizeType memberCount);
+ void StartArray();
+ void EndArray(SizeType elementCount);
+};
+\endcode
+*/
+///////////////////////////////////////////////////////////////////////////////
+// BaseReaderHandler
+
+//! Default implementation of Handler.
+/*! This can be used as base class of any reader handler.
+ \implements Handler
+*/
+template<typename Encoding = UTF8<> >
+struct BaseReaderHandler {
+ typedef typename Encoding::Ch Ch;
+
+ void Default() {}
+ void Null() { Default(); }
+ void Bool(bool) { Default(); }
+ void Int(int) { Default(); }
+ void Uint(unsigned) { Default(); }
+ void Int64(int64_t) { Default(); }
+ void Uint64(uint64_t) { Default(); }
+ void Double(double) { Default(); }
+ void String(const Ch*, SizeType, bool) { Default(); }
+ void StartObject() { Default(); }
+ void EndObject(SizeType) { Default(); }
+ void StartArray() { Default(); }
+ void EndArray(SizeType) { Default(); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SkipWhitespace
+
+//! Skip the JSON white spaces in a stream.
+/*! \param stream A input stream for skipping white spaces.
+ \note This function has SSE2/SSE4.2 specialization.
+*/
+template<typename Stream>
+void SkipWhitespace(Stream& stream) {
+ Stream s = stream; // Use a local copy for optimization
+ while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+ s.Take();
+ stream = s;
+}
+
+#ifdef RAPIDJSON_SSE42
+//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ static const char whitespace[16] = " \n\r\t";
+ __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
+
+ for (;;) {
+ __m128i s = _mm_loadu_si128((const __m128i *)p);
+ unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
+ if (r == 0) // all 16 characters are whitespace
+ p += 16;
+ else { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ if (_BitScanForward(&offset, r))
+ return p + offset;
+#else
+ if (r != 0)
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+#elif defined(RAPIDJSON_SSE2)
+
+//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ static const char whitespaces[4][17] = {
+ " ",
+ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
+ "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
+
+ __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
+ __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
+ __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
+ __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
+
+ for (;;) {
+ __m128i s = _mm_loadu_si128((const __m128i *)p);
+ __m128i x = _mm_cmpeq_epi8(s, w0);
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+ unsigned short r = ~_mm_movemask_epi8(x);
+ if (r == 0) // all 16 characters are whitespace
+ p += 16;
+ else { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ if (_BitScanForward(&offset, r))
+ return p + offset;
+#else
+ if (r != 0)
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+#endif // RAPIDJSON_SSE2
+
+#ifdef RAPIDJSON_SIMD
+//! Template function specialization for InsituStringStream
+template<> inline void SkipWhitespace(InsituStringStream& stream) {
+ stream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_));
+}
+
+//! Template function specialization for StringStream
+template<> inline void SkipWhitespace(StringStream& stream) {
+ stream.src_ = SkipWhitespace_SIMD(stream.src_);
+}
+#endif // RAPIDJSON_SIMD
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericReader
+
+//! SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
+/*! GenericReader parses JSON text from a stream, and send events synchronously to an
+ object implementing Handler concept.
+
+ It needs to allocate a stack for storing a single decoded string during
+ non-destructive parsing.
+
+ For in-situ parsing, the decoded string is directly written to the source
+ text string, no temporary buffer is required.
+
+ A GenericReader object can be reused for parsing multiple JSON text.
+
+ \tparam Encoding Encoding of both the stream and the parse output.
+ \tparam Allocator Allocator type for stack.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericReader {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ //! Constructor.
+ /*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
+ \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
+ */
+ GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
+
+ //! Parse JSON text.
+ /*! \tparam parseFlags Combination of ParseFlag.
+ \tparam Stream Type of input stream.
+ \tparam Handler Type of handler which must implement Handler concept.
+ \param stream Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <unsigned parseFlags, typename Stream, typename Handler>
+ bool Parse(Stream& stream, Handler& handler) {
+ parseError_ = 0;
+ errorOffset_ = 0;
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
+#endif
+ if (setjmp(jmpbuf_)) {
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+ stack_.Clear();
+ return false;
+ }
+
+ SkipWhitespace(stream);
+
+ if (stream.Peek() == '\0')
+ RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", stream.Tell());
+ else {
+ switch (stream.Peek()) {
+ case '{': ParseObject<parseFlags>(stream, handler); break;
+ case '[': ParseArray<parseFlags>(stream, handler); break;
+ default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", stream.Tell());
+ }
+ SkipWhitespace(stream);
+
+ if (stream.Peek() != '\0')
+ RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", stream.Tell());
+ }
+
+ return true;
+ }
+
+ bool HasParseError() const { return parseError_ != 0; }
+ const char* GetParseError() const { return parseError_; }
+ size_t GetErrorOffset() const { return errorOffset_; }
+
+private:
+ // Parse object: { string : value, ... }
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseObject(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == '{');
+ stream.Take(); // Skip '{'
+ handler.StartObject();
+ SkipWhitespace(stream);
+
+ if (stream.Peek() == '}') {
+ stream.Take();
+ handler.EndObject(0); // empty object
+ return;
+ }
+
+ for (SizeType memberCount = 0;;) {
+ if (stream.Peek() != '"') {
+ RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", stream.Tell());
+ break;
+ }
+
+ ParseString<parseFlags>(stream, handler);
+ SkipWhitespace(stream);
+
+ if (stream.Take() != ':') {
+ RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", stream.Tell());
+ break;
+ }
+ SkipWhitespace(stream);
+
+ ParseValue<parseFlags>(stream, handler);
+ SkipWhitespace(stream);
+
+ ++memberCount;
+
+ switch(stream.Take()) {
+ case ',': SkipWhitespace(stream); break;
+ case '}': handler.EndObject(memberCount); return;
+ default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", stream.Tell());
+ }
+ }
+ }
+
+ // Parse array: [ value, ... ]
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseArray(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == '[');
+ stream.Take(); // Skip '['
+ handler.StartArray();
+ SkipWhitespace(stream);
+
+ if (stream.Peek() == ']') {
+ stream.Take();
+ handler.EndArray(0); // empty array
+ return;
+ }
+
+ for (SizeType elementCount = 0;;) {
+ ParseValue<parseFlags>(stream, handler);
+ ++elementCount;
+ SkipWhitespace(stream);
+
+ switch (stream.Take()) {
+ case ',': SkipWhitespace(stream); break;
+ case ']': handler.EndArray(elementCount); return;
+ default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", stream.Tell());
+ }
+ }
+ }
+
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseNull(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == 'n');
+ stream.Take();
+
+ if (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l')
+ handler.Null();
+ else
+ RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
+ }
+
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseTrue(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == 't');
+ stream.Take();
+
+ if (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e')
+ handler.Bool(true);
+ else
+ RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell());
+ }
+
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseFalse(Stream& stream, Handler& handler) {
+ RAPIDJSON_ASSERT(stream.Peek() == 'f');
+ stream.Take();
+
+ if (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e')
+ handler.Bool(false);
+ else
+ RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
+ }
+
+ // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+ template<typename Stream>
+ unsigned ParseHex4(Stream& stream) {
+ Stream s = stream; // Use a local copy for optimization
+ unsigned codepoint = 0;
+ for (int i = 0; i < 4; i++) {
+ Ch c = s.Take();
+ codepoint <<= 4;
+ codepoint += c;
+ if (c >= '0' && c <= '9')
+ codepoint -= '0';
+ else if (c >= 'A' && c <= 'F')
+ codepoint -= 'A' - 10;
+ else if (c >= 'a' && c <= 'f')
+ codepoint -= 'a' - 10;
+ else
+ RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1);
+ }
+ stream = s; // Restore stream
+ return codepoint;
+ }
+
+ // Parse string, handling the prefix and suffix double quotes and escaping.
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseString(Stream& stream, Handler& handler) {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ static const Ch escape[256] = {
+ Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
+ Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
+ 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
+ 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
+ };
+#undef Z16
+
+ Stream s = stream; // Use a local copy for optimization
+ RAPIDJSON_ASSERT(s.Peek() == '\"');
+ s.Take(); // Skip '\"'
+ Ch *head;
+ SizeType len;
+ if (parseFlags & kParseInsituFlag)
+ head = s.PutBegin();
+ else
+ len = 0;
+
+#define RAPIDJSON_PUT(x) \
+ do { \
+ if (parseFlags & kParseInsituFlag) \
+ s.Put(x); \
+ else { \
+ *stack_.template Push<Ch>() = x; \
+ ++len; \
+ } \
+ } while(false)
+
+ for (;;) {
+ Ch c = s.Take();
+ if (c == '\\') { // Escape
+ Ch e = s.Take();
+ if ((sizeof(Ch) == 1 || (int)e < 256) && escape[(unsigned char)e])
+ RAPIDJSON_PUT(escape[(unsigned char)e]);
+ else if (e == 'u') { // Unicode
+ unsigned codepoint = ParseHex4(s);
+ if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair
+ if (s.Take() != '\\' || s.Take() != 'u') {
+ RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", s.Tell() - 2);
+ return;
+ }
+ unsigned codepoint2 = ParseHex4(s);
+ if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) {
+ RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", s.Tell() - 2);
+ return;
+ }
+ codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
+ }
+
+ Ch buffer[4];
+ SizeType count = SizeType(Encoding::Encode(buffer, codepoint) - &buffer[0]);
+
+ if (parseFlags & kParseInsituFlag)
+ for (SizeType i = 0; i < count; i++)
+ s.Put(buffer[i]);
+ else {
+ memcpy(stack_.template Push<Ch>(count), buffer, count * sizeof(Ch));
+ len += count;
+ }
+ }
+ else {
+ RAPIDJSON_PARSE_ERROR("Unknown escape character", stream.Tell() - 1);
+ return;
+ }
+ }
+ else if (c == '"') { // Closing double quote
+ if (parseFlags & kParseInsituFlag) {
+ size_t length = s.PutEnd(head);
+ RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+ RAPIDJSON_PUT('\0'); // null-terminate the string
+ handler.String(head, SizeType(length), false);
+ }
+ else {
+ RAPIDJSON_PUT('\0');
+ handler.String(stack_.template Pop<Ch>(len), len - 1, true);
+ }
+ stream = s; // restore stream
+ return;
+ }
+ else if (c == '\0') {
+ RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", stream.Tell() - 1);
+ return;
+ }
+ else if ((unsigned)c < 0x20) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+ RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", stream.Tell() - 1);
+ return;
+ }
+ else
+ RAPIDJSON_PUT(c); // Normal character, just copy
+ }
+#undef RAPIDJSON_PUT
+ }
+
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseNumber(Stream& stream, Handler& handler) {
+ Stream s = stream; // Local copy for optimization
+ // Parse minus
+ bool minus = false;
+ if (s.Peek() == '-') {
+ minus = true;
+ s.Take();
+ }
+
+ // Parse int: zero / ( digit1-9 *DIGIT )
+ unsigned i;
+ bool try64bit = false;
+ if (s.Peek() == '0') {
+ i = 0;
+ s.Take();
+ }
+ else if (s.Peek() >= '1' && s.Peek() <= '9') {
+ i = s.Take() - '0';
+
+ if (minus)
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i >= 214748364) { // 2^31 = 2147483648
+ if (i != 214748364 || s.Peek() > '8') {
+ try64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + (s.Take() - '0');
+ }
+ else
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i >= 429496729) { // 2^32 - 1 = 4294967295
+ if (i != 429496729 || s.Peek() > '5') {
+ try64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + (s.Take() - '0');
+ }
+ }
+ else {
+ RAPIDJSON_PARSE_ERROR("Expect a value here.", stream.Tell());
+ return;
+ }
+
+ // Parse 64bit int
+ uint64_t i64 = 0;
+ bool useDouble = false;
+ if (try64bit) {
+ i64 = i;
+ if (minus)
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808
+ if (i64 != 922337203685477580uLL || s.Peek() > '8') {
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + (s.Take() - '0');
+ }
+ else
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615
+ if (i64 != 1844674407370955161uLL || s.Peek() > '5') {
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + (s.Take() - '0');
+ }
+ }
+
+ // Force double for big integer
+ double d = 0.0;
+ if (useDouble) {
+ d = (double)i64;
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (d >= 1E307) {
+ RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
+ return;
+ }
+ d = d * 10 + (s.Take() - '0');
+ }
+ }
+
+ // Parse frac = decimal-point 1*DIGIT
+ int expFrac = 0;
+ if (s.Peek() == '.') {
+ if (!useDouble) {
+ d = try64bit ? (double)i64 : (double)i;
+ useDouble = true;
+ }
+ s.Take();
+
+ if (s.Peek() >= '0' && s.Peek() <= '9') {
+ d = d * 10 + (s.Take() - '0');
+ --expFrac;
+ }
+ else {
+ RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", stream.Tell());
+ return;
+ }
+
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ if (expFrac > -16) {
+ d = d * 10 + (s.Peek() - '0');
+ --expFrac;
+ }
+ s.Take();
+ }
+ }
+
+ // Parse exp = e [ minus / plus ] 1*DIGIT
+ int exp = 0;
+ if (s.Peek() == 'e' || s.Peek() == 'E') {
+ if (!useDouble) {
+ d = try64bit ? (double)i64 : (double)i;
+ useDouble = true;
+ }
+ s.Take();
+
+ bool expMinus = false;
+ if (s.Peek() == '+')
+ s.Take();
+ else if (s.Peek() == '-') {
+ s.Take();
+ expMinus = true;
+ }
+
+ if (s.Peek() >= '0' && s.Peek() <= '9') {
+ exp = s.Take() - '0';
+ while (s.Peek() >= '0' && s.Peek() <= '9') {
+ exp = exp * 10 + (s.Take() - '0');
+ if (exp > 308) {
+ RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
+ return;
+ }
+ }
+ }
+ else {
+ RAPIDJSON_PARSE_ERROR("At least one digit in exponent", s.Tell());
+ return;
+ }
+
+ if (expMinus)
+ exp = -exp;
+ }
+
+ // Finish parsing, call event according to the type of number.
+ if (useDouble) {
+ d *= internal::Pow10(exp + expFrac);
+ handler.Double(minus ? -d : d);
+ }
+ else {
+ if (try64bit) {
+ if (minus)
+ handler.Int64(-(int64_t)i64);
+ else
+ handler.Uint64(i64);
+ }
+ else {
+ if (minus)
+ handler.Int(-(int)i);
+ else
+ handler.Uint(i);
+ }
+ }
+
+ stream = s; // restore stream
+ }
+
+ // Parse any JSON value
+ template<unsigned parseFlags, typename Stream, typename Handler>
+ void ParseValue(Stream& stream, Handler& handler) {
+ switch (stream.Peek()) {
+ case 'n': ParseNull <parseFlags>(stream, handler); break;
+ case 't': ParseTrue <parseFlags>(stream, handler); break;
+ case 'f': ParseFalse <parseFlags>(stream, handler); break;
+ case '"': ParseString<parseFlags>(stream, handler); break;
+ case '{': ParseObject<parseFlags>(stream, handler); break;
+ case '[': ParseArray <parseFlags>(stream, handler); break;
+ default : ParseNumber<parseFlags>(stream, handler);
+ }
+ }
+
+ static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
+ internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
+ jmp_buf jmpbuf_; //!< setjmp buffer for fast exit from nested parsing function calls.
+ const char* parseError_;
+ size_t errorOffset_;
+}; // class GenericReader
+
+//! Reader with UTF8 encoding and default allocator.
+typedef GenericReader<UTF8<> > Reader;
+
+} // namespace rapidjson
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // RAPIDJSON_READER_H_
diff --git a/third-party/rapidjson/stringbuffer.h b/third-party/rapidjson/stringbuffer.h
new file mode 100644
index 000000000..269ae1076
--- /dev/null
+++ b/third-party/rapidjson/stringbuffer.h
@@ -0,0 +1,49 @@
+#ifndef RAPIDJSON_STRINGBUFFER_H_
+#define RAPIDJSON_STRINGBUFFER_H_
+
+#include "rapidjson.h"
+#include "internal/stack.h"
+
+namespace rapidjson {
+
+//! Represents an in-memory output stream.
+/*!
+ \tparam Encoding Encoding of the stream.
+ \tparam Allocator type for allocating memory buffer.
+ \implements Stream
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+struct GenericStringBuffer {
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+
+ void Clear() { stack_.Clear(); }
+
+ const char* GetString() const {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.template Pop<Ch>(1);
+
+ return stack_.template Bottom<Ch>();
+ }
+
+ size_t Size() const { return stack_.GetSize(); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericStringBuffer<UTF8<> > StringBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
+ memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+} // namespace rapidjson
+
+#endif // RAPIDJSON_STRINGBUFFER_H_
diff --git a/third-party/rapidjson/writer.h b/third-party/rapidjson/writer.h
new file mode 100644
index 000000000..d96f2081a
--- /dev/null
+++ b/third-party/rapidjson/writer.h
@@ -0,0 +1,241 @@
+#ifndef RAPIDJSON_WRITER_H_
+#define RAPIDJSON_WRITER_H_
+
+#include "rapidjson.h"
+#include "internal/stack.h"
+#include "internal/strfunc.h"
+#include <cstdio> // snprintf() or _sprintf_s()
+#include <new> // placement new
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127) // conditional expression is constant
+#endif
+
+namespace rapidjson {
+
+//! JSON writer
+/*! Writer implements the concept Handler.
+ It generates JSON text by events to an output stream.
+
+ User may programmatically calls the functions of a writer to generate JSON text.
+
+ On the other side, a writer can also be passed to objects that generates events,
+
+ for example Reader::Parse() and Document::Accept().
+
+ \tparam Stream Type of ouptut stream.
+ \tparam Encoding Encoding of both source strings and output.
+ \implements Handler
+*/
+template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
+class Writer {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ Writer(Stream& stream, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+ stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level)) {}
+
+ //@name Implementation of Handler
+ //@{
+ Writer& Null() { Prefix(kNullType); WriteNull(); return *this; }
+ Writer& Bool(bool b) { Prefix(b ? kTrueType : kFalseType); WriteBool(b); return *this; }
+ Writer& Int(int i) { Prefix(kNumberType); WriteInt(i); return *this; }
+ Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; }
+ Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; }
+ Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; }
+ Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; }
+
+ Writer& String(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ Prefix(kStringType);
+ WriteString(str, length);
+ return *this;
+ }
+
+ Writer& StartObject() {
+ Prefix(kObjectType);
+ new (level_stack_.template Push<Level>()) Level(false);
+ WriteStartObject();
+ return *this;
+ }
+
+ Writer& EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ WriteEndObject();
+ return *this;
+ }
+
+ Writer& StartArray() {
+ Prefix(kArrayType);
+ new (level_stack_.template Push<Level>()) Level(true);
+ WriteStartArray();
+ return *this;
+ }
+
+ Writer& EndArray(SizeType elementCount = 0) {
+ (void)elementCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ WriteEndArray();
+ return *this;
+ }
+ //@}
+
+ //! Simpler but slower overload.
+ Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); }
+
+protected:
+ //! Information for each nested level
+ struct Level {
+ Level(bool inArray_) : inArray(inArray_), valueCount(0) {}
+ bool inArray; //!< true if in array, otherwise in object
+ size_t valueCount; //!< number of values in this level
+ };
+
+ static const size_t kDefaultLevelDepth = 32;
+
+ void WriteNull() {
+ stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l');
+ }
+
+ void WriteBool(bool b) {
+ if (b) {
+ stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e');
+ }
+ else {
+ stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e');
+ }
+ }
+
+ void WriteInt(int i) {
+ if (i < 0) {
+ stream_.Put('-');
+ i = -i;
+ }
+ WriteUint((unsigned)i);
+ }
+
+ void WriteUint(unsigned u) {
+ char buffer[10];
+ char *p = buffer;
+ do {
+ *p++ = (u % 10) + '0';
+ u /= 10;
+ } while (u > 0);
+
+ do {
+ --p;
+ stream_.Put(*p);
+ } while (p != buffer);
+ }
+
+ void WriteInt64(int64_t i64) {
+ if (i64 < 0) {
+ stream_.Put('-');
+ i64 = -i64;
+ }
+ WriteUint64((uint64_t)i64);
+ }
+
+ void WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char *p = buffer;
+ do {
+ *p++ = char(u64 % 10) + '0';
+ u64 /= 10;
+ } while (u64 > 0);
+
+ do {
+ --p;
+ stream_.Put(*p);
+ } while (p != buffer);
+ }
+
+ //! \todo Optimization with custom double-to-string converter.
+ void WriteDouble(double d) {
+ char buffer[100];
+#if _MSC_VER
+ int ret = sprintf_s(buffer, sizeof(buffer), "%g", d);
+#else
+ int ret = snprintf(buffer, sizeof(buffer), "%g", d);
+#endif
+ RAPIDJSON_ASSERT(ret >= 1);
+ for (int i = 0; i < ret; i++)
+ stream_.Put(buffer[i]);
+ }
+
+ void WriteString(const Ch* str, SizeType length) {
+ static const char hexDigits[] = "0123456789ABCDEF";
+ static const char escape[256] = {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ //0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
+ 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
+ Z16, Z16, // 30~4F
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
+#undef Z16
+ };
+
+ stream_.Put('\"');
+ for (const Ch* p = str; p != str + length; ++p) {
+ if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p]) {
+ stream_.Put('\\');
+ stream_.Put(escape[(unsigned char)*p]);
+ if (escape[(unsigned char)*p] == 'u') {
+ stream_.Put('0');
+ stream_.Put('0');
+ stream_.Put(hexDigits[(*p) >> 4]);
+ stream_.Put(hexDigits[(*p) & 0xF]);
+ }
+ }
+ else
+ stream_.Put(*p);
+ }
+ stream_.Put('\"');
+ }
+
+ void WriteStartObject() { stream_.Put('{'); }
+ void WriteEndObject() { stream_.Put('}'); }
+ void WriteStartArray() { stream_.Put('['); }
+ void WriteEndArray() { stream_.Put(']'); }
+
+ void Prefix(Type type) {
+ (void)type;
+ if (level_stack_.GetSize() != 0) { // this value is not at root
+ Level* level = level_stack_.template Top<Level>();
+ if (level->valueCount > 0) {
+ if (level->inArray)
+ stream_.Put(','); // add comma if it is not the first element in array
+ else // in object
+ stream_.Put((level->valueCount % 2 == 0) ? ',' : ':');
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else
+ RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
+ }
+
+ Stream& stream_;
+ internal::Stack<Allocator> level_stack_;
+
+private:
+ // Prohibit assignment for VC C4512 warning
+ Writer& operator=(const Writer& w);
+};
+
+} // namespace rapidjson
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_