update rapidjson

This commit is contained in:
Riccardo Spagni 2016-09-17 09:35:49 +02:00
parent 2846d0850d
commit f62ebc5c81
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
31 changed files with 11484 additions and 6950 deletions

View file

@ -1,261 +1,271 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ALLOCATORS_H_ #ifndef RAPIDJSON_ALLOCATORS_H_
#define RAPIDJSON_ALLOCATORS_H_ #define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h" #include "rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Allocator // Allocator
/*! \class rapidjson::Allocator /*! \class rapidjson::Allocator
\brief Concept for allocating, resizing and freeing memory block. \brief Concept for allocating, resizing and freeing memory block.
Note that Malloc() and Realloc() are non-static but Free() is static. 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 So if an allocator need to support Free(), it needs to put its pointer in
the header of memory block. the header of memory block.
\code \code
concept Allocator { concept Allocator {
static const bool kNeedFree; //!< Whether this allocator needs to call Free(). static const bool kNeedFree; //!< Whether this allocator needs to call Free().
// Allocate a memory block. // Allocate a memory block.
// \param size of the memory block in bytes. // \param size of the memory block in bytes.
// \returns pointer to the memory block. // \returns pointer to the memory block.
void* Malloc(size_t size); void* Malloc(size_t size);
// Resize a memory block. // Resize a memory block.
// \param originalPtr The pointer to current memory block. Null pointer is permitted. // \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 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. // \param newSize the new size in bytes.
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
// Free a memory block. // Free a memory block.
// \param pointer to the memory block. Null pointer is permitted. // \param pointer to the memory block. Null pointer is permitted.
static void Free(void *ptr); static void Free(void *ptr);
}; };
\endcode \endcode
*/ */
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// CrtAllocator // CrtAllocator
//! C-runtime library allocator. //! C-runtime library allocator.
/*! This class is just wrapper for standard C library memory routines. /*! This class is just wrapper for standard C library memory routines.
\note implements Allocator concept \note implements Allocator concept
*/ */
class CrtAllocator { class CrtAllocator {
public: public:
static const bool kNeedFree = true; static const bool kNeedFree = true;
void* Malloc(size_t size) { void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined. if (size) // behavior of malloc(0) is implementation defined.
return std::malloc(size); return std::malloc(size);
else else
return NULL; // standardize to returning NULL. return NULL; // standardize to returning NULL.
} }
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
(void)originalSize; (void)originalSize;
if (newSize == 0) { if (newSize == 0) {
std::free(originalPtr); std::free(originalPtr);
return NULL; return NULL;
} }
return std::realloc(originalPtr, newSize); return std::realloc(originalPtr, newSize);
} }
static void Free(void *ptr) { std::free(ptr); } static void Free(void *ptr) { std::free(ptr); }
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// MemoryPoolAllocator // MemoryPoolAllocator
//! Default memory allocator used by the parser and DOM. //! Default memory allocator used by the parser and DOM.
/*! This allocator allocate memory blocks from pre-allocated memory chunks. /*! This allocator allocate memory blocks from pre-allocated memory chunks.
It does not free memory blocks. And Realloc() only allocate new memory. It does not free memory blocks. And Realloc() only allocate new memory.
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
User may also supply a buffer as the first chunk. User may also supply a buffer as the first chunk.
If the user-buffer is full then additional chunks are allocated by BaseAllocator. If the user-buffer is full then additional chunks are allocated by BaseAllocator.
The user-buffer is not deallocated by this allocator. The user-buffer is not deallocated by this allocator.
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
\note implements Allocator concept \note implements Allocator concept
*/ */
template <typename BaseAllocator = CrtAllocator> template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator { class MemoryPoolAllocator {
public: public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
//! Constructor with chunkSize. //! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks. \param baseAllocator The allocator for allocating memory chunks.
*/ */
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{ {
} }
//! Constructor with user-supplied buffer. //! 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 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. The user buffer will not be deallocated when this allocator is destructed.
\param buffer User supplied buffer. \param buffer User supplied buffer.
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). \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 chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks. \param baseAllocator The allocator for allocating memory chunks.
*/ */
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{ {
RAPIDJSON_ASSERT(buffer != 0); RAPIDJSON_ASSERT(buffer != 0);
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer); chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
chunkHead_->capacity = size - sizeof(ChunkHeader); chunkHead_->capacity = size - sizeof(ChunkHeader);
chunkHead_->size = 0; chunkHead_->size = 0;
chunkHead_->next = 0; chunkHead_->next = 0;
} }
//! Destructor. //! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer. /*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/ */
~MemoryPoolAllocator() { ~MemoryPoolAllocator() {
Clear(); Clear();
RAPIDJSON_DELETE(ownBaseAllocator_); RAPIDJSON_DELETE(ownBaseAllocator_);
} }
//! Deallocates all memory chunks, excluding the user-supplied buffer. //! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() { void Clear() {
while (chunkHead_ && chunkHead_ != userBuffer_) { while (chunkHead_ && chunkHead_ != userBuffer_) {
ChunkHeader* next = chunkHead_->next; ChunkHeader* next = chunkHead_->next;
baseAllocator_->Free(chunkHead_); baseAllocator_->Free(chunkHead_);
chunkHead_ = next; chunkHead_ = next;
} }
if (chunkHead_ && chunkHead_ == userBuffer_) if (chunkHead_ && chunkHead_ == userBuffer_)
chunkHead_->size = 0; // Clear user buffer chunkHead_->size = 0; // Clear user buffer
} }
//! Computes the total capacity of allocated memory chunks. //! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes. /*! \return total capacity in bytes.
*/ */
size_t Capacity() const { size_t Capacity() const {
size_t capacity = 0; size_t capacity = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
capacity += c->capacity; capacity += c->capacity;
return capacity; return capacity;
} }
//! Computes the memory blocks allocated. //! Computes the memory blocks allocated.
/*! \return total used bytes. /*! \return total used bytes.
*/ */
size_t Size() const { size_t Size() const {
size_t size = 0; size_t size = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
size += c->size; size += c->size;
return size; return size;
} }
//! Allocates a memory block. (concept Allocator) //! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) { void* Malloc(size_t size) {
if (!size) if (!size)
return NULL; return NULL;
size = RAPIDJSON_ALIGN(size); size = RAPIDJSON_ALIGN(size);
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
return NULL;
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
chunkHead_->size += size; void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
return buffer; chunkHead_->size += size;
} return buffer;
}
//! Resizes a memory block (concept Allocator)
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { //! Resizes a memory block (concept Allocator)
if (originalPtr == 0) void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
return Malloc(newSize); if (originalPtr == 0)
return Malloc(newSize);
if (newSize == 0)
return NULL; if (newSize == 0)
return NULL;
// Do not shrink if new size is smaller than original
if (originalSize >= newSize) originalSize = RAPIDJSON_ALIGN(originalSize);
return originalPtr; newSize = RAPIDJSON_ALIGN(newSize);
// Simply expand it if it is the last allocation and there is sufficient space // Do not shrink if new size is smaller than original
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { if (originalSize >= newSize)
size_t increment = static_cast<size_t>(newSize - originalSize); return originalPtr;
increment = RAPIDJSON_ALIGN(increment);
if (chunkHead_->size + increment <= chunkHead_->capacity) { // Simply expand it if it is the last allocation and there is sufficient space
chunkHead_->size += increment; if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
return originalPtr; size_t increment = static_cast<size_t>(newSize - originalSize);
} if (chunkHead_->size + increment <= chunkHead_->capacity) {
} chunkHead_->size += increment;
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.
if (originalSize) // Realloc process: allocate and copy memory, do not free original buffer.
std::memcpy(newBuffer, originalPtr, originalSize); if (void* newBuffer = Malloc(newSize)) {
return newBuffer; if (originalSize)
} std::memcpy(newBuffer, originalPtr, originalSize);
return newBuffer;
//! Frees a memory block (concept Allocator) }
static void Free(void *ptr) { (void)ptr; } // Do nothing else
return NULL;
private: }
//! Copy constructor is not permitted.
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; //! Frees a memory block (concept Allocator)
//! Copy assignment operator is not permitted. static void Free(void *ptr) { (void)ptr; } // Do nothing
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
private:
//! Creates a new chunk. //! Copy constructor is not permitted.
/*! \param capacity Capacity of the chunk in bytes. MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
*/ //! Copy assignment operator is not permitted.
void AddChunk(size_t capacity) { MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
if (!baseAllocator_)
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); //! Creates a new chunk.
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity)); /*! \param capacity Capacity of the chunk in bytes.
chunk->capacity = capacity; \return true if success.
chunk->size = 0; */
chunk->next = chunkHead_; bool AddChunk(size_t capacity) {
chunkHead_ = chunk; if (!baseAllocator_)
} ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. chunk->capacity = capacity;
chunk->size = 0;
//! Chunk header for perpending to each chunk. chunk->next = chunkHead_;
/*! Chunks are stored as a singly linked list. chunkHead_ = chunk;
*/ return true;
struct ChunkHeader { }
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). else
size_t size; //!< Current size of allocated memory in bytes. return false;
ChunkHeader *next; //!< Next chunk in the linked list. }
};
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
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. //! Chunk header for perpending to each chunk.
void *userBuffer_; //!< User supplied buffer. /*! Chunks are stored as a singly linked list.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. */
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. 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.
RAPIDJSON_NAMESPACE_END ChunkHeader *next; //!< Next chunk in the linked list.
};
#endif // RAPIDJSON_ENCODINGS_H_
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.
void *userBuffer_; //!< User supplied buffer.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_

File diff suppressed because it is too large Load diff

View file

