Merge branch 'master' into kimkulling/remode_default_destructor_from_cppp
commit
1fd3ca860e
|
@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
|
|||
IF(ASSIMP_HUNTER_ENABLED)
|
||||
include("cmake-modules/HunterGate.cmake")
|
||||
HunterGate(
|
||||
URL "https://github.com/cpp-pm/hunter/archive/v0.25.3.tar.gz"
|
||||
SHA1 "3319fe6a3b08090df7df98dee75134d68e2ef5a3"
|
||||
URL "https://github.com/cpp-pm/hunter/archive/v0.25.5.tar.gz"
|
||||
SHA1 "a20151e4c0740ee7d0f9994476856d813cdead29"
|
||||
)
|
||||
add_definitions(-DASSIMP_USE_HUNTER)
|
||||
ENDIF()
|
||||
|
@ -563,9 +563,9 @@ SET ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER OFF CACHE BOOL
|
|||
)
|
||||
|
||||
IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
||||
IF ( MSVC )
|
||||
SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/includes")
|
||||
|
||||
IF (WIN32)
|
||||
# pick the correct prebuilt library
|
||||
IF(MSVC143)
|
||||
SET(C4D_LIB_POSTFIX "_2022")
|
||||
|
@ -583,7 +583,7 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
|||
SET(C4D_LIB_POSTFIX "_2010")
|
||||
ELSE()
|
||||
MESSAGE( FATAL_ERROR
|
||||
"C4D is currently only supported with MSVC 10, 11, 12, 14, 14.2, 14.3"
|
||||
"C4D for Windows is currently only supported with MSVC 10, 11, 12, 14, 14.2, 14.3"
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
|
@ -601,9 +601,20 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
|
|||
# winsock and winmm are necessary (and undocumented) dependencies of Cineware SDK because
|
||||
# it can be used to communicate with a running Cinema 4D instance
|
||||
SET(C4D_EXTRA_LIBRARIES WSock32.lib Winmm.lib)
|
||||
ELSEIF (APPLE)
|
||||
SET(C4D_LIB_BASE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Cineware/libraries/osx")
|
||||
|
||||
SET(C4D_DEBUG_LIBRARIES
|
||||
"${C4D_LIB_BASE_PATH}/debug/libcinewarelib.a"
|
||||
"${C4D_LIB_BASE_PATH}/debug/libjpeglib.a"
|
||||
)
|
||||
SET(C4D_RELEASE_LIBRARIES
|
||||
"${C4D_LIB_BASE_PATH}/release/libcinewarelib.a"
|
||||
"${C4D_LIB_BASE_PATH}/release/libjpeglib.a"
|
||||
)
|
||||
ELSE ()
|
||||
MESSAGE( FATAL_ERROR
|
||||
"C4D is currently only available on Windows with Cineware SDK installed in contrib/Cineware"
|
||||
"C4D is currently only available on Windows and macOS with Cineware SDK installed in contrib/Cineware"
|
||||
)
|
||||
ENDIF ()
|
||||
ELSE ()
|
||||
|
|
|
@ -46,10 +46,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
// no #ifdefing here, Cinema4D support is carried out in a branch of assimp
|
||||
// where it is turned on in the CMake settings.
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# error C4D support is currently MSVC only
|
||||
#endif
|
||||
|
||||
#include "C4DImporter.h"
|
||||
#include <memory>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
@ -111,7 +107,7 @@ C4DImporter::C4DImporter() = default;
|
|||
C4DImporter::~C4DImporter() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool C4DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const {
|
||||
bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
|
||||
const std::string& extension = GetExtension(pFile);
|
||||
if (extension == "c4d") {
|
||||
return true;
|
||||
|
@ -305,7 +301,7 @@ void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) {
|
|||
|
||||
// based on Cineware sample code
|
||||
while (object) {
|
||||
const LONG type = object->GetType();
|
||||
const Int32 type = object->GetType();
|
||||
const Matrix& ml = object->GetMl();
|
||||
|
||||
aiNode* const nd = new aiNode();
|
||||
|
@ -368,8 +364,8 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) {
|
|||
PolygonObject* const polyObject = dynamic_cast<PolygonObject*>(object);
|
||||
ai_assert(polyObject != nullptr);
|
||||
|
||||
const LONG pointCount = polyObject->GetPointCount();
|
||||
const LONG polyCount = polyObject->GetPolygonCount();
|
||||
const Int32 pointCount = polyObject->GetPointCount();
|
||||
const Int32 polyCount = polyObject->GetPolygonCount();
|
||||
if(!polyObject || !pointCount) {
|
||||
LogWarn("ignoring mesh with zero vertices or faces");
|
||||
return nullptr;
|
||||
|
@ -391,7 +387,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) {
|
|||
unsigned int vcount = 0;
|
||||
|
||||
// first count vertices
|
||||
for (LONG i = 0; i < polyCount; i++)
|
||||
for (Int32 i = 0; i < polyCount; i++)
|
||||
{
|
||||
vcount += 3;
|
||||
|
||||
|
@ -434,7 +430,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) {
|
|||
}
|
||||
|
||||
// copy vertices and extra channels over and populate faces
|
||||
for (LONG i = 0; i < polyCount; ++i, ++face) {
|
||||
for (Int32 i = 0; i < polyCount; ++i, ++face) {
|
||||
ai_assert(polys[i].a < pointCount && polys[i].a >= 0);
|
||||
const Vector& pointA = points[polys[i].a];
|
||||
verts->x = pointA.x;
|
||||
|
@ -511,7 +507,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) {
|
|||
if (tangents_src) {
|
||||
|
||||
for(unsigned int k = 0; k < face->mNumIndices; ++k) {
|
||||
LONG l;
|
||||
Int32 l;
|
||||
switch(k) {
|
||||
case 0:
|
||||
l = polys[i].a;
|
||||
|
|
|
@ -78,6 +78,8 @@ namespace Assimp {
|
|||
// -------------------------------------------------------------------------------------------
|
||||
class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter> {
|
||||
public:
|
||||
C4DImporter();
|
||||
~C4DImporter() override;
|
||||
bool CanRead( const std::string& pFile, IOSystem*, bool checkSig) const override;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace HMP {
|
|||
#include <assimp/Compiler/pushpack1.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// to make it easier for us, we test the magic word against both "endianesses"
|
||||
// to make it easier for us, we test the magic word against both "endiannesses"
|
||||
#define AI_HMP_MAGIC_NUMBER_BE_4 AI_MAKE_MAGIC("HMP4")
|
||||
#define AI_HMP_MAGIC_NUMBER_LE_4 AI_MAKE_MAGIC("4PMH")
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace MD2 {
|
||||
|
||||
// to make it easier for us, we test the magic word against both "endianesses"
|
||||
// to make it easier for us, we test the magic word against both "endiannesses"
|
||||
#define AI_MD2_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDP2")
|
||||
#define AI_MD2_MAGIC_NUMBER_LE AI_MAKE_MAGIC("2PDI")
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace MD3 {
|
||||
|
||||
// to make it easier for us, we test the magic word against both "endianesses"
|
||||
// to make it easier for us, we test the magic word against both "endiannesses"
|
||||
#define AI_MD3_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDP3")
|
||||
#define AI_MD3_MAGIC_NUMBER_LE AI_MAKE_MAGIC("3PDI")
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ http://themdcfile.planetwolfenstein.gamespy.com/MDC_File_Format.pdf
|
|||
namespace Assimp {
|
||||
namespace MDC {
|
||||
|
||||
// to make it easier for us, we test the magic word against both "endianesses"
|
||||
// to make it easier for us, we test the magic word against both "endiannesses"
|
||||
#define AI_MDC_MAGIC_NUMBER_BE AI_MAKE_MAGIC("CPDI")
|
||||
#define AI_MDC_MAGIC_NUMBER_LE AI_MAKE_MAGIC("IDPC")
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace Assimp {
|
|||
namespace MDL {
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// to make it easier for us, we test the magic word against both "endianesses"
|
||||
// to make it easier for us, we test the magic word against both "endiannesses"
|
||||
|
||||
// magic bytes used in Quake 1 MDL meshes
|
||||
#define AI_MDL_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDPO")
|
||||
|
|
|
@ -16,6 +16,14 @@
|
|||
#define RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/meta.h"
|
||||
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -89,7 +97,14 @@ public:
|
|||
}
|
||||
return RAPIDJSON_REALLOC(originalPtr, newSize);
|
||||
}
|
||||
static void Free(void *ptr) { RAPIDJSON_FREE(ptr); }
|
||||
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
|
||||
|
||||
bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -113,16 +128,64 @@ public:
|
|||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
struct SharedData {
|
||||
ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
|
||||
size_t refcount;
|
||||
bool ownBuffer;
|
||||
};
|
||||
|
||||
static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
|
||||
static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
|
||||
|
||||
static inline ChunkHeader *GetChunkHead(SharedData *shared)
|
||||
{
|
||||
return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
|
||||
}
|
||||
static inline uint8_t *GetChunkBuffer(SharedData *shared)
|
||||
{
|
||||
return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
|
||||
}
|
||||
|
||||
static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
|
||||
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
explicit
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
chunk_capacity_(chunkSize),
|
||||
baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
|
||||
shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
|
||||
{
|
||||
RAPIDJSON_ASSERT(baseAllocator_ != 0);
|
||||
RAPIDJSON_ASSERT(shared_ != 0);
|
||||
if (baseAllocator) {
|
||||
shared_->ownBaseAllocator = 0;
|
||||
}
|
||||
else {
|
||||
shared_->ownBaseAllocator = baseAllocator_;
|
||||
}
|
||||
shared_->chunkHead = GetChunkHead(shared_);
|
||||
shared_->chunkHead->capacity = 0;
|
||||
shared_->chunkHead->size = 0;
|
||||
shared_->chunkHead->next = 0;
|
||||
shared_->ownBuffer = true;
|
||||
shared_->refcount = 1;
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
|
@ -136,41 +199,101 @@ public:
|
|||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
chunk_capacity_(chunkSize),
|
||||
baseAllocator_(baseAllocator),
|
||||
shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
|
||||
shared_->chunkHead = GetChunkHead(shared_);
|
||||
shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
|
||||
shared_->chunkHead->size = 0;
|
||||
shared_->chunkHead->next = 0;
|
||||
shared_->ownBaseAllocator = 0;
|
||||
shared_->ownBuffer = false;
|
||||
shared_->refcount = 1;
|
||||
}
|
||||
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT :
|
||||
chunk_capacity_(rhs.chunk_capacity_),
|
||||
baseAllocator_(rhs.baseAllocator_),
|
||||
shared_(rhs.shared_)
|
||||
{
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
|
||||
++shared_->refcount;
|
||||
}
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
|
||||
++rhs.shared_->refcount;
|
||||
this->~MemoryPoolAllocator();
|
||||
baseAllocator_ = rhs.baseAllocator_;
|
||||
chunk_capacity_ = rhs.chunk_capacity_;
|
||||
shared_ = rhs.shared_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT :
|
||||
chunk_capacity_(rhs.chunk_capacity_),
|
||||
baseAllocator_(rhs.baseAllocator_),
|
||||
shared_(rhs.shared_)
|
||||
{
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
|
||||
rhs.shared_ = 0;
|
||||
}
|
||||
MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
|
||||
this->~MemoryPoolAllocator();
|
||||
baseAllocator_ = rhs.baseAllocator_;
|
||||
chunk_capacity_ = rhs.chunk_capacity_;
|
||||
shared_ = rhs.shared_;
|
||||
rhs.shared_ = 0;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT {
|
||||
if (!shared_) {
|
||||
// do nothing if moved
|
||||
return;
|
||||
}
|
||||
if (shared_->refcount > 1) {
|
||||
--shared_->refcount;
|
||||
return;
|
||||
}
|
||||
Clear();
|
||||
RAPIDJSON_DELETE(ownBaseAllocator_);
|
||||
BaseAllocator *a = shared_->ownBaseAllocator;
|
||||
if (shared_->ownBuffer) {
|
||||
baseAllocator_->Free(shared_);
|
||||
}
|
||||
RAPIDJSON_DELETE(a);
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
//! Deallocates all memory chunks, excluding the first/user one.
|
||||
void Clear() RAPIDJSON_NOEXCEPT {
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
|
||||
for (;;) {
|
||||
ChunkHeader* c = shared_->chunkHead;
|
||||
if (!c->next) {
|
||||
break;
|
||||
}
|
||||
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||
chunkHead_->size = 0; // Clear user buffer
|
||||
shared_->chunkHead = c->next;
|
||||
baseAllocator_->Free(c);
|
||||
}
|
||||
shared_->chunkHead->size = 0;
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() const {
|
||||
size_t Capacity() const RAPIDJSON_NOEXCEPT {
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
@ -178,25 +301,35 @@ public:
|
|||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() const {
|
||||
size_t Size() const RAPIDJSON_NOEXCEPT {
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Whether the allocator is shared.
|
||||
/*! \return true or false.
|
||||
*/
|
||||
bool Shared() const RAPIDJSON_NOEXCEPT {
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
|
||||
return shared_->refcount > 1;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||
if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity))
|
||||
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 = GetChunkBuffer(shared_) + shared_->chunkHead->size;
|
||||
shared_->chunkHead->size += size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -205,6 +338,7 @@ public:
|
|||
if (originalPtr == 0)
|
||||
return Malloc(newSize);
|
||||
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
|
||||
if (newSize == 0)
|
||||
return NULL;
|
||||
|
||||
|
@ -216,10 +350,10 @@ public:
|
|||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||
if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
chunkHead_->size += increment;
|
||||
if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) {
|
||||
shared_->chunkHead->size += increment;
|
||||
return originalPtr;
|
||||
}
|
||||
}
|
||||
|
@ -235,50 +369,325 @@ public:
|
|||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing
|
||||
|
||||
//! Compare (equality) with another MemoryPoolAllocator
|
||||
bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
|
||||
return shared_ == rhs.shared_;
|
||||
}
|
||||
//! Compare (inequality) with another MemoryPoolAllocator
|
||||
bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
//! Copy constructor is not permitted.
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy assignment operator is not permitted.
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
\return true if success.
|
||||
*/
|
||||
bool AddChunk(size_t capacity) {
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
|
||||
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
|
||||
shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
|
||||
if (ChunkHeader* chunk = static_cast<ChunkHeader*>(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) {
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
chunk->next = shared_->chunkHead;
|
||||
shared_->chunkHead = chunk;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
|
||||
static inline void* AlignBuffer(void* buf, size_t &size)
|
||||
{
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(buf != 0);
|
||||
const uintptr_t mask = sizeof(void*) - 1;
|
||||
const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf);
|
||||
if (RAPIDJSON_UNLIKELY(ubuf & mask)) {
|
||||
const uintptr_t abuf = (ubuf + mask) & ~mask;
|
||||
RAPIDJSON_ASSERT(size >= abuf - ubuf);
|
||||
buf = reinterpret_cast<void*>(abuf);
|
||||
size -= abuf - ubuf;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
SharedData *shared_; //!< The shared data of the allocator
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
template<typename, typename = void>
|
||||
struct IsRefCounted :
|
||||
public FalseType
|
||||
{ };
|
||||
template<typename T>
|
||||
struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> :
|
||||
public TrueType
|
||||
{ };
|
||||
}
|
||||
|
||||
template<typename T, typename A>
|
||||
inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
|
||||
{
|
||||
RAPIDJSON_NOEXCEPT_ASSERT(old_n <= (std::numeric_limits<size_t>::max)() / sizeof(T) && new_n <= (std::numeric_limits<size_t>::max)() / sizeof(T));
|
||||
return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
|
||||
}
|
||||
|
||||
template<typename T, typename A>
|
||||
inline T *Malloc(A& a, size_t n = 1)
|
||||
{
|
||||
return Realloc<T, A>(a, NULL, 0, n);
|
||||
}
|
||||
|
||||
template<typename T, typename A>
|
||||
inline void Free(A& a, T *p, size_t n = 1)
|
||||
{
|
||||
static_cast<void>(Realloc<T, A>(a, p, n, 0));
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
|
||||
#endif
|
||||
|
||||
template <typename T, typename BaseAllocator = CrtAllocator>
|
||||
class StdAllocator :
|
||||
public std::allocator<T>
|
||||
{
|
||||
typedef std::allocator<T> allocator_type;
|
||||
#if RAPIDJSON_HAS_CXX11
|
||||
typedef std::allocator_traits<allocator_type> traits_type;
|
||||
#else
|
||||
typedef allocator_type traits_type;
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef BaseAllocator BaseAllocatorType;
|
||||
|
||||
StdAllocator() RAPIDJSON_NOEXCEPT :
|
||||
allocator_type(),
|
||||
baseAllocator_()
|
||||
{ }
|
||||
|
||||
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
|
||||
allocator_type(rhs),
|
||||
baseAllocator_(rhs.baseAllocator_)
|
||||
{ }
|
||||
|
||||
template<typename U>
|
||||
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
|
||||
allocator_type(rhs),
|
||||
baseAllocator_(rhs.baseAllocator_)
|
||||
{ }
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT :
|
||||
allocator_type(std::move(rhs)),
|
||||
baseAllocator_(std::move(rhs.baseAllocator_))
|
||||
{ }
|
||||
#endif
|
||||
#if RAPIDJSON_HAS_CXX11
|
||||
using propagate_on_container_move_assignment = std::true_type;
|
||||
using propagate_on_container_swap = std::true_type;
|
||||
#endif
|
||||
|
||||
/* implicit */
|
||||
StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
|
||||
allocator_type(),
|
||||
baseAllocator_(baseAllocator)
|
||||
{ }
|
||||
|
||||
~StdAllocator() RAPIDJSON_NOEXCEPT
|
||||
{ }
|
||||
|
||||
template<typename U>
|
||||
struct rebind {
|
||||
typedef StdAllocator<U, BaseAllocator> other;
|
||||
};
|
||||
|
||||
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.
|
||||
typedef typename traits_type::size_type size_type;
|
||||
typedef typename traits_type::difference_type difference_type;
|
||||
|
||||
typedef typename traits_type::value_type value_type;
|
||||
typedef typename traits_type::pointer pointer;
|
||||
typedef typename traits_type::const_pointer const_pointer;
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11
|
||||
|
||||
typedef typename std::add_lvalue_reference<value_type>::type &reference;
|
||||
typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type &const_reference;
|
||||
|
||||
pointer address(reference r) const RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
return std::addressof(r);
|
||||
}
|
||||
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
return std::addressof(r);
|
||||
}
|
||||
|
||||
size_type max_size() const RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
return traits_type::max_size(*this);
|
||||
}
|
||||
|
||||
template <typename ...Args>
|
||||
void construct(pointer p, Args&&... args)
|
||||
{
|
||||
traits_type::construct(*this, p, std::forward<Args>(args)...);
|
||||
}
|
||||
void destroy(pointer p)
|
||||
{
|
||||
traits_type::destroy(*this, p);
|
||||
}
|
||||
|
||||
#else // !RAPIDJSON_HAS_CXX11
|
||||
|
||||
typedef typename allocator_type::reference reference;
|
||||
typedef typename allocator_type::const_reference const_reference;
|
||||
|
||||
pointer address(reference r) const RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
return allocator_type::address(r);
|
||||
}
|
||||
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
return allocator_type::address(r);
|
||||
}
|
||||
|
||||
size_type max_size() const RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
return allocator_type::max_size();
|
||||
}
|
||||
|
||||
void construct(pointer p, const_reference r)
|
||||
{
|
||||
allocator_type::construct(p, r);
|
||||
}
|
||||
void destroy(pointer p)
|
||||
{
|
||||
allocator_type::destroy(p);
|
||||
}
|
||||
|
||||
#endif // !RAPIDJSON_HAS_CXX11
|
||||
|
||||
template <typename U>
|
||||
U* allocate(size_type n = 1, const void* = 0)
|
||||
{
|
||||
return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
|
||||
}
|
||||
template <typename U>
|
||||
void deallocate(U* p, size_type n = 1)
|
||||
{
|
||||
RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
|
||||
}
|
||||
|
||||
pointer allocate(size_type n = 1, const void* = 0)
|
||||
{
|
||||
return allocate<value_type>(n);
|
||||
}
|
||||
void deallocate(pointer p, size_type n = 1)
|
||||
{
|
||||
deallocate<value_type>(p, n);
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11
|
||||
using is_always_equal = std::is_empty<BaseAllocator>;
|
||||
#endif
|
||||
|
||||
template<typename U>
|
||||
bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
return baseAllocator_ == rhs.baseAllocator_;
|
||||
}
|
||||
template<typename U>
|
||||
bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
//! rapidjson Allocator concept
|
||||
static const bool kNeedFree = BaseAllocator::kNeedFree;
|
||||
static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::Value;
|
||||
void* Malloc(size_t size)
|
||||
{
|
||||
return baseAllocator_.Malloc(size);
|
||||
}
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
|
||||
{
|
||||
return baseAllocator_.Realloc(originalPtr, originalSize, newSize);
|
||||
}
|
||||
static void Free(void *ptr) RAPIDJSON_NOEXCEPT
|
||||
{
|
||||
BaseAllocator::Free(ptr);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename>
|
||||
friend class StdAllocator; // access to StdAllocator<!T>.*
|
||||
|
||||
BaseAllocator baseAllocator_;
|
||||
};
|
||||
|
||||
#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
|
||||
template <typename BaseAllocator>
|
||||
class StdAllocator<void, BaseAllocator> :
|
||||
public std::allocator<void>
|
||||
{
|
||||
typedef std::allocator<void> allocator_type;
|
||||
|
||||
public:
|
||||
typedef BaseAllocator BaseAllocatorType;
|
||||
|
||||
StdAllocator() RAPIDJSON_NOEXCEPT :
|
||||
allocator_type(),
|
||||
baseAllocator_()
|
||||
{ }
|
||||
|
||||
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
|
||||
allocator_type(rhs),
|
||||
baseAllocator_(rhs.baseAllocator_)
|
||||
{ }
|
||||
|
||||
template<typename U>
|
||||
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
|
||||
allocator_type(rhs),
|
||||
baseAllocator_(rhs.baseAllocator_)
|
||||
{ }
|
||||
|
||||
/* implicit */
|
||||
StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
|
||||
allocator_type(),
|
||||
baseAllocator_(baseAllocator)
|
||||
{ }
|
||||
|
||||
~StdAllocator() RAPIDJSON_NOEXCEPT
|
||||
{ }
|
||||
|
||||
template<typename U>
|
||||
struct rebind {
|
||||
typedef StdAllocator<U, BaseAllocator> other;
|
||||
};
|
||||
|
||||
typedef typename allocator_type::value_type value_type;
|
||||
|
||||
private:
|
||||
template <typename, typename>
|
||||
friend class StdAllocator; // access to StdAllocator<!T>.*
|
||||
|
||||
BaseAllocator baseAllocator_;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
|
|
|
@ -42,12 +42,21 @@ RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible lo
|
|||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif // __GNUC__
|
||||
|
||||
#ifdef GetObject
|
||||
// see https://github.com/Tencent/rapidjson/issues/1448
|
||||
// a former included windows.h might have defined a macro called GetObject, which affects
|
||||
// GetObject defined here. This ensures the macro does not get applied
|
||||
#pragma push_macro("GetObject")
|
||||
#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
|
||||
#undef GetObject
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
|
||||
#include <iterator> // std::random_access_iterator_tag
|
||||
#endif
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#include <utility> // std::move
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
#include <map> // std::multimap
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
@ -66,7 +75,7 @@ class GenericDocument;
|
|||
User can define this to use CrtAllocator or MemoryPoolAllocator.
|
||||
*/
|
||||
#ifndef RAPIDJSON_DEFAULT_ALLOCATOR
|
||||
#define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator<CrtAllocator>
|
||||
#define RAPIDJSON_DEFAULT_ALLOCATOR ::RAPIDJSON_NAMESPACE::MemoryPoolAllocator<::RAPIDJSON_NAMESPACE::CrtAllocator>
|
||||
#endif
|
||||
|
||||
/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR
|
||||
|
@ -76,7 +85,7 @@ class GenericDocument;
|
|||
User can define this to use CrtAllocator or MemoryPoolAllocator.
|
||||
*/
|
||||
#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR
|
||||
#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator
|
||||
#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR ::RAPIDJSON_NAMESPACE::CrtAllocator
|
||||
#endif
|
||||
|
||||
/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
|
||||
|
@ -732,18 +741,8 @@ public:
|
|||
template <typename SourceAllocator>
|
||||
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
|
||||
switch (rhs.GetType()) {
|
||||
case kObjectType: {
|
||||
SizeType count = rhs.data_.o.size;
|
||||
Member* lm = reinterpret_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
|
||||
const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
|
||||
for (SizeType i = 0; i < count; i++) {
|
||||
new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
|
||||
new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
|
||||
}
|
||||
data_.f.flags = kObjectFlag;
|
||||
data_.o.size = data_.o.capacity = count;
|
||||
SetMembersPointer(lm);
|
||||
}
|
||||
case kObjectType:
|
||||
DoCopyMembers(rhs, allocator, copyConstStrings);
|
||||
break;
|
||||
case kArrayType: {
|
||||
SizeType count = rhs.data_.a.size;
|
||||
|
@ -879,25 +878,30 @@ public:
|
|||
/*! Need to destruct elements of array, members of object, or copy-string.
|
||||
*/
|
||||
~GenericValue() {
|
||||
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
|
||||
// With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release
|
||||
// their Allocator if it's refcounted (e.g. MemoryPoolAllocator).
|
||||
if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 &&
|
||||
internal::IsRefCounted<Allocator>::Value)) {
|
||||
switch(data_.f.flags) {
|
||||
case kArrayFlag:
|
||||
{
|
||||
GenericValue* e = GetElementsPointer();
|
||||
for (GenericValue* v = e; v != e + data_.a.size; ++v)
|
||||
v->~GenericValue();
|
||||
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
|
||||
Allocator::Free(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kObjectFlag:
|
||||
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
|
||||
m->~Member();
|
||||
Allocator::Free(GetMembersPointer());
|
||||
DoFreeMembers();
|
||||
break;
|
||||
|
||||
case kCopyStringFlag:
|
||||
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
|
||||
Allocator::Free(const_cast<Ch*>(GetStringPointer()));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -916,8 +920,13 @@ public:
|
|||
*/
|
||||
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
|
||||
if (RAPIDJSON_LIKELY(this != &rhs)) {
|
||||
// Can't destroy "this" before assigning "rhs", otherwise "rhs"
|
||||
// could be used after free if it's an sub-Value of "this",
|
||||
// hence the temporary danse.
|
||||
GenericValue temp;
|
||||
temp.RawAssign(rhs);
|
||||
this->~GenericValue();
|
||||
RawAssign(rhs);
|
||||
RawAssign(temp);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -1024,7 +1033,7 @@ public:
|
|||
return false;
|
||||
for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
|
||||
typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
|
||||
if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
|
||||
if (rhsMemberItr == rhs.MemberEnd() || (!(lhsMemberItr->value == rhsMemberItr->value)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1033,7 +1042,7 @@ public:
|
|||
if (data_.a.size != rhs.data_.a.size)
|
||||
return false;
|
||||
for (SizeType i = 0; i < data_.a.size; i++)
|
||||
if ((*this)[i] != rhs[i])
|
||||
if (!((*this)[i] == rhs[i]))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
|
@ -1069,6 +1078,7 @@ public:
|
|||
*/
|
||||
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
|
||||
|
||||
#ifndef __cpp_impl_three_way_comparison
|
||||
//! Not-equal-to operator
|
||||
/*! \return !(*this == rhs)
|
||||
*/
|
||||
|
@ -1093,6 +1103,7 @@ public:
|
|||
*/
|
||||
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
|
||||
//@}
|
||||
#endif
|
||||
|
||||
//!@name Type
|
||||
//@{
|
||||
|
@ -1219,13 +1230,28 @@ public:
|
|||
else {
|
||||
RAPIDJSON_ASSERT(false); // see above note
|
||||
|
||||
// This will generate -Wexit-time-destructors in clang
|
||||
// static GenericValue NullValue;
|
||||
// return NullValue;
|
||||
|
||||
// Use static buffer and placement-new to prevent destruction
|
||||
static char buffer[sizeof(GenericValue)];
|
||||
#if RAPIDJSON_HAS_CXX11
|
||||
// Use thread-local storage to prevent races between threads.
|
||||
// Use static buffer and placement-new to prevent destruction, with
|
||||
// alignas() to ensure proper alignment.
|
||||
alignas(GenericValue) thread_local static char buffer[sizeof(GenericValue)];
|
||||
return *new (buffer) GenericValue();
|
||||
#elif defined(_MSC_VER) && _MSC_VER < 1900
|
||||
// There's no way to solve both thread locality and proper alignment
|
||||
// simultaneously.
|
||||
__declspec(thread) static char buffer[sizeof(GenericValue)];
|
||||
return *new (buffer) GenericValue();
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
// This will generate -Wexit-time-destructors in clang, but that's
|
||||
// better than having under-alignment.
|
||||
__thread static GenericValue buffer;
|
||||
return buffer;
|
||||
#else
|
||||
// Don't know what compiler this is, so don't know how to ensure
|
||||
// thread-locality.
|
||||
static GenericValue buffer;
|
||||
return buffer;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
template <typename SourceAllocator>
|
||||
|
@ -1258,10 +1284,7 @@ public:
|
|||
*/
|
||||
GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
if (newCapacity > data_.o.capacity) {
|
||||
SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));
|
||||
data_.o.capacity = newCapacity;
|
||||
}
|
||||
DoReserveMembers(newCapacity, allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1335,11 +1358,7 @@ public:
|
|||
MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
RAPIDJSON_ASSERT(name.IsString());
|
||||
MemberIterator member = MemberBegin();
|
||||
for ( ; member != MemberEnd(); ++member)
|
||||
if (name.StringEqual(member->name))
|
||||
break;
|
||||
return member;
|
||||
return DoFindMember(name);
|
||||
}
|
||||
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||
|
||||
|
@ -1368,14 +1387,7 @@ public:
|
|||
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
RAPIDJSON_ASSERT(name.IsString());
|
||||
|
||||
ObjectData& o = data_.o;
|
||||
if (o.size >= o.capacity)
|
||||
MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
|
||||
Member* members = GetMembersPointer();
|
||||
members[o.size].name.RawAssign(name);
|
||||
members[o.size].value.RawAssign(value);
|
||||
o.size++;
|
||||
DoAddMember(name, value, allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1509,9 +1521,7 @@ public:
|
|||
*/
|
||||
void RemoveAllMembers() {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
|
||||
m->~Member();
|
||||
data_.o.size = 0;
|
||||
DoClearMembers();
|
||||
}
|
||||
|
||||
//! Remove a member in object by its name.
|
||||
|
@ -1555,14 +1565,7 @@ public:
|
|||
RAPIDJSON_ASSERT(data_.o.size > 0);
|
||||
RAPIDJSON_ASSERT(GetMembersPointer() != 0);
|
||||
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
|
||||
|
||||
MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
|
||||
if (data_.o.size > 1 && m != last)
|
||||
*m = *last; // Move the last one to this place
|
||||
else
|
||||
m->~Member(); // Only one left, just destroy
|
||||
--data_.o.size;
|
||||
return m;
|
||||
return DoRemoveMember(m);
|
||||
}
|
||||
|
||||
//! Remove a member from an object by iterator.
|
||||
|
@ -1594,13 +1597,7 @@ public:
|
|||
RAPIDJSON_ASSERT(first >= MemberBegin());
|
||||
RAPIDJSON_ASSERT(first <= last);
|
||||
RAPIDJSON_ASSERT(last <= MemberEnd());
|
||||
|
||||
MemberIterator pos = MemberBegin() + (first - MemberBegin());
|
||||
for (MemberIterator itr = pos; itr != last; ++itr)
|
||||
itr->~Member();
|
||||
std::memmove(static_cast<void*>(&*pos), &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
|
||||
data_.o.size -= static_cast<SizeType>(last - first);
|
||||
return pos;
|
||||
return DoEraseMembers(first, last);
|
||||
}
|
||||
|
||||
//! Erase a member in object by its name.
|
||||
|
@ -1629,7 +1626,9 @@ public:
|
|||
}
|
||||
|
||||
Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
|
||||
Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
|
||||
ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
|
||||
ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
|
||||
|
||||
//@}
|
||||
|
||||
|
@ -1851,12 +1850,12 @@ public:
|
|||
//!@name String
|
||||
//@{
|
||||
|
||||
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
|
||||
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); }
|
||||
|
||||
//! Get the length of string.
|
||||
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
|
||||
*/
|
||||
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
|
||||
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); }
|
||||
|
||||
//! Set this value as a string without copying source string.
|
||||
/*! This version has better performance with supplied length, and also support string containing null character.
|
||||
|
@ -1967,7 +1966,7 @@ public:
|
|||
case kArrayType:
|
||||
if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
|
||||
return false;
|
||||
for (const GenericValue* v = Begin(); v != End(); ++v)
|
||||
for (ConstValueIterator v = Begin(); v != End(); ++v)
|
||||
if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
|
||||
return false;
|
||||
return handler.EndArray(data_.a.size);
|
||||
|
@ -2105,6 +2104,13 @@ private:
|
|||
Flag f;
|
||||
}; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||
|
||||
static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) {
|
||||
return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str);
|
||||
}
|
||||
static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) {
|
||||
return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length;
|
||||
}
|
||||
|
||||
RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
|
||||
RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
|
||||
RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
|
||||
|
@ -2112,6 +2118,286 @@ private:
|
|||
RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
|
||||
RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
|
||||
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
|
||||
struct MapTraits {
|
||||
struct Less {
|
||||
bool operator()(const Data& s1, const Data& s2) const {
|
||||
SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2);
|
||||
int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2));
|
||||
return cmp < 0 || (cmp == 0 && n1 < n2);
|
||||
}
|
||||
};
|
||||
typedef std::pair<const Data, SizeType> Pair;
|
||||
typedef std::multimap<Data, SizeType, Less, StdAllocator<Pair, Allocator> > Map;
|
||||
typedef typename Map::iterator Iterator;
|
||||
};
|
||||
typedef typename MapTraits::Map Map;
|
||||
typedef typename MapTraits::Less MapLess;
|
||||
typedef typename MapTraits::Pair MapPair;
|
||||
typedef typename MapTraits::Iterator MapIterator;
|
||||
|
||||
//
|
||||
// Layout of the members' map/array, re(al)located according to the needed capacity:
|
||||
//
|
||||
// {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]}
|
||||
//
|
||||
// (where <> stands for the RAPIDJSON_ALIGN-ment, if needed)
|
||||
//
|
||||
|
||||
static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) {
|
||||
return RAPIDJSON_ALIGN(sizeof(Map*)) +
|
||||
RAPIDJSON_ALIGN(sizeof(SizeType)) +
|
||||
RAPIDJSON_ALIGN(capacity * sizeof(Member)) +
|
||||
capacity * sizeof(MapIterator);
|
||||
}
|
||||
|
||||
static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) {
|
||||
return *reinterpret_cast<SizeType*>(reinterpret_cast<uintptr_t>(&map) +
|
||||
RAPIDJSON_ALIGN(sizeof(Map*)));
|
||||
}
|
||||
|
||||
static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) {
|
||||
return reinterpret_cast<Member*>(reinterpret_cast<uintptr_t>(&map) +
|
||||
RAPIDJSON_ALIGN(sizeof(Map*)) +
|
||||
RAPIDJSON_ALIGN(sizeof(SizeType)));
|
||||
}
|
||||
|
||||
static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) {
|
||||
return reinterpret_cast<MapIterator*>(reinterpret_cast<uintptr_t>(&map) +
|
||||
RAPIDJSON_ALIGN(sizeof(Map*)) +
|
||||
RAPIDJSON_ALIGN(sizeof(SizeType)) +
|
||||
RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member)));
|
||||
}
|
||||
|
||||
static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) {
|
||||
RAPIDJSON_ASSERT(members != 0);
|
||||
return *reinterpret_cast<Map**>(reinterpret_cast<uintptr_t>(members) -
|
||||
RAPIDJSON_ALIGN(sizeof(SizeType)) -
|
||||
RAPIDJSON_ALIGN(sizeof(Map*)));
|
||||
}
|
||||
|
||||
// Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting..
|
||||
RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) {
|
||||
#if RAPIDJSON_HAS_CXX11
|
||||
MapIterator ret = std::move(rhs);
|
||||
#else
|
||||
MapIterator ret = rhs;
|
||||
#endif
|
||||
rhs.~MapIterator();
|
||||
return ret;
|
||||
}
|
||||
|
||||
Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) {
|
||||
Map **newMap = static_cast<Map**>(allocator.Malloc(GetMapLayoutSize(newCapacity)));
|
||||
GetMapCapacity(*newMap) = newCapacity;
|
||||
if (!oldMap) {
|
||||
*newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator);
|
||||
}
|
||||
else {
|
||||
*newMap = *oldMap;
|
||||
size_t count = (*oldMap)->size();
|
||||
std::memcpy(static_cast<void*>(GetMapMembers(*newMap)),
|
||||
static_cast<void*>(GetMapMembers(*oldMap)),
|
||||
count * sizeof(Member));
|
||||
MapIterator *oldIt = GetMapIterators(*oldMap),
|
||||
*newIt = GetMapIterators(*newMap);
|
||||
while (count--) {
|
||||
new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count]));
|
||||
}
|
||||
Allocator::Free(oldMap);
|
||||
}
|
||||
return *newMap;
|
||||
}
|
||||
|
||||
RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
|
||||
return GetMapMembers(DoReallocMap(0, capacity, allocator));
|
||||
}
|
||||
|
||||
void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
|
||||
ObjectData& o = data_.o;
|
||||
if (newCapacity > o.capacity) {
|
||||
Member* oldMembers = GetMembersPointer();
|
||||
Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0,
|
||||
*&newMap = DoReallocMap(oldMap, newCapacity, allocator);
|
||||
RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap));
|
||||
o.capacity = newCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SourceAllocator>
|
||||
MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
if (Member* members = GetMembersPointer()) {
|
||||
Map* &map = GetMap(members);
|
||||
MapIterator mit = map->find(reinterpret_cast<const Data&>(name.data_));
|
||||
if (mit != map->end()) {
|
||||
return MemberIterator(&members[mit->second]);
|
||||
}
|
||||
}
|
||||
return MemberEnd();
|
||||
}
|
||||
|
||||
void DoClearMembers() {
|
||||
if (Member* members = GetMembersPointer()) {
|
||||
Map* &map = GetMap(members);
|
||||
MapIterator* mit = GetMapIterators(map);
|
||||
for (SizeType i = 0; i < data_.o.size; i++) {
|
||||
map->erase(DropMapIterator(mit[i]));
|
||||
members[i].~Member();
|
||||
}
|
||||
data_.o.size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DoFreeMembers() {
|
||||
if (Member* members = GetMembersPointer()) {
|
||||
GetMap(members)->~Map();
|
||||
for (SizeType i = 0; i < data_.o.size; i++) {
|
||||
members[i].~Member();
|
||||
}
|
||||
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
|
||||
Map** map = &GetMap(members);
|
||||
Allocator::Free(*map);
|
||||
Allocator::Free(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // !RAPIDJSON_USE_MEMBERSMAP
|
||||
|
||||
RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
|
||||
return Malloc<Member>(allocator, capacity);
|
||||
}
|
||||
|
||||
void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
|
||||
ObjectData& o = data_.o;
|
||||
if (newCapacity > o.capacity) {
|
||||
Member* newMembers = Realloc<Member>(allocator, GetMembersPointer(), o.capacity, newCapacity);
|
||||
RAPIDJSON_SETPOINTER(Member, o.members, newMembers);
|
||||
o.capacity = newCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SourceAllocator>
|
||||
MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
MemberIterator member = MemberBegin();
|
||||
for ( ; member != MemberEnd(); ++member)
|
||||
if (name.StringEqual(member->name))
|
||||
break;
|
||||
return member;
|
||||
}
|
||||
|
||||
void DoClearMembers() {
|
||||
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
|
||||
m->~Member();
|
||||
data_.o.size = 0;
|
||||
}
|
||||
|
||||
void DoFreeMembers() {
|
||||
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
|
||||
m->~Member();
|
||||
Allocator::Free(GetMembersPointer());
|
||||
}
|
||||
|
||||
#endif // !RAPIDJSON_USE_MEMBERSMAP
|
||||
|
||||
void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
|
||||
ObjectData& o = data_.o;
|
||||
if (o.size >= o.capacity)
|
||||
DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator);
|
||||
Member* members = GetMembersPointer();
|
||||
Member* m = members + o.size;
|
||||
m->name.RawAssign(name);
|
||||
m->value.RawAssign(value);
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
Map* &map = GetMap(members);
|
||||
MapIterator* mit = GetMapIterators(map);
|
||||
new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size)));
|
||||
#endif
|
||||
++o.size;
|
||||
}
|
||||
|
||||
MemberIterator DoRemoveMember(MemberIterator m) {
|
||||
ObjectData& o = data_.o;
|
||||
Member* members = GetMembersPointer();
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
Map* &map = GetMap(members);
|
||||
MapIterator* mit = GetMapIterators(map);
|
||||
SizeType mpos = static_cast<SizeType>(&*m - members);
|
||||
map->erase(DropMapIterator(mit[mpos]));
|
||||
#endif
|
||||
MemberIterator last(members + (o.size - 1));
|
||||
if (o.size > 1 && m != last) {
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members]));
|
||||
mit[mpos]->second = mpos;
|
||||
#endif
|
||||
*m = *last; // Move the last one to this place
|
||||
}
|
||||
else {
|
||||
m->~Member(); // Only one left, just destroy
|
||||
}
|
||||
--o.size;
|
||||
return m;
|
||||
}
|
||||
|
||||
MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) {
|
||||
ObjectData& o = data_.o;
|
||||
MemberIterator beg = MemberBegin(),
|
||||
pos = beg + (first - beg),
|
||||
end = MemberEnd();
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
Map* &map = GetMap(GetMembersPointer());
|
||||
MapIterator* mit = GetMapIterators(map);
|
||||
#endif
|
||||
for (MemberIterator itr = pos; itr != last; ++itr) {
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
map->erase(DropMapIterator(mit[itr - beg]));
|
||||
#endif
|
||||
itr->~Member();
|
||||
}
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
if (first != last) {
|
||||
// Move remaining members/iterators
|
||||
MemberIterator next = pos + (last - first);
|
||||
for (MemberIterator itr = pos; next != end; ++itr, ++next) {
|
||||
std::memcpy(static_cast<void*>(&*itr), &*next, sizeof(Member));
|
||||
SizeType mpos = static_cast<SizeType>(itr - beg);
|
||||
new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg]));
|
||||
mit[mpos]->second = mpos;
|
||||
}
|
||||
}
|
||||
#else
|
||||
std::memmove(static_cast<void*>(&*pos), &*last,
|
||||
static_cast<size_t>(end - last) * sizeof(Member));
|
||||
#endif
|
||||
o.size -= static_cast<SizeType>(last - first);
|
||||
return pos;
|
||||
}
|
||||
|
||||
template <typename SourceAllocator>
|
||||
void DoCopyMembers(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings) {
|
||||
RAPIDJSON_ASSERT(rhs.GetType() == kObjectType);
|
||||
|
||||
data_.f.flags = kObjectFlag;
|
||||
SizeType count = rhs.data_.o.size;
|
||||
Member* lm = DoAllocMembers(count, allocator);
|
||||
const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
Map* &map = GetMap(lm);
|
||||
MapIterator* mit = GetMapIterators(map);
|
||||
#endif
|
||||
for (SizeType i = 0; i < count; i++) {
|
||||
new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
|
||||
new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i)));
|
||||
#endif
|
||||
}
|
||||
data_.o.size = data_.o.capacity = count;
|
||||
SetMembersPointer(lm);
|
||||
}
|
||||
|
||||
// Initialize this value as array with initial data, without calling destructor.
|
||||
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
|
||||
data_.f.flags = kArrayFlag;
|
||||
|
@ -2129,9 +2415,16 @@ private:
|
|||
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
|
||||
data_.f.flags = kObjectFlag;
|
||||
if (count) {
|
||||
Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
|
||||
Member* m = DoAllocMembers(count, allocator);
|
||||
SetMembersPointer(m);
|
||||
std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));
|
||||
#if RAPIDJSON_USE_MEMBERSMAP
|
||||
Map* &map = GetMap(m);
|
||||
MapIterator* mit = GetMapIterators(map);
|
||||
for (SizeType i = 0; i < count; i++) {
|
||||
new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
SetMembersPointer(0);
|
||||
|
@ -2208,6 +2501,7 @@ public:
|
|||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
||||
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
|
||||
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
||||
typedef StackAllocator StackAllocatorType; //!< StackAllocator type from template parameter.
|
||||
|
||||
//! Constructor
|
||||
/*! Creates an empty document of specified type.
|
||||
|
@ -2252,6 +2546,13 @@ public:
|
|||
#endif
|
||||
|
||||
~GenericDocument() {
|
||||
// Clear the ::ValueType before ownAllocator is destroyed, ~ValueType()
|
||||
// runs last and may access its elements or members which would be freed
|
||||
// with an allocator like MemoryPoolAllocator (CrtAllocator does not
|
||||
// free its data when destroyed, but MemoryPoolAllocator does).
|
||||
if (ownAllocator_) {
|
||||
ValueType::SetNull();
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
@ -2734,4 +3035,9 @@ private:
|
|||
RAPIDJSON_NAMESPACE_END
|
||||
RAPIDJSON_DIAG_POP
|
||||
|
||||
#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
|
||||
#pragma pop_macro("GetObject")
|
||||
#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_DOCUMENT_H_
|
||||
|
|
|
@ -104,11 +104,65 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode val
|
|||
case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
|
||||
|
||||
case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
|
||||
case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'.");
|
||||
case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf', indices '%matches'.");
|
||||
case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
|
||||
case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
|
||||
case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
|
||||
|
||||
case kValidateErrorReadOnly: return RAPIDJSON_ERROR_STRING("Property is read-only but has been provided when validation is for writing.");
|
||||
case kValidateErrorWriteOnly: return RAPIDJSON_ERROR_STRING("Property is write-only but has been provided when validation is for reading.");
|
||||
|
||||
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
//! Maps error code of schema document compilation into error message.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_ERRORS
|
||||
\param schemaErrorCode Error code obtained from compiling the schema document.
|
||||
\return the error message.
|
||||
\note User can make a copy of this function for localization.
|
||||
Using switch-case is safer for future modification of error codes.
|
||||
*/
|
||||
inline const RAPIDJSON_ERROR_CHARTYPE* GetSchemaError_En(SchemaErrorCode schemaErrorCode) {
|
||||
switch (schemaErrorCode) {
|
||||
case kSchemaErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||
|
||||
case kSchemaErrorStartUnknown: return RAPIDJSON_ERROR_STRING("Pointer '%value' to start of schema does not resolve to a location in the document.");
|
||||
case kSchemaErrorRefPlainName: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' must be a JSON pointer.");
|
||||
case kSchemaErrorRefInvalid: return RAPIDJSON_ERROR_STRING("$ref must not be an empty string.");
|
||||
case kSchemaErrorRefPointerInvalid: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' is not a valid JSON pointer at offset '%offset'.");
|
||||
case kSchemaErrorRefUnknown: return RAPIDJSON_ERROR_STRING("$ref '%value' does not resolve to a location in the target document.");
|
||||
case kSchemaErrorRefCyclical: return RAPIDJSON_ERROR_STRING("$ref '%value' is cyclical.");
|
||||
case kSchemaErrorRefNoRemoteProvider: return RAPIDJSON_ERROR_STRING("$ref is remote but there is no remote provider.");
|
||||
case kSchemaErrorRefNoRemoteSchema: return RAPIDJSON_ERROR_STRING("$ref '%value' is remote but the remote provider did not return a schema.");
|
||||
case kSchemaErrorRegexInvalid: return RAPIDJSON_ERROR_STRING("Invalid regular expression '%value' in 'pattern' or 'patternProperties'.");
|
||||
case kSchemaErrorSpecUnknown: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not recognized.");
|
||||
case kSchemaErrorSpecUnsupported: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not supported.");
|
||||
case kSchemaErrorSpecIllegal: return RAPIDJSON_ERROR_STRING("Both JSON schema draft and OpenAPI version found in document.");
|
||||
case kSchemaErrorReadOnlyAndWriteOnly: return RAPIDJSON_ERROR_STRING("Property must not be both 'readOnly' and 'writeOnly'.");
|
||||
|
||||
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
//! Maps error code of pointer parse into error message.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_ERRORS
|
||||
\param pointerParseErrorCode Error code obtained from pointer parse.
|
||||
\return the error message.
|
||||
\note User can make a copy of this function for localization.
|
||||
Using switch-case is safer for future modification of error codes.
|
||||
*/
|
||||
inline const RAPIDJSON_ERROR_CHARTYPE* GetPointerParseError_En(PointerParseErrorCode pointerParseErrorCode) {
|
||||
switch (pointerParseErrorCode) {
|
||||
case kPointerParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||
|
||||
case kPointerParseErrorTokenMustBeginWithSolidus: return RAPIDJSON_ERROR_STRING("A token must begin with a '/'.");
|
||||
case kPointerParseErrorInvalidEscape: return RAPIDJSON_ERROR_STRING("Invalid escape.");
|
||||
case kPointerParseErrorInvalidPercentEncoding: return RAPIDJSON_ERROR_STRING("Invalid percent encoding in URI fragment.");
|
||||
case kPointerParseErrorCharacterMustPercentEncode: return RAPIDJSON_ERROR_STRING("A character must be percent encoded in a URI fragment.");
|
||||
|
||||
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ RAPIDJSON_DIAG_OFF(padded)
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ERROR_STRING
|
||||
|
||||
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
|
||||
//! Macro for converting string literal to \ref RAPIDJSON_ERROR_CHARTYPE[].
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
By default this conversion macro does nothing.
|
||||
On Windows, user can define this macro as \c _T(x) for supporting both
|
||||
|
@ -185,14 +185,17 @@ enum ValidateErrorCode {
|
|||
kValidateErrorPatternProperties, //!< See other errors.
|
||||
kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
|
||||
|
||||
kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values
|
||||
kValidateErrorType, //!< Property has a type that is not allowed by the schema..
|
||||
kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values.
|
||||
kValidateErrorType, //!< Property has a type that is not allowed by the schema.
|
||||
|
||||
kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'.
|
||||
kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
|
||||
kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'.
|
||||
kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'.
|
||||
kValidateErrorNot //!< Property matched the sub-schema specified by 'not'.
|
||||
kValidateErrorNot, //!< Property matched the sub-schema specified by 'not'.
|
||||
|
||||
kValidateErrorReadOnly, //!< Property is read-only but has been provided when validation is for writing
|
||||
kValidateErrorWriteOnly //!< Property is write-only but has been provided when validation is for reading
|
||||
};
|
||||
|
||||
//! Function pointer type of GetValidateError().
|
||||
|
@ -207,6 +210,72 @@ enum ValidateErrorCode {
|
|||
*/
|
||||
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SchemaErrorCode
|
||||
|
||||
//! Error codes when validating.
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
\see GenericSchemaValidator
|
||||
*/
|
||||
enum SchemaErrorCode {
|
||||
kSchemaErrorNone = 0, //!< No error.
|
||||
|
||||
kSchemaErrorStartUnknown, //!< Pointer to start of schema does not resolve to a location in the document
|
||||
kSchemaErrorRefPlainName, //!< $ref fragment must be a JSON pointer
|
||||
kSchemaErrorRefInvalid, //!< $ref must not be an empty string
|
||||
kSchemaErrorRefPointerInvalid, //!< $ref fragment is not a valid JSON pointer at offset
|
||||
kSchemaErrorRefUnknown, //!< $ref does not resolve to a location in the target document
|
||||
kSchemaErrorRefCyclical, //!< $ref is cyclical
|
||||
kSchemaErrorRefNoRemoteProvider, //!< $ref is remote but there is no remote provider
|
||||
kSchemaErrorRefNoRemoteSchema, //!< $ref is remote but the remote provider did not return a schema
|
||||
kSchemaErrorRegexInvalid, //!< Invalid regular expression in 'pattern' or 'patternProperties'
|
||||
kSchemaErrorSpecUnknown, //!< JSON schema draft or OpenAPI version is not recognized
|
||||
kSchemaErrorSpecUnsupported, //!< JSON schema draft or OpenAPI version is not supported
|
||||
kSchemaErrorSpecIllegal, //!< Both JSON schema draft and OpenAPI version found in document
|
||||
kSchemaErrorReadOnlyAndWriteOnly //!< Property must not be both 'readOnly' and 'writeOnly'
|
||||
};
|
||||
|
||||
//! Function pointer type of GetSchemaError().
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
|
||||
This is the prototype for \c GetSchemaError_X(), where \c X is a locale.
|
||||
User can dynamically change locale in runtime, e.g.:
|
||||
\code
|
||||
GetSchemaErrorFunc GetSchemaError = GetSchemaError_En; // or whatever
|
||||
const RAPIDJSON_ERROR_CHARTYPE* s = GetSchemaError(validator.GetInvalidSchemaCode());
|
||||
\endcode
|
||||
*/
|
||||
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetSchemaErrorFunc)(SchemaErrorCode);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PointerParseErrorCode
|
||||
|
||||
//! Error code of JSON pointer parsing.
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
\see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
|
||||
*/
|
||||
enum PointerParseErrorCode {
|
||||
kPointerParseErrorNone = 0, //!< The parse is successful
|
||||
|
||||
kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
|
||||
kPointerParseErrorInvalidEscape, //!< Invalid escape
|
||||
kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
|
||||
kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
|
||||
};
|
||||
|
||||
//! Function pointer type of GetPointerParseError().
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
|
||||
This is the prototype for \c GetPointerParseError_X(), where \c X is a locale.
|
||||
User can dynamically change locale in runtime, e.g.:
|
||||
\code
|
||||
GetPointerParseErrorFunc GetPointerParseError = GetPointerParseError_En; // or whatever
|
||||
const RAPIDJSON_ERROR_CHARTYPE* s = GetPointerParseError(pointer.GetParseErrorCode());
|
||||
\endcode
|
||||
*/
|
||||
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetPointerParseErrorFunc)(PointerParseErrorCode);
|
||||
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
|
||||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64)
|
||||
#include <intrin.h> // for _umul128
|
||||
#if !defined(_ARM64EC_)
|
||||
#pragma intrinsic(_umul128)
|
||||
#else
|
||||
#pragma comment(lib,"softintrin")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
@ -37,7 +41,8 @@ public:
|
|||
digits_[0] = u;
|
||||
}
|
||||
|
||||
BigInteger(const char* decimals, size_t length) : count_(1) {
|
||||
template<typename Ch>
|
||||
BigInteger(const Ch* decimals, size_t length) : count_(1) {
|
||||
RAPIDJSON_ASSERT(length > 0);
|
||||
digits_[0] = 0;
|
||||
size_t i = 0;
|
||||
|
@ -221,7 +226,8 @@ public:
|
|||
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
|
||||
|
||||
private:
|
||||
void AppendDecimal64(const char* begin, const char* end) {
|
||||
template<typename Ch>
|
||||
void AppendDecimal64(const Ch* begin, const Ch* end) {
|
||||
uint64_t u = ParseUint64(begin, end);
|
||||
if (IsZero())
|
||||
*this = u;
|
||||
|
@ -236,11 +242,12 @@ private:
|
|||
digits_[count_++] = digit;
|
||||
}
|
||||
|
||||
static uint64_t ParseUint64(const char* begin, const char* end) {
|
||||
template<typename Ch>
|
||||
static uint64_t ParseUint64(const Ch* begin, const Ch* end) {
|
||||
uint64_t r = 0;
|
||||
for (const char* p = begin; p != end; ++p) {
|
||||
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
||||
r = r * 10u + static_cast<unsigned>(*p - '0');
|
||||
for (const Ch* p = begin; p != end; ++p) {
|
||||
RAPIDJSON_ASSERT(*p >= Ch('0') && *p <= Ch('9'));
|
||||
r = r * 10u + static_cast<unsigned>(*p - Ch('0'));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -252,7 +259,7 @@ private:
|
|||
if (low < k)
|
||||
(*outHigh)++;
|
||||
return low;
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
|
||||
p += k;
|
||||
|
|
|
@ -25,7 +25,11 @@
|
|||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
|
||||
#include <intrin.h>
|
||||
#if !defined(_ARM64EC_)
|
||||
#pragma intrinsic(_umul128)
|
||||
#else
|
||||
#pragma comment(lib,"softintrin")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
@ -75,7 +79,7 @@ struct DiyFp {
|
|||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
return DiyFp(h, e + rhs.e + 64);
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
|
||||
uint64_t h = static_cast<uint64_t>(p >> 64);
|
||||
|
|
|
@ -58,7 +58,11 @@ inline int CountDecimalDigit32(uint32_t n) {
|
|||
}
|
||||
|
||||
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
|
||||
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
static const uint64_t kPow10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL,
|
||||
1000000000ULL, 10000000000ULL, 100000000000ULL, 1000000000000ULL,
|
||||
10000000000000ULL, 100000000000000ULL, 1000000000000000ULL,
|
||||
10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL,
|
||||
10000000000000000000ULL };
|
||||
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
|
||||
const DiyFp wp_w = Mp - W;
|
||||
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||
|
@ -86,7 +90,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
|
|||
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
|
||||
if (tmp <= delta) {
|
||||
*K += kappa;
|
||||
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
|
||||
GrisuRound(buffer, *len, delta, tmp, kPow10[kappa] << -one.e, wp_w.f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +107,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
|
|||
if (p2 < delta) {
|
||||
*K += kappa;
|
||||
int index = -kappa;
|
||||
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
|
||||
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 20 ? kPow10[index] : 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -615,7 +615,7 @@ public:
|
|||
RAPIDJSON_ASSERT(regex_.IsValid());
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
|
||||
stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
|
||||
stateSet_ = static_cast<uint32_t*>(allocator_->Malloc(GetStateSetSize()));
|
||||
state0_.template Reserve<SizeType>(regex_.stateCount_);
|
||||
state1_.template Reserve<SizeType>(regex_.stateCount_);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,20 @@ inline SizeType StrLen(const wchar_t* s) {
|
|||
return SizeType(std::wcslen(s));
|
||||
}
|
||||
|
||||
//! Custom strcmpn() which works on different character types.
|
||||
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||
\param s1 Null-terminated input string.
|
||||
\param s2 Null-terminated input string.
|
||||
\return 0 if equal
|
||||
*/
|
||||
template<typename Ch>
|
||||
inline int StrCmp(const Ch* s1, const Ch* s2) {
|
||||
RAPIDJSON_ASSERT(s1 != 0);
|
||||
RAPIDJSON_ASSERT(s2 != 0);
|
||||
while(*s1 && (*s1 == *s2)) { s1++; s2++; }
|
||||
return static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
|
||||
}
|
||||
|
||||
//! Returns number of code points in a encoded string.
|
||||
template<typename Encoding>
|
||||
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
|
||||
|
|
|
@ -128,17 +128,18 @@ inline bool StrtodFast(double d, int p, double* result) {
|
|||
}
|
||||
|
||||
// Compute an approximation and see if it is within 1/2 ULP
|
||||
inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
|
||||
template<typename Ch>
|
||||
inline bool StrtodDiyFp(const Ch* decimals, int dLen, int dExp, double* result) {
|
||||
uint64_t significand = 0;
|
||||
int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||
for (; i < dLen; i++) {
|
||||
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > Ch('5')))
|
||||
break;
|
||||
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||
significand = significand * 10u + static_cast<unsigned>(decimals[i] - Ch('0'));
|
||||
}
|
||||
|
||||
if (i < dLen && decimals[i] >= '5') // Rounding
|
||||
if (i < dLen && decimals[i] >= Ch('5')) // Rounding
|
||||
significand++;
|
||||
|
||||
int remaining = dLen - i;
|
||||
|
@ -205,7 +206,8 @@ inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result
|
|||
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||
}
|
||||
|
||||
inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
|
||||
template<typename Ch>
|
||||
inline double StrtodBigInteger(double approx, const Ch* decimals, int dLen, int dExp) {
|
||||
RAPIDJSON_ASSERT(dLen >= 0);
|
||||
const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
|
||||
Double a(approx);
|
||||
|
@ -223,7 +225,8 @@ inline double StrtodBigInteger(double approx, const char* decimals, int dLen, in
|
|||
return a.NextPositiveDouble();
|
||||
}
|
||||
|
||||
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||
template<typename Ch>
|
||||
inline double StrtodFullPrecision(double d, int p, const Ch* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||
RAPIDJSON_ASSERT(d >= 0.0);
|
||||
RAPIDJSON_ASSERT(length >= 1);
|
||||
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
#define RAPIDJSON_POINTER_H_
|
||||
|
||||
#include "document.h"
|
||||
#include "uri.h"
|
||||
#include "internal/itoa.h"
|
||||
#include "error/error.h" // PointerParseErrorCode
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
|
@ -30,19 +32,6 @@ RAPIDJSON_NAMESPACE_BEGIN
|
|||
|
||||
static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
|
||||
|
||||
//! Error code of parsing.
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
\see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
|
||||
*/
|
||||
enum PointerParseErrorCode {
|
||||
kPointerParseErrorNone = 0, //!< The parse is successful
|
||||
|
||||
kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
|
||||
kPointerParseErrorInvalidEscape, //!< Invalid escape
|
||||
kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
|
||||
kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericPointer
|
||||
|
||||
|
@ -80,6 +69,8 @@ class GenericPointer {
|
|||
public:
|
||||
typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
|
||||
typedef typename ValueType::Ch Ch; //!< Character type from Value
|
||||
typedef GenericUri<ValueType, Allocator> UriType;
|
||||
|
||||
|
||||
//! A token is the basic units of internal representation.
|
||||
/*!
|
||||
|
@ -163,7 +154,7 @@ public:
|
|||
GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
|
||||
|
||||
//! Copy constructor.
|
||||
GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
|
||||
GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
|
@ -520,6 +511,70 @@ public:
|
|||
|
||||
//@}
|
||||
|
||||
//!@name Compute URI
|
||||
//@{
|
||||
|
||||
//! Compute the in-scope URI for a subtree.
|
||||
// For use with JSON pointers into JSON schema documents.
|
||||
/*!
|
||||
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
|
||||
\param rootUri Root URI
|
||||
\param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
|
||||
\param allocator Allocator for Uris
|
||||
\return Uri if it can be resolved. Otherwise null.
|
||||
|
||||
\note
|
||||
There are only 3 situations when a URI 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.
|
||||
*/
|
||||
UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
|
||||
static const Ch kIdString[] = { 'i', 'd', '\0' };
|
||||
static const ValueType kIdValue(kIdString, 2);
|
||||
UriType base = UriType(rootUri, allocator);
|
||||
RAPIDJSON_ASSERT(IsValid());
|
||||
ValueType* v = &root;
|
||||
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
|
||||
switch (v->GetType()) {
|
||||
case kObjectType:
|
||||
{
|
||||
// See if we have an id, and if so resolve with the current base
|
||||
typename ValueType::MemberIterator m = v->FindMember(kIdValue);
|
||||
if (m != v->MemberEnd() && (m->value).IsString()) {
|
||||
UriType here = UriType(m->value, allocator).Resolve(base, allocator);
|
||||
base = here;
|
||||
}
|
||||
m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
|
||||
if (m == v->MemberEnd())
|
||||
break;
|
||||
v = &m->value;
|
||||
}
|
||||
continue;
|
||||
case kArrayType:
|
||||
if (t->index == kPointerInvalidIndex || t->index >= v->Size())
|
||||
break;
|
||||
v = &((*v)[t->index]);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Error: unresolved token
|
||||
if (unresolvedTokenIndex)
|
||||
*unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
|
||||
return UriType(allocator);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
|
||||
return GetUri(const_cast<ValueType&>(root), rootUri, unresolvedTokenIndex, allocator);
|
||||
}
|
||||
|
||||
|
||||
//!@name Query value
|
||||
//@{
|
||||
|
||||
|
@ -835,10 +890,16 @@ private:
|
|||
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
|
||||
}
|
||||
|
||||
// Adjust pointers to name buffer
|
||||
std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
|
||||
for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
|
||||
t->name += diff;
|
||||
// The names of each token point to a string in the nameBuffer_. The
|
||||
// previous memcpy copied over string pointers into the rhs.nameBuffer_,
|
||||
// but they should point to the strings in the new nameBuffer_.
|
||||
for (size_t i = 0; i < rhs.tokenCount_; ++i) {
|
||||
// The offset between the string address and the name buffer should
|
||||
// still be constant, so we can just get this offset and set each new
|
||||
// token name according the new buffer start + the known offset.
|
||||
std::ptrdiff_t name_offset = rhs.tokens_[i].name - rhs.nameBuffer_;
|
||||
tokens_[i].name = nameBuffer_ + name_offset;
|
||||
}
|
||||
|
||||
return nameBuffer_ + nameBufferSize;
|
||||
}
|
||||
|
|
|
@ -124,6 +124,19 @@
|
|||
#define RAPIDJSON_NAMESPACE_END }
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// __cplusplus macro
|
||||
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define RAPIDJSON_CPLUSPLUS _MSVC_LANG
|
||||
#else
|
||||
#define RAPIDJSON_CPLUSPLUS __cplusplus
|
||||
#endif
|
||||
|
||||
//!@endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
|
@ -149,6 +162,24 @@
|
|||
#include <string>
|
||||
#endif // RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_USE_MEMBERSMAP
|
||||
|
||||
/*! \def RAPIDJSON_USE_MEMBERSMAP
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Enable RapidJSON support for object members handling in a \c std::multimap
|
||||
|
||||
By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object
|
||||
members are stored in a \c std::multimap for faster lookup and deletion times, a
|
||||
trade off with a slightly slower insertion time and a small object allocat(or)ed
|
||||
memory overhead.
|
||||
|
||||
\hideinitializer
|
||||
*/
|
||||
#ifndef RAPIDJSON_USE_MEMBERSMAP
|
||||
#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_INT64DEFINE
|
||||
|
||||
|
@ -411,7 +442,7 @@ RAPIDJSON_NAMESPACE_END
|
|||
|
||||
// Prefer C++11 static_assert, if available
|
||||
#ifndef RAPIDJSON_STATIC_ASSERT
|
||||
#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
|
||||
#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
|
||||
#define RAPIDJSON_STATIC_ASSERT(x) \
|
||||
static_assert(x, RAPIDJSON_STRINGIFY(x))
|
||||
#endif // C++11
|
||||
|
@ -541,8 +572,14 @@ RAPIDJSON_NAMESPACE_END
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// C++11 features
|
||||
|
||||
#ifndef RAPIDJSON_HAS_CXX11
|
||||
#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L)
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#if defined(__clang__)
|
||||
#if RAPIDJSON_HAS_CXX11
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||
#elif defined(__clang__)
|
||||
#if __has_feature(cxx_rvalue_references) && \
|
||||
(defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||
|
@ -559,8 +596,14 @@ RAPIDJSON_NAMESPACE_END
|
|||
#endif
|
||||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#include <utility> // std::move
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#if defined(__clang__)
|
||||
#if RAPIDJSON_HAS_CXX11
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
|
||||
#elif defined(__clang__)
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
|
||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1900) || \
|
||||
|
@ -570,11 +613,13 @@ RAPIDJSON_NAMESPACE_END
|
|||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
|
||||
#endif
|
||||
#endif
|
||||
#ifndef RAPIDJSON_NOEXCEPT
|
||||
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#define RAPIDJSON_NOEXCEPT noexcept
|
||||
#else
|
||||
#define RAPIDJSON_NOEXCEPT /* noexcept */
|
||||
#define RAPIDJSON_NOEXCEPT throw()
|
||||
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#endif
|
||||
|
||||
// no automatic detection, yet
|
||||
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
@ -600,9 +645,17 @@ RAPIDJSON_NAMESPACE_END
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// C++17 features
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(fallthrough)
|
||||
#ifndef RAPIDJSON_HAS_CXX17
|
||||
#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L)
|
||||
#endif
|
||||
|
||||
#if RAPIDJSON_HAS_CXX17
|
||||
# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
|
||||
#elif defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(clang::fallthrough)
|
||||
# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]]
|
||||
# elif __has_cpp_attribute(fallthrough)
|
||||
# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough))
|
||||
# else
|
||||
# define RAPIDJSON_DELIBERATE_FALLTHROUGH
|
||||
# endif
|
||||
|
@ -628,12 +681,8 @@ RAPIDJSON_NAMESPACE_END
|
|||
|
||||
#ifndef RAPIDJSON_NOEXCEPT_ASSERT
|
||||
#ifdef RAPIDJSON_ASSERT_THROWS
|
||||
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#define RAPIDJSON_NOEXCEPT_ASSERT(x)
|
||||
#else
|
||||
#include <cassert>
|
||||
#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x)
|
||||
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#else
|
||||
#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
|
||||
#endif // RAPIDJSON_ASSERT_THROWS
|
||||
|
|
|
@ -1404,11 +1404,11 @@ private:
|
|||
}
|
||||
#endif // RAPIDJSON_NEON
|
||||
|
||||
template<typename InputStream, bool backup, bool pushOnTake>
|
||||
template<typename InputStream, typename StackCharacter, bool backup, bool pushOnTake>
|
||||
class NumberStream;
|
||||
|
||||
template<typename InputStream>
|
||||
class NumberStream<InputStream, false, false> {
|
||||
template<typename InputStream, typename StackCharacter>
|
||||
class NumberStream<InputStream, StackCharacter, false, false> {
|
||||
public:
|
||||
typedef typename InputStream::Ch Ch;
|
||||
|
||||
|
@ -1421,7 +1421,7 @@ private:
|
|||
|
||||
size_t Tell() { return is.Tell(); }
|
||||
size_t Length() { return 0; }
|
||||
const char* Pop() { return 0; }
|
||||
const StackCharacter* Pop() { return 0; }
|
||||
|
||||
protected:
|
||||
NumberStream& operator=(const NumberStream&);
|
||||
|
@ -1429,45 +1429,47 @@ private:
|
|||
InputStream& is;
|
||||
};
|
||||
|
||||
template<typename InputStream>
|
||||
class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
|
||||
typedef NumberStream<InputStream, false, false> Base;
|
||||
template<typename InputStream, typename StackCharacter>
|
||||
class NumberStream<InputStream, StackCharacter, true, false> : public NumberStream<InputStream, StackCharacter, false, false> {
|
||||
typedef NumberStream<InputStream, StackCharacter, false, false> Base;
|
||||
public:
|
||||
NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
|
||||
NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s), stackStream(reader.stack_) {}
|
||||
|
||||
RAPIDJSON_FORCEINLINE Ch TakePush() {
|
||||
stackStream.Put(static_cast<char>(Base::is.Peek()));
|
||||
stackStream.Put(static_cast<StackCharacter>(Base::is.Peek()));
|
||||
return Base::is.Take();
|
||||
}
|
||||
|
||||
RAPIDJSON_FORCEINLINE void Push(char c) {
|
||||
RAPIDJSON_FORCEINLINE void Push(StackCharacter c) {
|
||||
stackStream.Put(c);
|
||||
}
|
||||
|
||||
size_t Length() { return stackStream.Length(); }
|
||||
|
||||
const char* Pop() {
|
||||
const StackCharacter* Pop() {
|
||||
stackStream.Put('\0');
|
||||
return stackStream.Pop();
|
||||
}
|
||||
|
||||
private:
|
||||
StackStream<char> stackStream;
|
||||
StackStream<StackCharacter> stackStream;
|
||||
};
|
||||
|
||||
template<typename InputStream>
|
||||
class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
|
||||
typedef NumberStream<InputStream, true, false> Base;
|
||||
template<typename InputStream, typename StackCharacter>
|
||||
class NumberStream<InputStream, StackCharacter, true, true> : public NumberStream<InputStream, StackCharacter, true, false> {
|
||||
typedef NumberStream<InputStream, StackCharacter, true, false> Base;
|
||||
public:
|
||||
NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
|
||||
NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s) {}
|
||||
|
||||
RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
|
||||
};
|
||||
|
||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||
void ParseNumber(InputStream& is, Handler& handler) {
|
||||
typedef typename internal::SelectIf<internal::BoolType<(parseFlags & kParseNumbersAsStringsFlag) != 0>, typename TargetEncoding::Ch, char>::Type NumberCharacter;
|
||||
|
||||
internal::StreamLocalCopy<InputStream> copy(is);
|
||||
NumberStream<InputStream,
|
||||
NumberStream<InputStream, NumberCharacter,
|
||||
((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
|
||||
((parseFlags & kParseInsituFlag) == 0) :
|
||||
((parseFlags & kParseFullPrecisionFlag) != 0),
|
||||
|
@ -1692,10 +1694,10 @@ private:
|
|||
}
|
||||
else {
|
||||
SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
|
||||
StringStream srcStream(s.Pop());
|
||||
GenericStringStream<UTF8<NumberCharacter> > srcStream(s.Pop());
|
||||
StackStream<typename TargetEncoding::Ch> dstStream(stack_);
|
||||
while (numCharsToCopy--) {
|
||||
Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
|
||||
Transcoder<UTF8<typename TargetEncoding::Ch>, TargetEncoding>::Transcode(srcStream, dstStream);
|
||||
}
|
||||
dstStream.Put('\0');
|
||||
const typename TargetEncoding::Ch* str = dstStream.Pop();
|
||||
|
@ -1705,7 +1707,7 @@ private:
|
|||
}
|
||||
else {
|
||||
size_t length = s.Length();
|
||||
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
|
||||
const NumberCharacter* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
|
||||
|
||||
if (useDouble) {
|
||||
int p = exp + expFrac;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,481 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// (C) Copyright IBM Corporation 2021
|
||||
//
|
||||
// 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_URI_H_
|
||||
#define RAPIDJSON_URI_H_
|
||||
|
||||
#include "internal/strfunc.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#elif defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericUri
|
||||
|
||||
template <typename ValueType, typename Allocator=CrtAllocator>
|
||||
class GenericUri {
|
||||
public:
|
||||
typedef typename ValueType::Ch Ch;
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
typedef std::basic_string<Ch> String;
|
||||
#endif
|
||||
|
||||
//! Constructors
|
||||
GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
|
||||
}
|
||||
|
||||
GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
|
||||
Parse(uri, len);
|
||||
}
|
||||
|
||||
GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
|
||||
Parse(uri, internal::StrLen<Ch>(uri));
|
||||
}
|
||||
|
||||
// Use with specializations of GenericValue
|
||||
template<typename T> GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
|
||||
const Ch* u = uri.template Get<const Ch*>(); // TypeHelper from document.h
|
||||
Parse(u, internal::StrLen<Ch>(u));
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
|
||||
Parse(uri.c_str(), internal::StrLen<Ch>(uri.c_str()));
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Copy constructor
|
||||
GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() {
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
//! Copy constructor
|
||||
GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
//! Destructor.
|
||||
~GenericUri() {
|
||||
Free();
|
||||
RAPIDJSON_DELETE(ownAllocator_);
|
||||
}
|
||||
|
||||
//! Assignment operator
|
||||
GenericUri& operator=(const GenericUri& rhs) {
|
||||
if (this != &rhs) {
|
||||
// Do not delete ownAllocator
|
||||
Free();
|
||||
Allocate(rhs.GetStringLength());
|
||||
auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength());
|
||||
path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength());
|
||||
query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength());
|
||||
frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength());
|
||||
base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength());
|
||||
uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength());
|
||||
CopyPart(uri_, rhs.uri_, rhs.GetStringLength());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Getters
|
||||
// Use with specializations of GenericValue
|
||||
template<typename T> void Get(T& uri, Allocator& allocator) {
|
||||
uri.template Set<const Ch*>(this->GetString(), allocator); // TypeHelper from document.h
|
||||
}
|
||||
|
||||
const Ch* GetString() const { return uri_; }
|
||||
SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen<Ch>(uri_); }
|
||||
const Ch* GetBaseString() const { return base_; }
|
||||
SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen<Ch>(base_); }
|
||||
const Ch* GetSchemeString() const { return scheme_; }
|
||||
SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen<Ch>(scheme_); }
|
||||
const Ch* GetAuthString() const { return auth_; }
|
||||
SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen<Ch>(auth_); }
|
||||
const Ch* GetPathString() const { return path_; }
|
||||
SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen<Ch>(path_); }
|
||||
const Ch* GetQueryString() const { return query_; }
|
||||
SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen<Ch>(query_); }
|
||||
const Ch* GetFragString() const { return frag_; }
|
||||
SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen<Ch>(frag_); }
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); }
|
||||
static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); }
|
||||
static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); }
|
||||
static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); }
|
||||
static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); }
|
||||
static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); }
|
||||
static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); }
|
||||
#endif
|
||||
|
||||
//! Equality operators
|
||||
bool operator==(const GenericUri& rhs) const {
|
||||
return Match(rhs, true);
|
||||
}
|
||||
|
||||
bool operator!=(const GenericUri& rhs) const {
|
||||
return !Match(rhs, true);
|
||||
}
|
||||
|
||||
bool Match(const GenericUri& uri, bool full = true) const {
|
||||
Ch* s1;
|
||||
Ch* s2;
|
||||
if (full) {
|
||||
s1 = uri_;
|
||||
s2 = uri.uri_;
|
||||
} else {
|
||||
s1 = base_;
|
||||
s2 = uri.base_;
|
||||
}
|
||||
if (s1 == s2) return true;
|
||||
if (s1 == 0 || s2 == 0) return false;
|
||||
return internal::StrCmp<Ch>(s1, s2) == 0;
|
||||
}
|
||||
|
||||
//! Resolve this URI against another (base) URI in accordance with URI resolution rules.
|
||||
// See https://tools.ietf.org/html/rfc3986
|
||||
// Use for resolving an id or $ref with an in-scope id.
|
||||
// Returns a new GenericUri for the resolved URI.
|
||||
GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) {
|
||||
GenericUri resuri;
|
||||
resuri.allocator_ = allocator;
|
||||
// Ensure enough space for combining paths
|
||||
resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1); // + 1 for joining slash
|
||||
|
||||
if (!(GetSchemeStringLength() == 0)) {
|
||||
// Use all of this URI
|
||||
resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength());
|
||||
resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
|
||||
resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
|
||||
resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
|
||||
resuri.RemoveDotSegments();
|
||||
} else {
|
||||
// Use the base scheme
|
||||
resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength());
|
||||
if (!(GetAuthStringLength() == 0)) {
|
||||
// Use this auth, path, query
|
||||
resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
|
||||
resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
|
||||
resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
|
||||
resuri.RemoveDotSegments();
|
||||
} else {
|
||||
// Use the base auth
|
||||
resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength());
|
||||
if (GetPathStringLength() == 0) {
|
||||
// Use the base path
|
||||
resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength());
|
||||
if (GetQueryStringLength() == 0) {
|
||||
// Use the base query
|
||||
resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength());
|
||||
} else {
|
||||
// Use this query
|
||||
resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
|
||||
}
|
||||
} else {
|
||||
if (path_[0] == '/') {
|
||||
// Absolute path - use all of this path
|
||||
resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
|
||||
resuri.RemoveDotSegments();
|
||||
} else {
|
||||
// Relative path - append this path to base path after base path's last slash
|
||||
size_t pos = 0;
|
||||
if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) {
|
||||
resuri.path_[pos] = '/';
|
||||
pos++;
|
||||
}
|
||||
size_t lastslashpos = baseuri.GetPathStringLength();
|
||||
while (lastslashpos > 0) {
|
||||
if (baseuri.path_[lastslashpos - 1] == '/') break;
|
||||
lastslashpos--;
|
||||
}
|
||||
std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch));
|
||||
pos += lastslashpos;
|
||||
resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength());
|
||||
resuri.RemoveDotSegments();
|
||||
}
|
||||
// Use this query
|
||||
resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Always use this frag
|
||||
resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength());
|
||||
|
||||
// Re-constitute base_ and uri_
|
||||
resuri.SetBase();
|
||||
resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1;
|
||||
resuri.SetUri();
|
||||
return resuri;
|
||||
}
|
||||
|
||||
//! Get the allocator of this GenericUri.
|
||||
Allocator& GetAllocator() { return *allocator_; }
|
||||
|
||||
private:
|
||||
// Allocate memory for a URI
|
||||
// Returns total amount allocated
|
||||
std::size_t Allocate(std::size_t len) {
|
||||
// Create own allocator if user did not supply.
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
|
||||
|
||||
// Allocate one block containing each part of the URI (5) plus base plus full URI, all null terminated.
|
||||
// Order: scheme, auth, path, query, frag, base, uri
|
||||
// Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
|
||||
size_t total = (3 * len + 7) * sizeof(Ch);
|
||||
scheme_ = static_cast<Ch*>(allocator_->Malloc(total));
|
||||
*scheme_ = '\0';
|
||||
auth_ = scheme_;
|
||||
auth_++;
|
||||
*auth_ = '\0';
|
||||
path_ = auth_;
|
||||
path_++;
|
||||
*path_ = '\0';
|
||||
query_ = path_;
|
||||
query_++;
|
||||
*query_ = '\0';
|
||||
frag_ = query_;
|
||||
frag_++;
|
||||
*frag_ = '\0';
|
||||
base_ = frag_;
|
||||
base_++;
|
||||
*base_ = '\0';
|
||||
uri_ = base_;
|
||||
uri_++;
|
||||
*uri_ = '\0';
|
||||
return total;
|
||||
}
|
||||
|
||||
// Free memory for a URI
|
||||
void Free() {
|
||||
if (scheme_) {
|
||||
Allocator::Free(scheme_);
|
||||
scheme_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a URI into constituent scheme, authority, path, query, & fragment parts
|
||||
// Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per
|
||||
// https://tools.ietf.org/html/rfc3986
|
||||
void Parse(const Ch* uri, std::size_t len) {
|
||||
std::size_t start = 0, pos1 = 0, pos2 = 0;
|
||||
Allocate(len);
|
||||
|
||||
// Look for scheme ([^:/?#]+):)?
|
||||
if (start < len) {
|
||||
while (pos1 < len) {
|
||||
if (uri[pos1] == ':') break;
|
||||
pos1++;
|
||||
}
|
||||
if (pos1 != len) {
|
||||
while (pos2 < len) {
|
||||
if (uri[pos2] == '/') break;
|
||||
if (uri[pos2] == '?') break;
|
||||
if (uri[pos2] == '#') break;
|
||||
pos2++;
|
||||
}
|
||||
if (pos1 < pos2) {
|
||||
pos1++;
|
||||
std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch));
|
||||
scheme_[pos1] = '\0';
|
||||
start = pos1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Look for auth (//([^/?#]*))?
|
||||
// Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
|
||||
auth_ = scheme_ + GetSchemeStringLength();
|
||||
auth_++;
|
||||
*auth_ = '\0';
|
||||
if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') {
|
||||
pos2 = start + 2;
|
||||
while (pos2 < len) {
|
||||
if (uri[pos2] == '/') break;
|
||||
if (uri[pos2] == '?') break;
|
||||
if (uri[pos2] == '#') break;
|
||||
pos2++;
|
||||
}
|
||||
std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch));
|
||||
auth_[pos2 - start] = '\0';
|
||||
start = pos2;
|
||||
}
|
||||
// Look for path ([^?#]*)
|
||||
// Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
|
||||
path_ = auth_ + GetAuthStringLength();
|
||||
path_++;
|
||||
*path_ = '\0';
|
||||
if (start < len) {
|
||||
pos2 = start;
|
||||
while (pos2 < len) {
|
||||
if (uri[pos2] == '?') break;
|
||||
if (uri[pos2] == '#') break;
|
||||
pos2++;
|
||||
}
|
||||
if (start != pos2) {
|
||||
std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch));
|
||||
path_[pos2 - start] = '\0';
|
||||
if (path_[0] == '/')
|
||||
RemoveDotSegments(); // absolute path - normalize
|
||||
start = pos2;
|
||||
}
|
||||
}
|
||||
// Look for query (\?([^#]*))?
|
||||
// Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
|
||||
query_ = path_ + GetPathStringLength();
|
||||
query_++;
|
||||
*query_ = '\0';
|
||||
if (start < len && uri[start] == '?') {
|
||||
pos2 = start + 1;
|
||||
while (pos2 < len) {
|
||||
if (uri[pos2] == '#') break;
|
||||
pos2++;
|
||||
}
|
||||
if (start != pos2) {
|
||||
std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch));
|
||||
query_[pos2 - start] = '\0';
|
||||
start = pos2;
|
||||
}
|
||||
}
|
||||
// Look for fragment (#(.*))?
|
||||
// Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
|
||||
frag_ = query_ + GetQueryStringLength();
|
||||
frag_++;
|
||||
*frag_ = '\0';
|
||||
if (start < len && uri[start] == '#') {
|
||||
std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch));
|
||||
frag_[len - start] = '\0';
|
||||
}
|
||||
|
||||
// Re-constitute base_ and uri_
|
||||
base_ = frag_ + GetFragStringLength() + 1;
|
||||
SetBase();
|
||||
uri_ = base_ + GetBaseStringLength() + 1;
|
||||
SetUri();
|
||||
}
|
||||
|
||||
// Reconstitute base
|
||||
void SetBase() {
|
||||
Ch* next = base_;
|
||||
std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch));
|
||||
next+= GetSchemeStringLength();
|
||||
std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch));
|
||||
next+= GetAuthStringLength();
|
||||
std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch));
|
||||
next+= GetPathStringLength();
|
||||
std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch));
|
||||
next+= GetQueryStringLength();
|
||||
*next = '\0';
|
||||
}
|
||||
|
||||
// Reconstitute uri
|
||||
void SetUri() {
|
||||
Ch* next = uri_;
|
||||
std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch));
|
||||
next+= GetBaseStringLength();
|
||||
std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch));
|
||||
next+= GetFragStringLength();
|
||||
*next = '\0';
|
||||
}
|
||||
|
||||
// Copy a part from one GenericUri to another
|
||||
// Return the pointer to the next part to be copied to
|
||||
Ch* CopyPart(Ch* to, Ch* from, std::size_t len) {
|
||||
RAPIDJSON_ASSERT(to != 0);
|
||||
RAPIDJSON_ASSERT(from != 0);
|
||||
std::memcpy(to, from, len * sizeof(Ch));
|
||||
to[len] = '\0';
|
||||
Ch* next = to + len + 1;
|
||||
return next;
|
||||
}
|
||||
|
||||
// Remove . and .. segments from the path_ member.
|
||||
// https://tools.ietf.org/html/rfc3986
|
||||
// This is done in place as we are only removing segments.
|
||||
void RemoveDotSegments() {
|
||||
std::size_t pathlen = GetPathStringLength();
|
||||
std::size_t pathpos = 0; // Position in path_
|
||||
std::size_t newpos = 0; // Position in new path_
|
||||
|
||||
// Loop through each segment in original path_
|
||||
while (pathpos < pathlen) {
|
||||
// Get next segment, bounded by '/' or end
|
||||
size_t slashpos = 0;
|
||||
while ((pathpos + slashpos) < pathlen) {
|
||||
if (path_[pathpos + slashpos] == '/') break;
|
||||
slashpos++;
|
||||
}
|
||||
// Check for .. and . segments
|
||||
if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') {
|
||||
// Backup a .. segment in the new path_
|
||||
// We expect to find a previously added slash at the end or nothing
|
||||
RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/');
|
||||
size_t lastslashpos = newpos;
|
||||
// Make sure we don't go beyond the start segment
|
||||
if (lastslashpos > 1) {
|
||||
// Find the next to last slash and back up to it
|
||||
lastslashpos--;
|
||||
while (lastslashpos > 0) {
|
||||
if (path_[lastslashpos - 1] == '/') break;
|
||||
lastslashpos--;
|
||||
}
|
||||
// Set the new path_ position
|
||||
newpos = lastslashpos;
|
||||
}
|
||||
} else if (slashpos == 1 && path_[pathpos] == '.') {
|
||||
// Discard . segment, leaves new path_ unchanged
|
||||
} else {
|
||||
// Move any other kind of segment to the new path_
|
||||
RAPIDJSON_ASSERT(newpos <= pathpos);
|
||||
std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch));
|
||||
newpos += slashpos;
|
||||
// Add slash if not at end
|
||||
if ((pathpos + slashpos) < pathlen) {
|
||||
path_[newpos] = '/';
|
||||
newpos++;
|
||||
}
|
||||
}
|
||||
// Move to next segment
|
||||
pathpos += slashpos + 1;
|
||||
}
|
||||
path_[newpos] = '\0';
|
||||
}
|
||||
|
||||
Ch* uri_; // Everything
|
||||
Ch* base_; // Everything except fragment
|
||||
Ch* scheme_; // Includes the :
|
||||
Ch* auth_; // Includes the //
|
||||
Ch* path_; // Absolute if starts with /
|
||||
Ch* query_; // Includes the ?
|
||||
Ch* frag_; // Includes the #
|
||||
|
||||
Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
|
||||
Allocator* ownAllocator_; //!< Allocator owned by this Uri.
|
||||
};
|
||||
|
||||
//! GenericUri for Value (UTF-8, default allocator).
|
||||
typedef GenericUri<Value> Uri;
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_URI_H_
|
|
@ -67,6 +67,7 @@ enum WriteFlag {
|
|||
kWriteNoFlags = 0, //!< No flags are set.
|
||||
kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
|
||||
kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
|
||||
kWriteNanAndInfNullFlag = 4, //!< Allow writing of Infinity, -Infinity and NaN as null.
|
||||
kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||
};
|
||||
|
||||
|
@ -348,8 +349,13 @@ protected:
|
|||
|
||||
bool WriteDouble(double d) {
|
||||
if (internal::Double(d).IsNanOrInf()) {
|
||||
if (!(writeFlags & kWriteNanAndInfFlag))
|
||||
if (!(writeFlags & kWriteNanAndInfFlag) && !(writeFlags & kWriteNanAndInfNullFlag))
|
||||
return false;
|
||||
if (writeFlags & kWriteNanAndInfNullFlag) {
|
||||
PutReserve(*os_, 4);
|
||||
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l');
|
||||
return true;
|
||||
}
|
||||
if (internal::Double(d).IsNan()) {
|
||||
PutReserve(*os_, 3);
|
||||
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
|
||||
|
@ -548,6 +554,11 @@ inline bool Writer<StringBuffer>::WriteDouble(double d) {
|
|||
// Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
|
||||
if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
|
||||
return false;
|
||||
if (kWriteDefaultFlags & kWriteNanAndInfNullFlag) {
|
||||
PutReserve(*os_, 4);
|
||||
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l');
|
||||
return true;
|
||||
}
|
||||
if (internal::Double(d).IsNan()) {
|
||||
PutReserve(*os_, 3);
|
||||
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
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.
|
||||
|
||||
* [RapidJSON GitHub](https://github.com/Tencent/rapidjson/)
|
||||
* RapidJSON Documentation
|
||||
|
@ -43,7 +43,7 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](
|
|||
|
||||
More features can be read [here](doc/features.md).
|
||||
|
||||
JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at
|
||||
JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in full compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at
|
||||
* [Introducing JSON](http://json.org/)
|
||||
* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159)
|
||||
* [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm)
|
||||
|
@ -72,6 +72,9 @@ Users can build and run the unit tests on their platform/compiler.
|
|||
|
||||
RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path.
|
||||
|
||||
Alternatively, if you are using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager you can download and install rapidjson with CMake integration in a single command:
|
||||
* vcpkg install rapidjson
|
||||
|
||||
RapidJSON uses following software as its dependencies:
|
||||
* [CMake](https://cmake.org/) as a general build tool
|
||||
* (optional) [Doxygen](http://www.doxygen.org) to build documentation
|
||||
|
@ -158,3 +161,50 @@ More [examples](https://github.com/Tencent/rapidjson/tree/master/example) are av
|
|||
* [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread.
|
||||
* [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key.
|
||||
* [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`.
|
||||
|
||||
## Contributing
|
||||
|
||||
RapidJSON welcomes contributions. When contributing, please follow the code below.
|
||||
|
||||
### Issues
|
||||
|
||||
Feel free to submit issues and enhancement requests.
|
||||
|
||||
Please help us by providing **minimal reproducible examples**, because source code is easier to let other people understand what happens.
|
||||
For crash problems on certain platforms, please bring stack dump content with the detail of the OS, compiler, etc.
|
||||
|
||||
Please try breakpoint debugging first, tell us what you found, see if we can start exploring based on more information been prepared.
|
||||
|
||||
### Workflow
|
||||
|
||||
In general, we follow the "fork-and-pull" Git workflow.
|
||||
|
||||
1. **Fork** the repo on GitHub
|
||||
2. **Clone** the project to your own machine
|
||||
3. **Checkout** a new branch on your fork, start developing on the branch
|
||||
4. **Test** the change before commit, Make sure the changes pass all the tests, including `unittest` and `preftest`, please add test case for each new feature or bug-fix if needed.
|
||||
5. **Commit** changes to your own branch
|
||||
6. **Push** your work back up to your fork
|
||||
7. Submit a **Pull request** so that we can review your changes
|
||||
|
||||
NOTE: Be sure to merge the latest from "upstream" before making a pull request!
|
||||
|
||||
### Copyright and Licensing
|
||||
|
||||
You can copy and paste the license summary from below.
|
||||
|
||||
```
|
||||
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.
|
||||
|
||||
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.
|
||||
```
|
||||
|
|
|
@ -1545,7 +1545,7 @@ Don't trust the input data! Check all offsets!
|
|||
Mixed stuff for internal use by loaders, mostly documented (most of them are already included by <i>AssimpPCH.h</i>):
|
||||
<ul>
|
||||
<li><b>ByteSwapper</b> (<i>ByteSwapper.h</i>) - manual byte swapping stuff for binary loaders.</li>
|
||||
<li><b>StreamReader</b> (<i>StreamReader.h</i>) - safe, endianess-correct, binary reading.</li>
|
||||
<li><b>StreamReader</b> (<i>StreamReader.h</i>) - safe, endianness-correct, binary reading.</li>
|
||||
<li><b>IrrXML</b> (<i>irrXMLWrapper.h</i>) - for XML-parsing (SAX.</li>
|
||||
<li><b>CommentRemover</b> (<i>RemoveComments.h</i>) - remove single-line and multi-line comments from a text file.</li>
|
||||
<li>fast_atof, strtoul10, strtoul16, SkipSpaceAndLineEnd, SkipToNextToken .. large family of low-level
|
||||
|
|
|
@ -261,7 +261,7 @@ struct ByteSwapper<T,false> {
|
|||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <bool SwapEndianess, typename T, bool RuntimeSwitch>
|
||||
template <bool SwapEndianness, typename T, bool RuntimeSwitch>
|
||||
struct Getter {
|
||||
void operator() (T* inout, bool le) {
|
||||
#ifdef AI_BUILD_BIG_ENDIAN
|
||||
|
@ -276,12 +276,12 @@ struct Getter {
|
|||
}
|
||||
};
|
||||
|
||||
template <bool SwapEndianess, typename T>
|
||||
struct Getter<SwapEndianess,T,false> {
|
||||
template <bool SwapEndianness, typename T>
|
||||
struct Getter<SwapEndianness,T,false> {
|
||||
|
||||
void operator() (T* inout, bool /*le*/) {
|
||||
// static branch
|
||||
ByteSwapper<T,(SwapEndianess && sizeof(T)>1)> () (inout);
|
||||
ByteSwapper<T,(SwapEndianness && sizeof(T)>1)> () (inout);
|
||||
}
|
||||
};
|
||||
} // end Intern
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace Assimp {
|
|||
*
|
||||
* XXX switch from unsigned int for size types to size_t? or ptrdiff_t?*/
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <bool SwapEndianess = false, bool RuntimeSwitch = false>
|
||||
template <bool SwapEndianness = false, bool RuntimeSwitch = false>
|
||||
class StreamReader {
|
||||
public:
|
||||
using diff = size_t;
|
||||
|
@ -84,7 +84,7 @@ public:
|
|||
* reads from the current position to the end of the stream.
|
||||
* @param le If @c RuntimeSwitch is true: specifies whether the
|
||||
* stream is in little endian byte order. Otherwise the
|
||||
* endianness information is contained in the @c SwapEndianess
|
||||
* endianness information is contained in the @c SwapEndianness
|
||||
* template parameter and this parameter is meaningless. */
|
||||
StreamReader(std::shared_ptr<IOStream> stream, bool le = false) :
|
||||
mStream(stream),
|
||||
|
@ -291,7 +291,7 @@ public:
|
|||
|
||||
T f;
|
||||
::memcpy(&f, mCurrent, sizeof(T));
|
||||
Intern::Getter<SwapEndianess, T, RuntimeSwitch>()(&f, mLe);
|
||||
Intern::Getter<SwapEndianness, T, RuntimeSwitch>()(&f, mLe);
|
||||
mCurrent += sizeof(T);
|
||||
|
||||
return f;
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace Assimp {
|
|||
* stream is to be determined at runtime.
|
||||
*/
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <bool SwapEndianess = false, bool RuntimeSwitch = false>
|
||||
template <bool SwapEndianness = false, bool RuntimeSwitch = false>
|
||||
class StreamWriter {
|
||||
enum {
|
||||
INITIAL_CAPACITY = 1024
|
||||
|
@ -82,7 +82,7 @@ public:
|
|||
continues at the current position of the stream cursor.
|
||||
* @param le If @c RuntimeSwitch is true: specifies whether the
|
||||
* stream is in little endian byte order. Otherwise the
|
||||
* endianness information is defined by the @c SwapEndianess
|
||||
* endianness information is defined by the @c SwapEndianness
|
||||
* template parameter and this parameter is meaningless. */
|
||||
StreamWriter(std::shared_ptr<IOStream> stream, bool le = false)
|
||||
: stream(stream)
|
||||
|
@ -260,7 +260,7 @@ public:
|
|||
/** Generic write method. ByteSwap::Swap(T*) *must* be defined */
|
||||
template <typename T>
|
||||
void Put(T f) {
|
||||
Intern :: Getter<SwapEndianess,T,RuntimeSwitch>() (&f, le);
|
||||
Intern :: Getter<SwapEndianness,T,RuntimeSwitch>() (&f, le);
|
||||
|
||||
if (cursor + sizeof(T) >= buffer.size()) {
|
||||
buffer.resize(cursor + sizeof(T));
|
||||
|
|
|
@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <assimp/vector3.h>
|
||||
#include <assimp/defs.h>
|
||||
#include <assimp/config.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
|
|
@ -44,9 +44,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <cstdlib>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
|
||||
#define TMP_PATH "./"
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define TMP_PATH "/tmp/"
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
#define TMP_PATH "./"
|
||||
inline FILE* MakeTmpFile(char* tmplate)
|
||||
{
|
||||
auto pathtemplate = _mktemp(tmplate);
|
||||
|
@ -60,7 +65,6 @@ inline FILE* MakeTmpFile(char* tmplate)
|
|||
return fs;
|
||||
}
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define TMP_PATH "/tmp/"
|
||||
inline FILE* MakeTmpFile(char* tmplate)
|
||||
{
|
||||
auto fd = mkstemp(tmplate);
|
||||
|
|
Loading…
Reference in New Issue