@ -1,270 +1,299 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODEDSTREAM_H_ #ifndef RAPIDJSON_ENCODEDSTREAM_H_
#define RAPIDJSON_ENCODEDSTREAM_H_ #define RAPIDJSON_ENCODEDSTREAM_H_
#include "rapidjson.h" #include "stream.h"
#include "memorystream.h"
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH #ifdef __GNUC__
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_PUSH
#endif RAPIDJSON_DIAG_OFF(effc++)
#endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH #ifdef __clang__
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_PUSH
#endif RAPIDJSON_DIAG_OFF(padded)
#endif
RAPIDJSON_NAMESPACE_BEGIN
RAPIDJSON_NAMESPACE_BEGIN
//! Input byte stream wrapper with a statically bound encoding.
/*! //! Input byte stream wrapper with a statically bound encoding.
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. /*!
\tparam InputByteStream Type of input byte stream. For example, FileReadStream. \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
*/ \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
template <typename Encoding, typename InputByteStream> */
class EncodedInputStream { template <typename Encoding, typename InputByteStream>
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); class EncodedInputStream {
public: RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
typedef typename Encoding::Ch Ch; public:
typedef typename Encoding::Ch Ch;
EncodedInputStream(InputByteStream& is) : is_(is) {
current_ = Encoding::TakeBOM(is_); EncodedInputStream(InputByteStream& is) : is_(is) {
} current_ = Encoding::TakeBOM(is_);
}
Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } Ch Peek() const { return current_; }
size_t Tell() const { return is_.Tell(); } Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
size_t Tell() const { return is_.Tell(); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } // Not implemented
void Flush() { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
EncodedInputStream(const EncodedInputStream&); private:
EncodedInputStream& operator=(const EncodedInputStream&); EncodedInputStream(const EncodedInputStream&);
EncodedInputStream& operator=(const EncodedInputStream&);
InputByteStream& is_;
Ch current_; InputByteStream& is_;
}; Ch current_;
};
//! Output byte stream wrapper with statically bound encoding.
/*! //! Specialized for UTF8 MemoryStream.
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. template <>
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. class EncodedInputStream<UTF8<>, MemoryStream> {
*/ public:
template <typename Encoding, typename OutputByteStream> typedef UTF8<>::Ch Ch;
class EncodedOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); EncodedInputStream(MemoryStream& is) : is_(is) {
public: if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
typedef typename Encoding::Ch Ch; if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { }
if (putBOM) Ch Peek() const { return is_.Peek(); }
Encoding::PutBOM(os_); Ch Take() { return is_.Take(); }
} size_t Tell() const { return is_.Tell(); }
void Put(Ch c) { Encoding::Put(os_, c); } // Not implemented
void Flush() { os_.Flush(); } void Put(Ch) {}
void Flush() {}
// Not implemented Ch* PutBegin() { return 0; }
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} size_t PutEnd(Ch*) { return 0; }
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } MemoryStream& is_;
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private:
EncodedInputStream(const EncodedInputStream&);
private: EncodedInputStream& operator=(const EncodedInputStream&);
EncodedOutputStream(const EncodedOutputStream&); };
EncodedOutputStream& operator=(const EncodedOutputStream&);
//! Output byte stream wrapper with statically bound encoding.
OutputByteStream& os_; /*!
}; \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x */
template <typename Encoding, typename OutputByteStream>
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. class EncodedOutputStream {
/*! RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
\tparam CharType Type of character for reading. public:
\tparam InputByteStream type of input byte stream to be wrapped. typedef typename Encoding::Ch Ch;
*/
template <typename CharType, typename InputByteStream> EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
class AutoUTFInputStream { if (putBOM)
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); Encoding::PutBOM(os_);
public: }
typedef CharType Ch;
void Put(Ch c) { Encoding::Put(os_, c); }
//! Constructor. void Flush() { os_.Flush(); }
/*!
\param is input stream to be wrapped. // Not implemented
\param type UTF encoding type if it is not detected from the stream. Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
*/ Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
DetectType(); size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_]; private:
current_ = takeFunc_(*is_); EncodedOutputStream(const EncodedOutputStream&);
} EncodedOutputStream& operator=(const EncodedOutputStream&);
UTFType GetType() const { return type_; } OutputByteStream& os_;
bool HasBOM() const { return hasBOM_; } };
Ch Peek() const { return current_; } #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
size_t Tell() const { return is_->Tell(); } //! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
// Not implemented \tparam CharType Type of character for reading.
void Put(Ch) { RAPIDJSON_ASSERT(false); } \tparam InputByteStream type of input byte stream to be wrapped.
void Flush() { RAPIDJSON_ASSERT(false); } */
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } template <typename CharType, typename InputByteStream>
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } class AutoUTFInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
private: public:
AutoUTFInputStream(const AutoUTFInputStream&); typedef CharType Ch;
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
//! Constructor.
// Detect encoding type with BOM or RFC 4627 /*!
void DetectType() { \param is input stream to be wrapped.
// BOM (Byte Order Mark): \param type UTF encoding type if it is not detected from the stream.
// 00 00 FE FF UTF-32BE */
// FF FE 00 00 UTF-32LE AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
// FE FF UTF-16BE RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
// FF FE UTF-16LE DetectType();
// EF BB BF UTF-8 static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_];
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4()); current_ = takeFunc_(*is_);
if (!c) }
return;
UTFType GetType() const { return type_; }
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); bool HasBOM() const { return hasBOM_; }
hasBOM_ = false;
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } Ch Peek() const { return current_; }
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } size_t Tell() const { return is_->Tell(); }
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
// RFC 4627: Section 3 void Flush() { RAPIDJSON_ASSERT(false); }
// "Since the first two characters of a JSON text will always be ASCII Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
// characters [RFC0020], it is possible to determine whether an octet size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
// at the pattern of nulls in the first four octets." private:
// 00 00 00 xx UTF-32BE AutoUTFInputStream(const AutoUTFInputStream&);
// 00 xx 00 xx UTF-16BE AutoUTFInputStream& operator=(const AutoUTFInputStream&);
// xx 00 00 00 UTF-32LE
// xx 00 xx 00 UTF-16LE // Detect encoding type with BOM or RFC 4627
// xx xx xx xx UTF-8 void DetectType() {
// BOM (Byte Order Mark):
if (!hasBOM_) { // 00 00 FE FF UTF-32BE
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); // FF FE 00 00 UTF-32LE
switch (pattern) { // FE FF UTF-16BE
case 0x08: type_ = kUTF32BE; break; // FF FE UTF-16LE
case 0x0A: type_ = kUTF16BE; break; // EF BB BF UTF-8
case 0x01: type_ = kUTF32LE; break;
case 0x05: type_ = kUTF16LE; break; const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
case 0x0F: type_ = kUTF8; break; if (!c)
default: break; // Use type defined by user. return;
}
} unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
hasBOM_ = false;
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
} else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
typedef Ch (*TakeFunc)(InputByteStream& is);
InputByteStream* is_; // RFC 4627: Section 3
UTFType type_; // "Since the first two characters of a JSON text will always be ASCII
Ch current_; // characters [RFC0020], it is possible to determine whether an octet
TakeFunc takeFunc_; // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
bool hasBOM_; // at the pattern of nulls in the first four octets."
}; // 00 00 00 xx UTF-32BE
// 00 xx 00 xx UTF-16BE
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. // xx 00 00 00 UTF-32LE
/*! // xx 00 xx 00 UTF-16LE
\tparam CharType Type of character for writing. // xx xx xx xx UTF-8
\tparam OutputByteStream type of output byte stream to be wrapped.
*/ if (!hasBOM_) {
template <typename CharType, typename OutputByteStream> unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
class AutoUTFOutputStream { switch (pattern) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); case 0x08: type_ = kUTF32BE; break;
public: case 0x0A: type_ = kUTF16BE; break;
typedef CharType Ch; case 0x01: type_ = kUTF32LE; break;
case 0x05: type_ = kUTF16LE; break;
//! Constructor. case 0x0F: type_ = kUTF8; break;
/*! default: break; // Use type defined by user.
\param os output stream to be wrapped. }
\param type UTF encoding type. }
\param putBOM Whether to write BOM at the beginning of the stream.
*/ // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
}
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); typedef Ch (*TakeFunc)(InputByteStream& is);
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); InputByteStream* is_;
UTFType type_;
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; Ch current_;
putFunc_ = f[type_]; TakeFunc takeFunc_;
bool hasBOM_;
if (putBOM) };
PutBOM();
} //! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
UTFType GetType() const { return type_; } \tparam CharType Type of character for writing.
\tparam OutputByteStream type of output byte stream to be wrapped.
void Put(Ch c) { putFunc_(*os_, c); } */
void Flush() { os_->Flush(); } template <typename CharType, typename OutputByteStream>
class AutoUTFOutputStream {
// Not implemented RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} public:
Ch Take() { RAPIDJSON_ASSERT(false); return 0;} typedef CharType Ch;
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } //! Constructor.
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } /*!
\param os output stream to be wrapped.
private: \param type UTF encoding type.
AutoUTFOutputStream(const AutoUTFOutputStream&); \param putBOM Whether to write BOM at the beginning of the stream.
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); */
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
void PutBOM() { RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
typedef void (*PutBOMFunc)(OutputByteStream&);
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
f[type_](*os_); if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
} if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
typedef void (*PutFunc)(OutputByteStream&, Ch); static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_];
OutputByteStream* os_;
UTFType type_; if (putBOM)
PutFunc putFunc_; PutBOM();
}; }
#undef RAPIDJSON_ENCODINGS_FUNC UTFType GetType() const { return type_; }
RAPIDJSON_NAMESPACE_END void Put(Ch c) { putFunc_(*os_, c); }
void Flush() { os_->Flush(); }
#ifdef __clang__
RAPIDJSON_DIAG_POP // Not implemented
#endif Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
#ifdef __GNUC__ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
RAPIDJSON_DIAG_POP Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
#endif size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
#endif // RAPIDJSON_FILESTREAM_H_ private:
AutoUTFOutputStream(const AutoUTFOutputStream&);
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
void PutBOM() {
typedef void (*PutBOMFunc)(OutputByteStream&);
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
f[type_](*os_);
}
typedef void (*PutFunc)(OutputByteStream&, Ch);
OutputByteStream* os_;
UTFType type_;
PutFunc putFunc_;
};
#undef RAPIDJSON_ENCODINGS_FUNC
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_

File diff suppressed because it is too large Load diff

View file

@ -38,7 +38,7 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");

View file

@ -1,99 +1,99 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEREADSTREAM_H_ #ifndef RAPIDJSON_FILEREADSTREAM_H_
#define RAPIDJSON_FILEREADSTREAM_H_ #define RAPIDJSON_FILEREADSTREAM_H_
#include "rapidjson.h" #include "stream.h"
#include <cstdio> #include <cstdio>
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable-code)
RAPIDJSON_DIAG_OFF(missing-noreturn) RAPIDJSON_DIAG_OFF(missing-noreturn)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
//! File byte stream for input using fread(). //! File byte stream for input using fread().
/*! /*!
\note implements Stream concept \note implements Stream concept
*/ */
class FileReadStream { class FileReadStream {
public: public:
typedef char Ch; //!< Character type (byte). typedef char Ch; //!< Character type (byte).
//! Constructor. //! Constructor.
/*! /*!
\param fp File pointer opened for read. \param fp File pointer opened for read.
\param buffer user-supplied buffer. \param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes. \param bufferSize size of buffer in bytes. Must >=4 bytes.
*/ */
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(fp_ != 0);
RAPIDJSON_ASSERT(bufferSize >= 4); RAPIDJSON_ASSERT(bufferSize >= 4);
Read(); Read();
} }
Ch Peek() const { return *current_; } Ch Peek() const { return *current_; }
Ch Take() { Ch c = *current_; Read(); return c; } Ch Take() { Ch c = *current_; Read(); return c; }
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); } size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only. // For encoding detection only.
const Ch* Peek4() const { const Ch* Peek4() const {
return (current_ + 4 <= bufferLast_) ? current_ : 0; return (current_ + 4 <= bufferLast_) ? current_ : 0;
} }
private: private:
void Read() { void Read() {
if (current_ < bufferLast_) if (current_ < bufferLast_)
++current_; ++current_;
else if (!eof_) { else if (!eof_) {
count_ += readCount_; count_ += readCount_;
readCount_ = fread(buffer_, 1, bufferSize_, fp_); readCount_ = fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1; bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_; current_ = buffer_;
if (readCount_ < bufferSize_) { if (readCount_ < bufferSize_) {
buffer_[readCount_] = '\0'; buffer_[readCount_] = '\0';
++bufferLast_; ++bufferLast_;
eof_ = true; eof_ = true;
} }
} }
} }
std::FILE* fp_; std::FILE* fp_;
Ch *buffer_; Ch *buffer_;
size_t bufferSize_; size_t bufferSize_;
Ch *bufferLast_; Ch *bufferLast_;
Ch *current_; Ch *current_;
size_t readCount_; size_t readCount_;
size_t count_; //!< Number of characters read size_t count_; //!< Number of characters read
bool eof_; bool eof_;
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#endif // RAPIDJSON_FILESTREAM_H_ #endif // RAPIDJSON_FILESTREAM_H_

View file

@ -1,104 +1,104 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEWRITESTREAM_H_ #ifndef RAPIDJSON_FILEWRITESTREAM_H_
#define RAPIDJSON_FILEWRITESTREAM_H_ #define RAPIDJSON_FILEWRITESTREAM_H_
#include "rapidjson.h" #include "stream.h"
#include <cstdio> #include <cstdio>
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable-code)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of C file stream for input using fread(). //! Wrapper of C file stream for input using fread().
/*! /*!
\note implements Stream concept \note implements Stream concept
*/ */
class FileWriteStream { class FileWriteStream {
public: public:
typedef char Ch; //!< Character type. Only support char. typedef char Ch; //!< Character type. Only support char.
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(fp_ != 0);
} }
void Put(char c) { void Put(char c) {
if (current_ >= bufferEnd_) if (current_ >= bufferEnd_)
Flush(); Flush();
*current_++ = c; *current_++ = c;
} }
void PutN(char c, size_t n) { void PutN(char c, size_t n) {
size_t avail = static_cast<size_t>(bufferEnd_ - current_); size_t avail = static_cast<size_t>(bufferEnd_ - current_);
while (n > avail) { while (n > avail) {
std::memset(current_, c, avail); std::memset(current_, c, avail);
current_ += avail; current_ += avail;
Flush(); Flush();
n -= avail; n -= avail;
avail = static_cast<size_t>(bufferEnd_ - current_); avail = static_cast<size_t>(bufferEnd_ - current_);
} }
if (n > 0) { if (n > 0) {
std::memset(current_, c, n); std::memset(current_, c, n);
current_ += n; current_ += n;
} }
} }
void Flush() { void Flush() {
if (current_ != buffer_) { if (current_ != buffer_) {
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_); size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
if (result < static_cast<size_t>(current_ - buffer_)) { if (result < static_cast<size_t>(current_ - buffer_)) {
// failure deliberately ignored at this time // failure deliberately ignored at this time
// added to avoid warn_unused_result build errors // added to avoid warn_unused_result build errors
} }
current_ = buffer_; current_ = buffer_;
} }
} }
// Not implemented // Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
char Take() { RAPIDJSON_ASSERT(false); return 0; } char Take() { RAPIDJSON_ASSERT(false); return 0; }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
private: private:
// Prohibit copy constructor & assignment operator. // Prohibit copy constructor & assignment operator.
FileWriteStream(const FileWriteStream&); FileWriteStream(const FileWriteStream&);
FileWriteStream& operator=(const FileWriteStream&); FileWriteStream& operator=(const FileWriteStream&);
std::FILE* fp_; std::FILE* fp_;
char *buffer_; char *buffer_;
char *bufferEnd_; char *bufferEnd_;
char *current_; char *current_;
}; };
//! Implement specialized version of PutN() with memset() for better performance. //! Implement specialized version of PutN() with memset() for better performance.
template<> template<>
inline void PutN(FileWriteStream& stream, char c, size_t n) { inline void PutN(FileWriteStream& stream, char c, size_t n) {
stream.PutN(c, n); stream.PutN(c, n);
} }
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#endif // RAPIDJSON_FILESTREAM_H_ #endif // RAPIDJSON_FILESTREAM_H_

151
external/rapidjson/fwd.h vendored Normal file
View file

@ -0,0 +1,151 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FWD_H_
#define RAPIDJSON_FWD_H_
#include "rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
// encodings.h
template<typename CharType> struct UTF8;
template<typename CharType> struct UTF16;
template<typename CharType> struct UTF16BE;
template<typename CharType> struct UTF16LE;
template<typename CharType> struct UTF32;
template<typename CharType> struct UTF32BE;
template<typename CharType> struct UTF32LE;
template<typename CharType> struct ASCII;
template<typename CharType> struct AutoUTF;
template<typename SourceEncoding, typename TargetEncoding>
struct Transcoder;
// allocators.h
class CrtAllocator;
template <typename BaseAllocator>
class MemoryPoolAllocator;
// stream.h
template <typename Encoding>
struct GenericStringStream;
typedef GenericStringStream<UTF8<char> > StringStream;
template <typename Encoding>
struct GenericInsituStringStream;
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
// stringbuffer.h
template <typename Encoding, typename Allocator>
class GenericStringBuffer;
typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
// filereadstream.h
class FileReadStream;
// filewritestream.h
class FileWriteStream;
// memorybuffer.h
template <typename Allocator>
struct GenericMemoryBuffer;
typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
// memorystream.h
struct MemoryStream;
// reader.h
template<typename Encoding, typename Derived>
struct BaseReaderHandler;
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
class GenericReader;
typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
// writer.h
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
class Writer;
// prettywriter.h
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
class PrettyWriter;
// document.h
template <typename Encoding, typename Allocator>
struct GenericMember;
template <bool Const, typename Encoding, typename Allocator>
class GenericMemberIterator;
template<typename CharType>
struct GenericStringRef;
template <typename Encoding, typename Allocator>
class GenericValue;
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
template <typename Encoding, typename Allocator, typename StackAllocator>
class GenericDocument;
typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
// pointer.h
template <typename ValueType, typename Allocator>
class GenericPointer;
typedef GenericPointer<Value, CrtAllocator> Pointer;
// schema.h
template <typename SchemaDocumentType>
class IGenericRemoteSchemaDocumentProvider;
template <typename ValueT, typename Allocator>
class GenericSchemaDocument;
typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
template <
typename SchemaDocumentType,
typename OutputHandler,
typename StateAllocator>
class GenericSchemaValidator;
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_RAPIDJSONFWD_H_

0
external/rapidjson/internal/biginteger.h vendored Executable file → Normal file
View file

View file

@ -41,7 +41,7 @@ RAPIDJSON_DIAG_OFF(padded)
#endif #endif
struct DiyFp { struct DiyFp {
DiyFp() {} DiyFp() : f(), e() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}

View file

@ -29,6 +29,7 @@ namespace internal {
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
#endif #endif
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
@ -101,7 +102,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
kappa--; kappa--;
if (p2 < delta) { if (p2 < delta) {
*K += kappa; *K += kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast<int>(kappa)]); int index = -static_cast<int>(kappa);
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
return; return;
} }
} }
@ -145,10 +147,10 @@ inline char* WriteExponent(int K, char* buffer) {
return buffer; return buffer;
} }
inline char* Prettify(char* buffer, int length, int k) { inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
const int kk = length + k; // 10^(kk-1) <= v < 10^kk const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (length <= kk && kk <= 21) { if (0 <= k && kk <= 21) {
// 1234e7 -> 12340000000 // 1234e7 -> 12340000000
for (int i = length; i < kk; i++) for (int i = length; i < kk; i++)
buffer[i] = '0'; buffer[i] = '0';
@ -160,7 +162,16 @@ inline char* Prettify(char* buffer, int length, int k) {
// 1234e-2 -> 12.34 // 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk)); std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
buffer[kk] = '.'; buffer[kk] = '.';
return &buffer[length + 1]; if (0 > k + maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
if (buffer[i] != '0')
return &buffer[i + 1];
return &buffer[kk + 2]; // Reserve one zero
}
else
return &buffer[length + 1];
} }
else if (-6 < kk && kk <= 0) { else if (-6 < kk && kk <= 0) {
// 1234e-6 -> 0.001234 // 1234e-6 -> 0.001234
@ -170,7 +181,23 @@ inline char* Prettify(char* buffer, int length, int k) {
buffer[1] = '.'; buffer[1] = '.';
for (int i = 2; i < offset; i++) for (int i = 2; i < offset; i++)
buffer[i] = '0'; buffer[i] = '0';
return &buffer[length + offset]; if (length - kk > maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = maxDecimalPlaces + 1; i > 2; i--)
if (buffer[i] != '0')
return &buffer[i + 1];
return &buffer[3]; // Reserve one zero
}
else
return &buffer[length + offset];
}
else if (kk < -maxDecimalPlaces) {
// Truncate to zero
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
return &buffer[3];
} }
else if (length == 1) { else if (length == 1) {
// 1e30 // 1e30
@ -186,7 +213,8 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
} }
inline char* dtoa(double value, char* buffer) { inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
Double d(value); Double d(value);
if (d.IsZero()) { if (d.IsZero()) {
if (d.Sign()) if (d.Sign())
@ -203,7 +231,7 @@ inline char* dtoa(double value, char* buffer) {
} }
int length, K; int length, K;
Grisu2(value, buffer, &length, &K); Grisu2(value, buffer, &length, &K);
return Prettify(buffer, length, K); return Prettify(buffer, length, K, maxDecimalPlaces);
} }
} }

View file

@ -40,6 +40,7 @@ public:
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }

View file

@ -1,181 +1,181 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_META_H_ #ifndef RAPIDJSON_INTERNAL_META_H_
#define RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_
#include "../rapidjson.h" #include "../rapidjson.h"
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(6334) RAPIDJSON_DIAG_OFF(6334)
#endif #endif
#if RAPIDJSON_HAS_CXX11_TYPETRAITS #if RAPIDJSON_HAS_CXX11_TYPETRAITS
#include <type_traits> #include <type_traits>
#endif #endif
//@cond RAPIDJSON_INTERNAL //@cond RAPIDJSON_INTERNAL
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
template <typename T> struct Void { typedef void Type; }; template <typename T> struct Void { typedef void Type; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// BoolType, TrueType, FalseType // BoolType, TrueType, FalseType
// //
template <bool Cond> struct BoolType { template <bool Cond> struct BoolType {
static const bool Value = Cond; static const bool Value = Cond;
typedef BoolType Type; typedef BoolType Type;
}; };
typedef BoolType<true> TrueType; typedef BoolType<true> TrueType;
typedef BoolType<false> FalseType; typedef BoolType<false> FalseType;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
// //
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; }; template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; }; template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {}; template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {}; template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {}; template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
template <> struct AndExprCond<true, true> : TrueType {}; template <> struct AndExprCond<true, true> : TrueType {};
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {}; template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
template <> struct OrExprCond<false, false> : FalseType {}; template <> struct OrExprCond<false, false> : FalseType {};
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {}; template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {}; template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {}; template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {}; template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// AddConst, MaybeAddConst, RemoveConst // AddConst, MaybeAddConst, RemoveConst
template <typename T> struct AddConst { typedef const T Type; }; template <typename T> struct AddConst { typedef const T Type; };
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {}; template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
template <typename T> struct RemoveConst { typedef T Type; }; template <typename T> struct RemoveConst { typedef T Type; };
template <typename T> struct RemoveConst<const T> { typedef T Type; }; template <typename T> struct RemoveConst<const T> { typedef T Type; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// IsSame, IsConst, IsMoreConst, IsPointer // IsSame, IsConst, IsMoreConst, IsPointer
// //
template <typename T, typename U> struct IsSame : FalseType {}; template <typename T, typename U> struct IsSame : FalseType {};
template <typename T> struct IsSame<T, T> : TrueType {}; template <typename T> struct IsSame<T, T> : TrueType {};
template <typename T> struct IsConst : FalseType {}; template <typename T> struct IsConst : FalseType {};
template <typename T> struct IsConst<const T> : TrueType {}; template <typename T> struct IsConst<const T> : TrueType {};
template <typename CT, typename T> template <typename CT, typename T>
struct IsMoreConst struct IsMoreConst
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>, : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {}; BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
template <typename T> struct IsPointer : FalseType {}; template <typename T> struct IsPointer : FalseType {};
template <typename T> struct IsPointer<T*> : TrueType {}; template <typename T> struct IsPointer<T*> : TrueType {};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// IsBaseOf // IsBaseOf
// //
#if RAPIDJSON_HAS_CXX11_TYPETRAITS #if RAPIDJSON_HAS_CXX11_TYPETRAITS
template <typename B, typename D> struct IsBaseOf template <typename B, typename D> struct IsBaseOf
: BoolType< ::std::is_base_of<B,D>::value> {}; : BoolType< ::std::is_base_of<B,D>::value> {};
#else // simplified version adopted from Boost #else // simplified version adopted from Boost
template<typename B, typename D> struct IsBaseOfImpl { template<typename B, typename D> struct IsBaseOfImpl {
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
typedef char (&Yes)[1]; typedef char (&Yes)[1];
typedef char (&No) [2]; typedef char (&No) [2];
template <typename T> template <typename T>
static Yes Check(const D*, T); static Yes Check(const D*, T);
static No Check(const B*, int); static No Check(const B*, int);
struct Host { struct Host {
operator const B*() const; operator const B*() const;
operator const D*(); operator const D*();
}; };
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
}; };
template <typename B, typename D> struct IsBaseOf template <typename B, typename D> struct IsBaseOf
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {}; : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// EnableIf / DisableIf // EnableIf / DisableIf
// //
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; }; template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
template <typename T> struct EnableIfCond<false, T> { /* empty */ }; template <typename T> struct EnableIfCond<false, T> { /* empty */ };
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; }; template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
template <typename T> struct DisableIfCond<true, T> { /* empty */ }; template <typename T> struct DisableIfCond<true, T> { /* empty */ };
template <typename Condition, typename T = void> template <typename Condition, typename T = void>
struct EnableIf : EnableIfCond<Condition::Value, T> {}; struct EnableIf : EnableIfCond<Condition::Value, T> {};
template <typename Condition, typename T = void> template <typename Condition, typename T = void>
struct DisableIf : DisableIfCond<Condition::Value, T> {}; struct DisableIf : DisableIfCond<Condition::Value, T> {};
// SFINAE helpers // SFINAE helpers
struct SfinaeTag {}; struct SfinaeTag {};
template <typename T> struct RemoveSfinaeTag; template <typename T> struct RemoveSfinaeTag;
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; }; template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
#define RAPIDJSON_REMOVEFPTR_(type) \ #define RAPIDJSON_REMOVEFPTR_(type) \
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
#define RAPIDJSON_ENABLEIF(cond) \ #define RAPIDJSON_ENABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_DISABLEIF(cond) \ #define RAPIDJSON_DISABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \ <RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type RAPIDJSON_REMOVEFPTR_(returntype)>::Type
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \ <RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type RAPIDJSON_REMOVEFPTR_(returntype)>::Type
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
//@endcond //@endcond
#if defined(__GNUC__) || defined(_MSC_VER) #if defined(__GNUC__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#endif // RAPIDJSON_INTERNAL_META_H_ #endif // RAPIDJSON_INTERNAL_META_H_

View file

@ -1,55 +1,55 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_POW10_ #ifndef RAPIDJSON_POW10_
#define RAPIDJSON_POW10_ #define RAPIDJSON_POW10_
#include "../rapidjson.h" #include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
//! Computes integer powers of 10 in double (10.0^n). //! Computes integer powers of 10 in double (10.0^n).
/*! This function uses lookup table for fast and accurate results. /*! This function uses lookup table for fast and accurate results.
\param n non-negative exponent. Must <= 308. \param n non-negative exponent. Must <= 308.
\return 10.0^n \return 10.0^n
*/ */
inline double Pow10(int n) { inline double Pow10(int n) {
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
1e+0, 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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
}; };
RAPIDJSON_ASSERT(n >= 0 && n <= 308); RAPIDJSON_ASSERT(n >= 0 && n <= 308);
return e[n]; return e[n];
} }
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_POW10_ #endif // RAPIDJSON_POW10_

731
external/rapidjson/internal/regex.h vendored Normal file
View file

@ -0,0 +1,731 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_REGEX_H_
#define RAPIDJSON_INTERNAL_REGEX_H_
#include "../allocators.h"
#include "../stream.h"
#include "stack.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
#ifndef RAPIDJSON_REGEX_VERBOSE
#define RAPIDJSON_REGEX_VERBOSE 0
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
///////////////////////////////////////////////////////////////////////////////
// DecodedStream
template <typename SourceStream, typename Encoding>
class DecodedStream {
public:
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
unsigned Peek() { return codepoint_; }
unsigned Take() {
unsigned c = codepoint_;
if (c) // No further decoding when '\0'
Decode();
return c;
}
private:
void Decode() {
if (!Encoding::Decode(ss_, &codepoint_))
codepoint_ = 0;
}
SourceStream& ss_;
unsigned codepoint_;
};
///////////////////////////////////////////////////////////////////////////////
// GenericRegex
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
static const SizeType kRegexInvalidRange = ~SizeType(0);
template <typename Encoding, typename Allocator>
class GenericRegexSearch;
//! Regular expression engine with subset of ECMAscript grammar.
/*!
Supported regular expression syntax:
- \c ab Concatenation
- \c a|b Alternation
- \c a? Zero or one
- \c a* Zero or more
- \c a+ One or more
- \c a{3} Exactly 3 times
- \c a{3,} At least 3 times
- \c a{3,5} 3 to 5 times
- \c (ab) Grouping
- \c ^a At the beginning
- \c a$ At the end
- \c . Any character
- \c [abc] Character classes
- \c [a-c] Character class range
- \c [a-z0-9_] Character class combination
- \c [^abc] Negated character classes
- \c [^a-c] Negated character class range
- \c [\b] Backspace (U+0008)
- \c \\| \\\\ ... Escape characters
- \c \\f Form feed (U+000C)
- \c \\n Line feed (U+000A)
- \c \\r Carriage return (U+000D)
- \c \\t Tab (U+0009)
- \c \\v Vertical tab (U+000B)
\note This is a Thompson NFA engine, implemented with reference to
Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
https://swtch.com/~rsc/regexp/regexp1.html
*/
template <typename Encoding, typename Allocator = CrtAllocator>
class GenericRegex {
public:
typedef Encoding EncodingType;
typedef typename Encoding::Ch Ch;
template <typename, typename> friend class GenericRegexSearch;
GenericRegex(const Ch* source, Allocator* allocator = 0) :
states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
anchorBegin_(), anchorEnd_()
{
GenericStringStream<Encoding> ss(source);
DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
Parse(ds);
}
~GenericRegex() {}
bool IsValid() const {
return root_ != kRegexInvalidState;
}
private:
enum Operator {
kZeroOrOne,
kZeroOrMore,
kOneOrMore,
kConcatenation,
kAlternation,
kLeftParenthesis
};
static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
static const unsigned kRangeNegationFlag = 0x80000000;
struct Range {
unsigned start; //
unsigned end;
SizeType next;
};
struct State {
SizeType out; //!< Equals to kInvalid for matching state
SizeType out1; //!< Equals to non-kInvalid for split
SizeType rangeStart;
unsigned codepoint;
};
struct Frag {
Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
SizeType start;
SizeType out; //!< link-list of all output states
SizeType minIndex;
};
State& GetState(SizeType index) {
RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index];
}
const State& GetState(SizeType index) const {
RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index];
}
Range& GetRange(SizeType index) {
RAPIDJSON_ASSERT(index < rangeCount_);
return ranges_.template Bottom<Range>()[index];
}
const Range& GetRange(SizeType index) const {
RAPIDJSON_ASSERT(index < rangeCount_);
return ranges_.template Bottom<Range>()[index];
}
template <typename InputStream>
void Parse(DecodedStream<InputStream, Encoding>& ds) {
Allocator allocator;
Stack<Allocator> operandStack(&allocator, 256); // Frag
Stack<Allocator> operatorStack(&allocator, 256); // Operator
Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
*atomCountStack.template Push<unsigned>() = 0;
unsigned codepoint;
while (ds.Peek() != 0) {
switch (codepoint = ds.Take()) {
case '^':
anchorBegin_ = true;
break;
case '$':
anchorEnd_ = true;
break;
case '|':
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
return;
*operatorStack.template Push<Operator>() = kAlternation;
*atomCountStack.template Top<unsigned>() = 0;
break;
case '(':
*operatorStack.template Push<Operator>() = kLeftParenthesis;
*atomCountStack.template Push<unsigned>() = 0;
break;
case ')':
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
return;
if (operatorStack.Empty())
return;
operatorStack.template Pop<Operator>(1);
atomCountStack.template Pop<unsigned>(1);
ImplicitConcatenation(atomCountStack, operatorStack);
break;
case '?':
if (!Eval(operandStack, kZeroOrOne))
return;
break;
case '*':
if (!Eval(operandStack, kZeroOrMore))
return;
break;
case '+':
if (!Eval(operandStack, kOneOrMore))
return;
break;
case '{':
{
unsigned n, m;
if (!ParseUnsigned(ds, &n))
return;
if (ds.Peek() == ',') {
ds.Take();
if (ds.Peek() == '}')
m = kInfinityQuantifier;
else if (!ParseUnsigned(ds, &m) || m < n)
return;
}
else
m = n;
if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
return;
ds.Take();
}
break;
case '.':
PushOperand(operandStack, kAnyCharacterClass);
ImplicitConcatenation(atomCountStack, operatorStack);
break;
case '[':
{
SizeType range;
if (!ParseRange(ds, &range))
return;
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
GetState(s).rangeStart = range;
*operandStack.template Push<Frag>() = Frag(s, s, s);
}
ImplicitConcatenation(atomCountStack, operatorStack);
break;
case '\\': // Escape character
if (!CharacterEscape(ds, &codepoint))
return; // Unsupported escape character
// fall through to default
default: // Pattern character
PushOperand(operandStack, codepoint);
ImplicitConcatenation(atomCountStack, operatorStack);
}
}
while (!operatorStack.Empty())
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
return;
// Link the operand to matching state.
if (operandStack.GetSize() == sizeof(Frag)) {
Frag* e = operandStack.template Pop<Frag>(1);
Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
root_ = e->start;
#if RAPIDJSON_REGEX_VERBOSE
printf("root: %d\n", root_);
for (SizeType i = 0; i < stateCount_ ; i++) {
State& s = GetState(i);
printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
}
printf("\n");
#endif
}
}
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
State* s = states_.template Push<State>();
s->out = out;
s->out1 = out1;
s->codepoint = codepoint;
s->rangeStart = kRegexInvalidRange;
return stateCount_++;
}
void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
*operandStack.template Push<Frag>() = Frag(s, s, s);
}
void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
if (*atomCountStack.template Top<unsigned>())
*operatorStack.template Push<Operator>() = kConcatenation;
(*atomCountStack.template Top<unsigned>())++;
}
SizeType Append(SizeType l1, SizeType l2) {
SizeType old = l1;
while (GetState(l1).out != kRegexInvalidState)
l1 = GetState(l1).out;
GetState(l1).out = l2;
return old;
}
void Patch(SizeType l, SizeType s) {
for (SizeType next; l != kRegexInvalidState; l = next) {
next = GetState(l).out;
GetState(l).out = s;
}
}
bool Eval(Stack<Allocator>& operandStack, Operator op) {
switch (op) {
case kConcatenation:
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
{
Frag e2 = *operandStack.template Pop<Frag>(1);
Frag e1 = *operandStack.template Pop<Frag>(1);
Patch(e1.out, e2.start);
*operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
}
return true;
case kAlternation:
if (operandStack.GetSize() >= sizeof(Frag) * 2) {
Frag e2 = *operandStack.template Pop<Frag>(1);
Frag e1 = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(e1.start, e2.start, 0);
*operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
return true;
}
return false;
case kZeroOrOne:
if (operandStack.GetSize() >= sizeof(Frag)) {
Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0);
*operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
return true;
}
return false;
case kZeroOrMore:
if (operandStack.GetSize() >= sizeof(Frag)) {
Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0);
Patch(e.out, s);
*operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
return true;
}
return false;
default:
RAPIDJSON_ASSERT(op == kOneOrMore);
if (operandStack.GetSize() >= sizeof(Frag)) {
Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0);
Patch(e.out, s);
*operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
return true;
}
return false;
}
}
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
RAPIDJSON_ASSERT(n <= m);
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
if (n == 0) {
if (m == 0) // a{0} not support
return false;
else if (m == kInfinityQuantifier)
Eval(operandStack, kZeroOrMore); // a{0,} -> a*
else {
Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
for (unsigned i = 0; i < m - 1; i++)
CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
for (unsigned i = 0; i < m - 1; i++)
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
}
return true;
}
for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
CloneTopOperand(operandStack);
if (m == kInfinityQuantifier)
Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
else if (m > n) {
CloneTopOperand(operandStack); // a{3,5} -> a a a a
Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
for (unsigned i = n; i < m - 1; i++)
CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
for (unsigned i = n; i < m; i++)
Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
}
for (unsigned i = 0; i < n - 1; i++)
Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
return true;
}
static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
void CloneTopOperand(Stack<Allocator>& operandStack) {
const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
State* s = states_.template Push<State>(count);
memcpy(s, &GetState(src.minIndex), count * sizeof(State));
for (SizeType j = 0; j < count; j++) {
if (s[j].out != kRegexInvalidState)
s[j].out += count;
if (s[j].out1 != kRegexInvalidState)
s[j].out1 += count;
}
*operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
stateCount_ += count;
}
template <typename InputStream>
bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
unsigned r = 0;
if (ds.Peek() < '0' || ds.Peek() > '9')
return false;
while (ds.Peek() >= '0' && ds.Peek() <= '9') {
if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
return false; // overflow
r = r * 10 + (ds.Take() - '0');
}
*u = r;
return true;
}
template <typename InputStream>
bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
bool isBegin = true;
bool negate = false;
int step = 0;
SizeType start = kRegexInvalidRange;
SizeType current = kRegexInvalidRange;
unsigned codepoint;
while ((codepoint = ds.Take()) != 0) {
if (isBegin) {
isBegin = false;
if (codepoint == '^') {
negate = true;
continue;
}
}
switch (codepoint) {
case ']':
if (start == kRegexInvalidRange)
return false; // Error: nothing inside []
if (step == 2) { // Add trailing '-'
SizeType r = NewRange('-');
RAPIDJSON_ASSERT(current != kRegexInvalidRange);
GetRange(current).next = r;
}
if (negate)
GetRange(start).start |= kRangeNegationFlag;
*range = start;
return true;
case '\\':
if (ds.Peek() == 'b') {
ds.Take();
codepoint = 0x0008; // Escape backspace character
}
else if (!CharacterEscape(ds, &codepoint))
return false;
// fall through to default
default:
switch (step) {
case 1:
if (codepoint == '-') {
step++;
break;
}
// fall through to step 0 for other characters
case 0:
{
SizeType r = NewRange(codepoint);
if (current != kRegexInvalidRange)
GetRange(current).next = r;
if (start == kRegexInvalidRange)
start = r;
current = r;
}
step = 1;
break;
default:
RAPIDJSON_ASSERT(step == 2);
GetRange(current).end = codepoint;
step = 0;
}
}
}
return false;
}
SizeType NewRange(unsigned codepoint) {
Range* r = ranges_.template Push<Range>();
r->start = r->end = codepoint;
r->next = kRegexInvalidRange;
return rangeCount_++;
}
template <typename InputStream>
bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
unsigned codepoint;
switch (codepoint = ds.Take()) {
case '^':
case '$':
case '|':
case '(':
case ')':
case '?':
case '*':
case '+':
case '.':
case '[':
case ']':
case '{':
case '}':
case '\\':
*escapedCodepoint = codepoint; return true;
case 'f': *escapedCodepoint = 0x000C; return true;
case 'n': *escapedCodepoint = 0x000A; return true;
case 'r': *escapedCodepoint = 0x000D; return true;
case 't': *escapedCodepoint = 0x0009; return true;
case 'v': *escapedCodepoint = 0x000B; return true;
default:
return false; // Unsupported escape character
}
}
Stack<Allocator> states_;
Stack<Allocator> ranges_;
SizeType root_;
SizeType stateCount_;
SizeType rangeCount_;
static const unsigned kInfinityQuantifier = ~0u;
// For SearchWithAnchoring()
bool anchorBegin_;
bool anchorEnd_;
};
template <typename RegexType, typename Allocator = CrtAllocator>
class GenericRegexSearch {
public:
typedef typename RegexType::EncodingType Encoding;
typedef typename Encoding::Ch Ch;
GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
regex_(regex), allocator_(allocator), ownAllocator_(0),
state0_(allocator, 0), state1_(allocator, 0), stateSet_()
{
RAPIDJSON_ASSERT(regex_.IsValid());
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
state0_.template Reserve<SizeType>(regex_.stateCount_);
state1_.template Reserve<SizeType>(regex_.stateCount_);
}
~GenericRegexSearch() {
Allocator::Free(stateSet_);
RAPIDJSON_DELETE(ownAllocator_);
}
template <typename InputStream>
bool Match(InputStream& is) {
return SearchWithAnchoring(is, true, true);
}
bool Match(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Match(is);
}
template <typename InputStream>
bool Search(InputStream& is) {
return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
}
bool Search(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Search(is);
}
private:
typedef typename RegexType::State State;
typedef typename RegexType::Range Range;
template <typename InputStream>
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
DecodedStream<InputStream, Encoding> ds(is);
state0_.Clear();
Stack<Allocator> *current = &state0_, *next = &state1_;
const size_t stateSetSize = GetStateSetSize();
std::memset(stateSet_, 0, stateSetSize);
bool matched = AddState(*current, regex_.root_);
unsigned codepoint;
while (!current->Empty() && (codepoint = ds.Take()) != 0) {
std::memset(stateSet_, 0, stateSetSize);
next->Clear();
matched = false;
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
const State& sr = regex_.GetState(*s);
if (sr.codepoint == codepoint ||
sr.codepoint == RegexType::kAnyCharacterClass ||
(sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
{
matched = AddState(*next, sr.out) || matched;
if (!anchorEnd && matched)
return true;
}
if (!anchorBegin)
AddState(*next, regex_.root_);
}
internal::Swap(current, next);
}
return matched;
}
size_t GetStateSetSize() const {
return (regex_.stateCount_ + 31) / 32 * 4;
}
// Return whether the added states is a match state
bool AddState(Stack<Allocator>& l, SizeType index) {
RAPIDJSON_ASSERT(index != kRegexInvalidState);
const State& s = regex_.GetState(index);
if (s.out1 != kRegexInvalidState) { // Split
bool matched = AddState(l, s.out);
return AddState(l, s.out1) || matched;
}
else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
stateSet_[index >> 5] |= (1 << (index & 31));
*l.template PushUnsafe<SizeType>() = index;
}
return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
}
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
while (rangeIndex != kRegexInvalidRange) {
const Range& r = regex_.GetRange(rangeIndex);
if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
return yes;
rangeIndex = r.next;
}
return !yes;
}
const RegexType& regex_;
Allocator* allocator_;
Allocator* ownAllocator_;
Stack<Allocator> state0_;
Stack<Allocator> state1_;
uint32_t* stateSet_;
};
typedef GenericRegex<UTF8<> > Regex;
typedef GenericRegexSearch<Regex> RegexSearch;
} // namespace internal
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_INTERNAL_REGEX_H_

View file

@ -1,196 +1,230 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STACK_H_ #ifndef RAPIDJSON_INTERNAL_STACK_H_
#define RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_
#include "../rapidjson.h" #include "../allocators.h"
#include "swap.h" #include "swap.h"
RAPIDJSON_NAMESPACE_BEGIN #if defined(__clang__)
namespace internal { RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat)
/////////////////////////////////////////////////////////////////////////////// #endif
// Stack
RAPIDJSON_NAMESPACE_BEGIN
//! A type-unsafe stack for storing different types of data. namespace internal {
/*! \tparam Allocator Allocator for allocating stack memory.
*/ ///////////////////////////////////////////////////////////////////////////////
template <typename Allocator> // Stack
class Stack {
public: //! A type-unsafe stack for storing different types of data.
// Optimization note: Do not allocate memory for stack_ in constructor. /*! \tparam Allocator Allocator for allocating stack memory.
// Do it lazily when first Push() -> Expand() -> Resize(). */
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { template <typename Allocator>
RAPIDJSON_ASSERT(stackCapacity > 0); class Stack {
} public:
// Optimization note: Do not allocate memory for stack_ in constructor.
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS // Do it lazily when first Push() -> Expand() -> Resize().
Stack(Stack&& rhs) Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
: allocator_(rhs.allocator_), }
ownAllocator_(rhs.ownAllocator_),
stack_(rhs.stack_), #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
stackTop_(rhs.stackTop_), Stack(Stack&& rhs)
stackEnd_(rhs.stackEnd_), : allocator_(rhs.allocator_),
initialCapacity_(rhs.initialCapacity_) ownAllocator_(rhs.ownAllocator_),
{ stack_(rhs.stack_),
rhs.allocator_ = 0; stackTop_(rhs.stackTop_),
rhs.ownAllocator_ = 0; stackEnd_(rhs.stackEnd_),
rhs.stack_ = 0; initialCapacity_(rhs.initialCapacity_)
rhs.stackTop_ = 0; {
rhs.stackEnd_ = 0; rhs.allocator_ = 0;
rhs.initialCapacity_ = 0; rhs.ownAllocator_ = 0;
} rhs.stack_ = 0;
#endif rhs.stackTop_ = 0;
rhs.stackEnd_ = 0;
~Stack() { rhs.initialCapacity_ = 0;
Destroy(); }
} #endif
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS ~Stack() {
Stack& operator=(Stack&& rhs) { Destroy();
if (&rhs != this) }
{
Destroy(); #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack& operator=(Stack&& rhs) {
allocator_ = rhs.allocator_; if (&rhs != this)
ownAllocator_ = rhs.ownAllocator_; {
stack_ = rhs.stack_; Destroy();
stackTop_ = rhs.stackTop_;
stackEnd_ = rhs.stackEnd_; allocator_ = rhs.allocator_;
initialCapacity_ = rhs.initialCapacity_; ownAllocator_ = rhs.ownAllocator_;
stack_ = rhs.stack_;
rhs.allocator_ = 0; stackTop_ = rhs.stackTop_;
rhs.ownAllocator_ = 0; stackEnd_ = rhs.stackEnd_;
rhs.stack_ = 0; initialCapacity_ = rhs.initialCapacity_;
rhs.stackTop_ = 0;
rhs.stackEnd_ = 0; rhs.allocator_ = 0;
rhs.initialCapacity_ = 0; rhs.ownAllocator_ = 0;
} rhs.stack_ = 0;
return *this; rhs.stackTop_ = 0;
} rhs.stackEnd_ = 0;
#endif rhs.initialCapacity_ = 0;
}
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { return *this;
internal::Swap(allocator_, rhs.allocator_); }
internal::Swap(ownAllocator_, rhs.ownAllocator_); #endif
internal::Swap(stack_, rhs.stack_);
internal::Swap(stackTop_, rhs.stackTop_); void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
internal::Swap(stackEnd_, rhs.stackEnd_); internal::Swap(allocator_, rhs.allocator_);
internal::Swap(initialCapacity_, rhs.initialCapacity_); internal::Swap(ownAllocator_, rhs.ownAllocator_);
} internal::Swap(stack_, rhs.stack_);
internal::Swap(stackTop_, rhs.stackTop_);
void Clear() { stackTop_ = stack_; } internal::Swap(stackEnd_, rhs.stackEnd_);
internal::Swap(initialCapacity_, rhs.initialCapacity_);
void ShrinkToFit() { }
if (Empty()) {
// If the stack is empty, completely deallocate the memory. void Clear() { stackTop_ = stack_; }
Allocator::Free(stack_);
stack_ = 0; void ShrinkToFit() {
stackTop_ = 0; if (Empty()) {
stackEnd_ = 0; // If the stack is empty, completely deallocate the memory.
} Allocator::Free(stack_);
else stack_ = 0;
Resize(GetSize()); stackTop_ = 0;
} stackEnd_ = 0;
}
// Optimization note: try to minimize the size of this function for force inline. else
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function. Resize(GetSize());
template<typename T> }
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
// Expand the stack if needed // Optimization note: try to minimize the size of this function for force inline.
if (stackTop_ + sizeof(T) * count >= stackEnd_) // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
Expand<T>(count); template<typename T>
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
T* ret = reinterpret_cast<T*>(stackTop_); // Expand the stack if needed
stackTop_ += sizeof(T) * count; if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
return ret; Expand<T>(count);
} }
template<typename T> template<typename T>
T* Pop(size_t count) { RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); Reserve<T>(count);
stackTop_ -= count * sizeof(T); return PushUnsafe<T>(count);
return reinterpret_cast<T*>(stackTop_); }
}
template<typename T>
template<typename T> RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
T* Top() { RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); T* ret = reinterpret_cast<T*>(stackTop_);
return reinterpret_cast<T*>(stackTop_ - sizeof(T)); stackTop_ += sizeof(T) * count;
} return ret;
}
template<typename T>
T* Bottom() { return reinterpret_cast<T*>(stack_); } template<typename T>
T* Pop(size_t count) {
bool HasAllocator() const { RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
return allocator_ != 0; stackTop_ -= count * sizeof(T);
} return reinterpret_cast<T*>(stackTop_);
}
Allocator& GetAllocator() {
RAPIDJSON_ASSERT(allocator_); template<typename T>
return *allocator_; T* Top() {
} RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
bool Empty() const { return stackTop_ == stack_; } return reinterpret_cast<T*>(stackTop_ - sizeof(T));
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); } }
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
template<typename T>
private: const T* Top() const {
template<typename T> RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
void Expand(size_t count) { return reinterpret_cast<T*>(stackTop_ - sizeof(T));
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. }
size_t newCapacity;
if (stack_ == 0) { template<typename T>
if (!allocator_) T* End() { return reinterpret_cast<T*>(stackTop_); }
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
newCapacity = initialCapacity_; template<typename T>
} else { const T* End() const { return reinterpret_cast<T*>(stackTop_); }
newCapacity = GetCapacity();
newCapacity += (newCapacity + 1) / 2; template<typename T>
} T* Bottom() { return reinterpret_cast<T*>(stack_); }
size_t newSize = GetSize() + sizeof(T) * count;
if (newCapacity < newSize) template<typename T>
newCapacity = newSize; const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
Resize(newCapacity); bool HasAllocator() const {
} return allocator_ != 0;
}
void Resize(size_t newCapacity) {
const size_t size = GetSize(); // Backup the current size Allocator& GetAllocator() {
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); RAPIDJSON_ASSERT(allocator_);
stackTop_ = stack_ + size; return *allocator_;
stackEnd_ = stack_ + newCapacity; }
}
bool Empty() const { return stackTop_ == stack_; }
void Destroy() { size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
Allocator::Free(stack_); size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
} private:
template<typename T>
// Prohibit copy constructor & assignment operator. void Expand(size_t count) {
Stack(const Stack&); // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
Stack& operator=(const Stack&); size_t newCapacity;
if (stack_ == 0) {
Allocator* allocator_; if (!allocator_)
Allocator* ownAllocator_; ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
char *stack_; newCapacity = initialCapacity_;
char *stackTop_; } else {
char *stackEnd_; newCapacity = GetCapacity();
size_t initialCapacity_; newCapacity += (newCapacity + 1) / 2;
}; }
size_t newSize = GetSize() + sizeof(T) * count;
} // namespace internal if (newCapacity < newSize)
RAPIDJSON_NAMESPACE_END newCapacity = newSize;
#endif // RAPIDJSON_STACK_H_ Resize(newCapacity);
}
void Resize(size_t newCapacity) {
const size_t size = GetSize(); // Backup the current size
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
stackTop_ = stack_ + size;
stackEnd_ = stack_ + newCapacity;
}
void Destroy() {
Allocator::Free(stack_);
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
}
// Prohibit copy constructor & assignment operator.
Stack(const Stack&);
Stack& operator=(const Stack&);
Allocator* allocator_;
Allocator* ownAllocator_;
char *stack_;
char *stackTop_;
char *stackEnd_;
size_t initialCapacity_;
};
} // namespace internal
RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_STACK_H_

View file

@ -1,39 +1,58 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
#define RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_
#include "../rapidjson.h" #include "../stream.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
//! Custom strlen() which works on different character types. //! Custom strlen() which works on different character types.
/*! \tparam Ch Character type (e.g. char, wchar_t, short) /*! \tparam Ch Character type (e.g. char, wchar_t, short)
\param s Null-terminated input string. \param s Null-terminated input string.
\return Number of characters in the 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. \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
*/ */
template <typename Ch> template <typename Ch>
inline SizeType StrLen(const Ch* s) { inline SizeType StrLen(const Ch* s) {
const Ch* p = s; RAPIDJSON_ASSERT(s != 0);
while (*p) ++p; const Ch* p = s;
return SizeType(p - s); while (*p) ++p;
} return SizeType(p - s);
}
} // namespace internal
RAPIDJSON_NAMESPACE_END //! Returns number of code points in a encoded string.
template<typename Encoding>
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
RAPIDJSON_ASSERT(s != 0);
RAPIDJSON_ASSERT(outCount != 0);
GenericStringStream<Encoding> is(s);
const typename Encoding::Ch* end = s + length;
SizeType count = 0;
while (is.src_ < end) {
unsigned codepoint;
if (!Encoding::Decode(is, &codepoint))
return false;
count++;
}
*outCount = count;
return true;
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_

View file

@ -15,7 +15,6 @@
#ifndef RAPIDJSON_STRTOD_ #ifndef RAPIDJSON_STRTOD_
#define RAPIDJSON_STRTOD_ #define RAPIDJSON_STRTOD_
#include "../rapidjson.h"
#include "ieee754.h" #include "ieee754.h"
#include "biginteger.h" #include "biginteger.h"
#include "diyfp.h" #include "diyfp.h"
@ -143,7 +142,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
size_t remaining = length - i; size_t remaining = length - i;
const unsigned kUlpShift = 3; const unsigned kUlpShift = 3;
const unsigned kUlp = 1 << kUlpShift; const unsigned kUlp = 1 << kUlpShift;
int error = (remaining == 0) ? 0 : kUlp / 2; int64_t error = (remaining == 0) ? 0 : kUlp / 2;
DiyFp v(significand, 0); DiyFp v(significand, 0);
v = v.Normalize(); v = v.Normalize();

View file

@ -1,37 +1,46 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_SWAP_H_ #ifndef RAPIDJSON_INTERNAL_SWAP_H_
#define RAPIDJSON_INTERNAL_SWAP_H_ #define RAPIDJSON_INTERNAL_SWAP_H_
#include "../rapidjson.h" #include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN #if defined(__clang__)
namespace internal { RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat)
//! Custom swap() to avoid dependency on C++ <algorithm> header #endif
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
\note This has the same semantics as std::swap(). RAPIDJSON_NAMESPACE_BEGIN
*/ namespace internal {
template <typename T>
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { //! Custom swap() to avoid dependency on C++ <algorithm> header
T tmp = a; /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
a = b; \note This has the same semantics as std::swap().
b = tmp; */
} template <typename T>
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
} // namespace internal T tmp = a;
RAPIDJSON_NAMESPACE_END a = b;
b = tmp;
#endif // RAPIDJSON_INTERNAL_SWAP_H_ }
} // namespace internal
RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_INTERNAL_SWAP_H_

115
external/rapidjson/istreamwrapper.h vendored Normal file
View file

@ -0,0 +1,115 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
#define RAPIDJSON_ISTREAMWRAPPER_H_
#include "stream.h"
#include <iosfwd>
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
/*!
The classes can be wrapped including but not limited to:
- \c std::istringstream
- \c std::stringstream
- \c std::wistringstream
- \c std::wstringstream
- \c std::ifstream
- \c std::fstream
- \c std::wifstream
- \c std::wfstream
\tparam StreamType Class derived from \c std::basic_istream.
*/
template <typename StreamType>
class BasicIStreamWrapper {
public:
typedef typename StreamType::char_type Ch;
BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
Ch Peek() const {
typename StreamType::int_type c = stream_.peek();
return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
}
Ch Take() {
typename StreamType::int_type c = stream_.get();
if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
count_++;
return static_cast<Ch>(c);
}
else
return '\0';
}
// tellg() may return -1 when failed. So we count by ourself.
size_t Tell() const { return count_; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
int i;
bool hasError = false;
for (i = 0; i < 4; ++i) {
typename StreamType::int_type c = stream_.get();
if (c == StreamType::traits_type::eof()) {
hasError = true;
stream_.clear();
break;
}
peekBuffer_[i] = static_cast<Ch>(c);
}
for (--i; i >= 0; --i)
stream_.putback(peekBuffer_[i]);
return !hasError ? peekBuffer_ : 0;
}
private:
BasicIStreamWrapper(const BasicIStreamWrapper&);
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
StreamType& stream_;
size_t count_; //!< Number of characters read. Note:
mutable Ch peekBuffer_[4];
};
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ISTREAMWRAPPER_H_

View file

@ -15,7 +15,7 @@
#ifndef RAPIDJSON_MEMORYBUFFER_H_ #ifndef RAPIDJSON_MEMORYBUFFER_H_
#define RAPIDJSON_MEMORYBUFFER_H_ #define RAPIDJSON_MEMORYBUFFER_H_
#include "rapidjson.h" #include "stream.h"
#include "internal/stack.h" #include "internal/stack.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN

View file

@ -15,7 +15,7 @@
#ifndef RAPIDJSON_MEMORYSTREAM_H_ #ifndef RAPIDJSON_MEMORYSTREAM_H_
#define RAPIDJSON_MEMORYSTREAM_H_ #define RAPIDJSON_MEMORYSTREAM_H_
#include "rapidjson.h" #include "stream.h"
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
@ -42,8 +42,8 @@ struct MemoryStream {
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
Ch Peek() const { return (src_ == end_) ? '\0' : *src_; } Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
Ch Take() { return (src_ == end_) ? '\0' : *src_++; } Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - begin_); } size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }

81
external/rapidjson/ostreamwrapper.h vendored Normal file
View file

@ -0,0 +1,81 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_OSTREAMWRAPPER_H_
#define RAPIDJSON_OSTREAMWRAPPER_H_
#include "stream.h"
#include <iosfwd>
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
/*!
The classes can be wrapped including but not limited to:
- \c std::ostringstream
- \c std::stringstream
- \c std::wpstringstream
- \c std::wstringstream
- \c std::ifstream
- \c std::fstream
- \c std::wofstream
- \c std::wfstream
\tparam StreamType Class derived from \c std::basic_ostream.
*/
template <typename StreamType>
class BasicOStreamWrapper {
public:
typedef typename StreamType::char_type Ch;
BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
void Put(Ch c) {
stream_.put(c);
}
void Flush() {
stream_.flush();
}
// Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
char Take() { RAPIDJSON_ASSERT(false); return 0; }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
private:
BasicOStreamWrapper(const BasicOStreamWrapper&);
BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
StreamType& stream_;
};
typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_OSTREAMWRAPPER_H_

View file

@ -23,6 +23,11 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(switch-enum)
#endif #endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
@ -101,7 +106,7 @@ public:
//@{ //@{
//! Default constructor. //! Default constructor.
GenericPointer() : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
//! Constructor that parses a string or URI fragment representation. //! Constructor that parses a string or URI fragment representation.
/*! /*!
@ -160,7 +165,7 @@ public:
GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
//! Copy constructor. //! Copy constructor.
GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
*this = rhs; *this = rhs;
} }
@ -305,6 +310,9 @@ public:
//@} //@}
//! Get the allocator of this pointer.
Allocator& GetAllocator() { return *allocator_; }
//!@name Tokens //!@name Tokens
//@{ //@{
@ -457,9 +465,18 @@ public:
//! Query a value in a subtree. //! Query a value in a subtree.
/*! /*!
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
\param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
\return Pointer to the value if it can be resolved. Otherwise null. \return Pointer to the value if it can be resolved. Otherwise null.
\note
There are only 3 situations when a value cannot be resolved:
1. A value in the path is not an array nor object.
2. An object value does not contain the token.
3. A token is out of range of an array value.
Use unresolvedTokenIndex to retrieve the token index.
*/ */
ValueType* Get(ValueType& root) const { ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
RAPIDJSON_ASSERT(IsValid()); RAPIDJSON_ASSERT(IsValid());
ValueType* v = &root; ValueType* v = &root;
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
@ -468,18 +485,23 @@ public:
{ {
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length)); typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
if (m == v->MemberEnd()) if (m == v->MemberEnd())
return 0; break;
v = &m->value; v = &m->value;
} }
break; continue;
case kArrayType: case kArrayType:
if (t->index == kPointerInvalidIndex || t->index >= v->Size()) if (t->index == kPointerInvalidIndex || t->index >= v->Size())
return 0; break;
v = &((*v)[t->index]); v = &((*v)[t->index]);
break; continue;
default: default:
return 0; break;
} }
// Error: unresolved token
if (unresolvedTokenIndex)
*unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
return 0;
} }
return v; return v;
} }
@ -489,7 +511,9 @@ public:
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
\return Pointer to the value if it can be resolved. Otherwise null. \return Pointer to the value if it can be resolved. Otherwise null.
*/ */
const ValueType* Get(const ValueType& root) const { return Get(const_cast<ValueType&>(root)); } const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
}
//@} //@}
@ -743,8 +767,12 @@ private:
tokenCount_ = rhs.tokenCount_ + extraToken; tokenCount_ = rhs.tokenCount_ + extraToken;
tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_); nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); if (rhs.tokenCount_ > 0) {
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
}
if (nameBufferSize > 0) {
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
}
// Adjust pointers to name buffer // Adjust pointers to name buffer
std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
@ -968,11 +996,11 @@ private:
src_++; src_++;
Ch c = 0; Ch c = 0;
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
c <<= 4; c = static_cast<Ch>(c << 4);
Ch h = *src_; Ch h = *src_;
if (h >= '0' && h <= '9') c += h - '0'; if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');
else if (h >= 'A' && h <= 'F') c += h - 'A' + 10; else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);
else if (h >= 'a' && h <= 'f') c += h - 'a' + 10; else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);
else { else {
valid_ = false; valid_ = false;
return 0; return 0;
@ -1050,23 +1078,23 @@ typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, c
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
template <typename T> template <typename T>
typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) { typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
return pointer.Get(root); return pointer.Get(root, unresolvedTokenIndex);
} }
template <typename T> template <typename T>
const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer) { const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
return pointer.Get(root); return pointer.Get(root, unresolvedTokenIndex);
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N]) { typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
return GenericPointer<typename T::ValueType>(source, N - 1).Get(root); return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N]) { const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
return GenericPointer<typename T::ValueType>(source, N - 1).Get(root); return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -1323,4 +1351,8 @@ RAPIDJSON_NAMESPACE_END
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_POINTER_H_ #endif // RAPIDJSON_POINTER_H_

View file

@ -1,207 +1,261 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_PRETTYWRITER_H_ #ifndef RAPIDJSON_PRETTYWRITER_H_
#define RAPIDJSON_PRETTYWRITER_H_ #define RAPIDJSON_PRETTYWRITER_H_
#include "writer.h" #include "writer.h"
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
//! Writer with indentation and spacing. //! Combination of PrettyWriter format flags.
/*! /*! \see PrettyWriter::SetFormatOptions
\tparam OutputStream Type of ouptut os. */
\tparam SourceEncoding Encoding of source string. enum PrettyFormatOptions {
\tparam TargetEncoding Encoding of output stream. kFormatDefault = 0, //!< Default pretty formatting.
\tparam StackAllocator Type of allocator for allocating memory of stack. kFormatSingleLineArray = 1 //!< Format arrays on a single line.
*/ };
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> { //! Writer with indentation and spacing.
public: /*!
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base; \tparam OutputStream Type of ouptut os.
typedef typename Base::Ch Ch; \tparam SourceEncoding Encoding of source string.
\tparam TargetEncoding Encoding of output stream.
//! Constructor \tparam StackAllocator Type of allocator for allocating memory of stack.
/*! \param os Output stream. */
\param allocator User supplied allocator. If it is null, it will create a private one. template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
\param levelDepth Initial capacity of stack. class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
*/ public:
PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} typedef typename Base::Ch Ch;
//! Set custom indentation. //! Constructor
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). /*! \param os Output stream.
\param indentCharCount Number of indent characters for each indentation level. \param allocator User supplied allocator. If it is null, it will create a private one.
\note The default indentation is 4 spaces. \param levelDepth Initial capacity of stack.
*/ */
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
indentChar_ = indentChar;
indentCharCount_ = indentCharCount;
return *this; explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
} Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
/*! @name Implementation of Handler //! Set custom indentation.
\see Handler /*! \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.
*/
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } indentChar_ = indentChar;
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } indentCharCount_ = indentCharCount;
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } return *this;
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } }
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
//! Set pretty writer formatting options.
bool String(const Ch* str, SizeType length, bool copy = false) { /*! \param options Formatting options.
(void)copy; */
PrettyPrefix(kStringType); PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
return Base::WriteString(str, length); formatOptions_ = options;
} return *this;
}
#if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) { /*! @name Implementation of Handler
return String(str.data(), SizeType(str.size())); \see Handler
} */
#endif //@{
bool StartObject() { bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
PrettyPrefix(kObjectType); bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false); bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
return Base::WriteStartObject(); bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
} bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
bool EndObject(SizeType memberCount = 0) { bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
(void)memberCount; RAPIDJSON_ASSERT(str != 0);
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); (void)copy;
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); PrettyPrefix(kNumberType);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; return Base::WriteString(str, length);
}
if (!empty) {
Base::os_->Put('\n'); bool String(const Ch* str, SizeType length, bool copy = false) {
WriteIndent(); RAPIDJSON_ASSERT(str != 0);
} (void)copy;
bool ret = Base::WriteEndObject(); PrettyPrefix(kStringType);
(void)ret; return Base::WriteString(str, length);
RAPIDJSON_ASSERT(ret == true); }
if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush(); #if RAPIDJSON_HAS_STDSTRING
return true; bool String(const std::basic_string<Ch>& str) {
} return String(str.data(), SizeType(str.size()));
}
bool StartArray() { #endif
PrettyPrefix(kArrayType);
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true); bool StartObject() {
return Base::WriteStartArray(); PrettyPrefix(kObjectType);
} new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
return Base::WriteStartObject();
bool EndArray(SizeType memberCount = 0) { }
(void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
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 RAPIDJSON_HAS_STDSTRING
bool Key(const std::basic_string<Ch>& str) {
if (!empty) { return Key(str.data(), SizeType(str.size()));
Base::os_->Put('\n'); }
WriteIndent(); #endif
}
bool ret = Base::WriteEndArray(); bool EndObject(SizeType memberCount = 0) {
(void)ret; (void)memberCount;
RAPIDJSON_ASSERT(ret == true); RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
if (Base::level_stack_.Empty()) // end of json text RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
Base::os_->Flush(); bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
return true;
} if (!empty) {
Base::os_->Put('\n');
//@} WriteIndent();
}
/*! @name Convenience extensions */ bool ret = Base::WriteEndObject();
//@{ (void)ret;
RAPIDJSON_ASSERT(ret == true);
//! Simpler but slower overload. if (Base::level_stack_.Empty()) // end of json text
bool String(const Ch* str) { return String(str, internal::StrLen(str)); } Base::os_->Flush();
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } return true;
}
//@}
protected: bool StartArray() {
void PrettyPrefix(Type type) { PrettyPrefix(kArrayType);
(void)type; new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
if (Base::level_stack_.GetSize() != 0) { // this value is not at root return Base::WriteStartArray();
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>(); }
if (level->inArray) { bool EndArray(SizeType memberCount = 0) {
if (level->valueCount > 0) { (void)memberCount;
Base::os_->Put(','); // add comma if it is not the first element in array RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
Base::os_->Put('\n'); RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
} bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
else
Base::os_->Put('\n'); if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
WriteIndent(); Base::os_->Put('\n');
} WriteIndent();
else { // in object }
if (level->valueCount > 0) { bool ret = Base::WriteEndArray();
if (level->valueCount % 2 == 0) { (void)ret;
Base::os_->Put(','); RAPIDJSON_ASSERT(ret == true);
Base::os_->Put('\n'); if (Base::level_stack_.Empty()) // end of json text
} Base::os_->Flush();
else { return true;
Base::os_->Put(':'); }
Base::os_->Put(' ');
} //@}
}
else /*! @name Convenience extensions */
Base::os_->Put('\n'); //@{
if (level->valueCount % 2 == 0) //! Simpler but slower overload.
WriteIndent(); bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
} bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
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++;
} //! Write a raw JSON value.
else { /*!
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. For user to write a stringified JSON as a value.
Base::hasRoot_ = true;
} \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
} \param length Length of the json.
\param type Type of the root of json.
void WriteIndent() { \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; */
PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count); bool RawValue(const Ch* json, size_t length, Type type) {
} RAPIDJSON_ASSERT(json != 0);
PrettyPrefix(type);
Ch indentChar_; return Base::WriteRawValue(json, length);
unsigned indentCharCount_; }
private: protected:
// Prohibit copy constructor & assignment operator. void PrettyPrefix(Type type) {
PrettyWriter(const PrettyWriter&); (void)type;
PrettyWriter& operator=(const PrettyWriter&); if (Base::level_stack_.GetSize() != 0) { // this value is not at root
}; typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
RAPIDJSON_NAMESPACE_END if (level->inArray) {
if (level->valueCount > 0) {
#ifdef __GNUC__ Base::os_->Put(','); // add comma if it is not the first element in array
RAPIDJSON_DIAG_POP if (formatOptions_ & kFormatSingleLineArray)
#endif Base::os_->Put(' ');
}
#endif // RAPIDJSON_RAPIDJSON_H_
if (!(formatOptions_ & kFormatSingleLineArray)) {
Base::os_->Put('\n');
WriteIndent();
}
}
else { // in object
if (level->valueCount > 0) {
if (level->valueCount % 2 == 0) {
Base::os_->Put(',');
Base::os_->Put('\n');
}
else {
Base::os_->Put(':');
Base::os_->Put(' ');
}
}
else
Base::os_->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(!Base::hasRoot_); // Should only has one and only one root.
Base::hasRoot_ = true;
}
}
void WriteIndent() {
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
}
Ch indentChar_;
unsigned indentCharCount_;
PrettyFormatOptions formatOptions_;
private:
// Prohibit copy constructor & assignment operator.
PrettyWriter(const PrettyWriter&);
PrettyWriter& operator=(const PrettyWriter&);
};
RAPIDJSON_NAMESPACE_END
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_RAPIDJSON_H_

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

2007
external/rapidjson/schema.h vendored Normal file

File diff suppressed because it is too large Load diff

179
external/rapidjson/stream.h vendored Normal file
View file

@ -0,0 +1,179 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "rapidjson.h"
#ifndef RAPIDJSON_STREAM_H_
#define RAPIDJSON_STREAM_H_
#include "encodings.h"
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Stream
/*! \class rapidjson::Stream
\brief Concept for reading and writing characters.
For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
For write-only stream, only need to implement Put() and Flush().
\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);
//! Flush the buffer.
void Flush();
//! End the writing operation.
//! \param begin The begin write pointer returned by PutBegin().
//! \return Number of characters written.
size_t PutEnd(Ch* begin);
}
\endcode
*/
//! Provides additional information for stream.
/*!
By using traits pattern, this type provides a default configuration for stream.
For custom stream, this type can be specialized for other configuration.
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
*/
template<typename Stream>
struct StreamTraits {
//! Whether to make local copy of stream for optimization during parsing.
/*!
By default, for safety, streams do not use local copy optimization.
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
*/
enum { copyOptimization = 0 };
};
//! Reserve n characters for writing to a stream.
template<typename Stream>
inline void PutReserve(Stream& stream, size_t count) {
(void)stream;
(void)count;
}
//! Write character to a stream, presuming buffer is reserved.
template<typename Stream>
inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
stream.Put(c);
}
//! Put N copies of a character to a stream.
template<typename Stream, typename Ch>
inline void PutN(Stream& stream, Ch c, size_t n) {
PutReserve(stream, n);
for (size_t i = 0; i < n; i++)
PutUnsafe(stream, c);
}
///////////////////////////////////////////////////////////////////////////////
// StringStream
//! Read-only string stream.
/*! \note implements Stream concept
*/
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 static_cast<size_t>(src_ - head_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { 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.
};
template <typename Encoding>
struct StreamTraits<GenericStringStream<Encoding> > {
enum { copyOptimization = 1 };
};
//! String stream with UTF8 encoding.
typedef GenericStringStream<UTF8<> > StringStream;
///////////////////////////////////////////////////////////////////////////////
// InsituStringStream
//! A read-write string stream.
/*! This string stream is particularly designed for in-situ parsing.
\note implements Stream concept
*/
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 static_cast<size_t>(src_ - head_); }
// Write
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
Ch* PutBegin() { return dst_ = src_; }
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
void Flush() {}
Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
void Pop(size_t count) { dst_ -= count; }
Ch* src_;
Ch* dst_;
Ch* head_;
};
template <typename Encoding>
struct StreamTraits<GenericInsituStringStream<Encoding> > {
enum { copyOptimization = 1 };
};
//! Insitu string stream with UTF8 encoding.
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STREAM_H_

View file

@ -1,93 +1,117 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at // in compliance with the License. You may obtain a copy of the License at
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRINGBUFFER_H_ #ifndef RAPIDJSON_STRINGBUFFER_H_
#define RAPIDJSON_STRINGBUFFER_H_ #define RAPIDJSON_STRINGBUFFER_H_
#include "rapidjson.h" #include "stream.h"
#include "internal/stack.h"
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#include <utility> // std::move #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#endif #include <utility> // std::move
#endif
#include "internal/stack.h"
#include "internal/stack.h"
RAPIDJSON_NAMESPACE_BEGIN
#if defined(__clang__)
//! Represents an in-memory output stream. RAPIDJSON_DIAG_PUSH
/*! RAPIDJSON_DIAG_OFF(c++98-compat)
\tparam Encoding Encoding of the stream. #endif
\tparam Allocator type for allocating memory buffer.
\note implements Stream concept RAPIDJSON_NAMESPACE_BEGIN
*/
template <typename Encoding, typename Allocator = CrtAllocator> //! Represents an in-memory output stream.
class GenericStringBuffer { /*!
public: \tparam Encoding Encoding of the stream.
typedef typename Encoding::Ch Ch; \tparam Allocator type for allocating memory buffer.
\note implements Stream concept
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} */
template <typename Encoding, typename Allocator = CrtAllocator>
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS class GenericStringBuffer {
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} public:
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { typedef typename Encoding::Ch Ch;
if (&rhs != this)
stack_ = std::move(rhs.stack_); GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
return *this;
} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#endif GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
void Put(Ch c) { *stack_.template Push<Ch>() = c; } if (&rhs != this)
void Flush() {} stack_ = std::move(rhs.stack_);
return *this;
void Clear() { stack_.Clear(); } }
void ShrinkToFit() { #endif
// Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0'; void Put(Ch c) { *stack_.template Push<Ch>() = c; }
stack_.ShrinkToFit(); void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
stack_.template Pop<Ch>(1); void Flush() {}
}
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); } void Clear() { stack_.Clear(); }
void Pop(size_t count) { stack_.template Pop<Ch>(count); } void ShrinkToFit() {
// Push and pop a null terminator. This is safe.
const Ch* GetString() const { *stack_.template Push<Ch>() = '\0';
// Push and pop a null terminator. This is safe. stack_.ShrinkToFit();
*stack_.template Push<Ch>() = '\0'; stack_.template Pop<Ch>(1);
stack_.template Pop<Ch>(1); }
return stack_.template Bottom<Ch>(); void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
} Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
size_t GetSize() const { return stack_.GetSize(); } void Pop(size_t count) { stack_.template Pop<Ch>(count); }
static const size_t kDefaultCapacity = 256; const Ch* GetString() const {
mutable internal::Stack<Allocator> stack_; // Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0';
private: stack_.template Pop<Ch>(1);
// Prohibit copy constructor & assignment operator.
GenericStringBuffer(const GenericStringBuffer&); return stack_.template Bottom<Ch>();
GenericStringBuffer& operator=(const GenericStringBuffer&); }
};
size_t GetSize() const { return stack_.GetSize(); }
//! String buffer with UTF8 encoding
typedef GenericStringBuffer<UTF8<> > StringBuffer; static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_;
//! Implement specialized version of PutN() with memset() for better performance.
template<> private:
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) { // Prohibit copy constructor & assignment operator.
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c)); GenericStringBuffer(const GenericStringBuffer&);
} GenericStringBuffer& operator=(const GenericStringBuffer&);
};
RAPIDJSON_NAMESPACE_END
//! String buffer with UTF8 encoding
#endif // RAPIDJSON_STRINGBUFFER_H_ typedef GenericStringBuffer<UTF8<> > StringBuffer;
template<typename Encoding, typename Allocator>
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
stream.Reserve(count);
}
template<typename Encoding, typename Allocator>
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
stream.PutUnsafe(c);
}
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
}
RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_STRINGBUFFER_H_

File diff suppressed because it is too large Load diff