Merge pull request #1485 from ylavic/MemberMap
Object members stored in std::multimap
This commit is contained in:
commit
47b837e14a
49
.travis.yml
49
.travis.yml
@ -28,59 +28,65 @@ env:
|
||||
matrix:
|
||||
include:
|
||||
# gcc
|
||||
- env: CONF=release ARCH=x86 CXX11=ON CXX17=OFF
|
||||
- env: CONF=release ARCH=x86 CXX11=ON CXX17=OFF MEMBERSMAP=OFF
|
||||
compiler: gcc
|
||||
arch: amd64
|
||||
- env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF
|
||||
- env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=OFF
|
||||
compiler: gcc
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=x86 CXX11=OFF CXX17=OFF
|
||||
- env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=ON
|
||||
compiler: gcc
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=OFF
|
||||
- env: CONF=debug ARCH=x86 CXX11=OFF CXX17=OFF MEMBERSMAP=OFF
|
||||
compiler: gcc
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=x86 CXX11=OFF CXX17=ON CXX_FLAGS='-D_GLIBCXX_DEBUG'
|
||||
compiler: gcc
|
||||
arch: amd64/
|
||||
- env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=ON CXX_FLAGS='-D_GLIBCXX_DEBUG'
|
||||
- env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=OFF MEMBERSMAP=OFF
|
||||
compiler: gcc
|
||||
arch: amd64
|
||||
- env: CONF=release ARCH=aarch64 CXX11=ON CXX17=OFF
|
||||
- env: CONF=debug ARCH=x86 CXX11=OFF CXX17=ON MEMBERSMAP=ON CXX_FLAGS='-D_GLIBCXX_DEBUG'
|
||||
compiler: gcc
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=ON MEMBERSMAP=ON CXX_FLAGS='-D_GLIBCXX_DEBUG'
|
||||
compiler: gcc
|
||||
arch: amd64
|
||||
- env: CONF=release ARCH=aarch64 CXX11=ON CXX17=OFF MEMBERSMAP=OFF
|
||||
compiler: gcc
|
||||
arch: arm64
|
||||
- env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=OFF
|
||||
- env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=OFF MEMBERSMAP=OFF
|
||||
compiler: gcc
|
||||
arch: arm64
|
||||
- env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=ON
|
||||
- env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=ON MEMBERSMAP=ON
|
||||
compiler: gcc
|
||||
arch: arm64
|
||||
# clang
|
||||
- env: CONF=release ARCH=x86 CXX11=ON CXX17=OFF CCACHE_CPP2=yes
|
||||
- env: CONF=release ARCH=x86 CXX11=ON CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: amd64
|
||||
- env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF CCACHE_CPP2=yes
|
||||
- env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=x86 CXX11=OFF CXX17=OFF CCACHE_CPP2=yes
|
||||
- env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=OFF CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=OFF CCACHE_CPP2=yes
|
||||
- env: CONF=debug ARCH=x86 CXX11=OFF CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=x86 CXX11=OFF CXX17=ON CCACHE_CPP2=yes
|
||||
- env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=ON CCACHE_CPP2=yes
|
||||
- env: CONF=debug ARCH=x86 CXX11=OFF CXX17=ON MEMBERSMAP=OFF CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=aarch64 CXX11=ON CXX17=OFF CCACHE_CPP2=yes
|
||||
- env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=ON MEMBERSMAP=OFF CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: amd64
|
||||
- env: CONF=debug ARCH=aarch64 CXX11=ON CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: arm64
|
||||
- env: CONF=debug ARCH=aarch64 CXX11=OFF CXX17=OFF CCACHE_CPP2=yes
|
||||
- env: CONF=debug ARCH=aarch64 CXX11=OFF CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: arm64
|
||||
- env: CONF=debug ARCH=aarch64 CXX11=OFF CXX17=ON CCACHE_CPP2=yes
|
||||
- env: CONF=debug ARCH=aarch64 CXX11=OFF CXX17=ON MEMBERSMAP=OFF CCACHE_CPP2=yes
|
||||
compiler: clang
|
||||
arch: arm64
|
||||
# coverage report
|
||||
@ -93,7 +99,7 @@ matrix:
|
||||
after_success:
|
||||
- pip install --user cpp-coveralls
|
||||
- coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h
|
||||
- env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=ON CXX17=OFF
|
||||
- env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=ON CXX17=OFF MEMBERSMAP=ON
|
||||
compiler: gcc
|
||||
arch: amd64
|
||||
cache:
|
||||
@ -146,6 +152,7 @@ script:
|
||||
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
|
||||
(cd build && cmake
|
||||
-DRAPIDJSON_HAS_STDSTRING=ON
|
||||
-DRAPIDJSON_USE_MEMBERSMAP=$MEMBERSMAP
|
||||
-DRAPIDJSON_BUILD_CXX11=$CXX11
|
||||
-DRAPIDJSON_BUILD_CXX17=$CXX17
|
||||
-DCMAKE_VERBOSE_MAKEFILE=ON
|
||||
|
@ -52,6 +52,11 @@ if(RAPIDJSON_HAS_STDSTRING)
|
||||
add_definitions(-DRAPIDJSON_HAS_STDSTRING)
|
||||
endif()
|
||||
|
||||
option(RAPIDJSON_USE_MEMBERSMAP "" OFF)
|
||||
if(RAPIDJSON_USE_MEMBERSMAP)
|
||||
add_definitions(-DRAPIDJSON_USE_MEMBERSMAP=1)
|
||||
endif()
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
|
15
appveyor.yml
15
appveyor.yml
@ -15,70 +15,83 @@ environment:
|
||||
VS_PLATFORM: win32
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: OFF
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
VS_VERSION: 10 2010
|
||||
VS_PLATFORM: x64
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: ON
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
VS_VERSION: 11 2012
|
||||
VS_PLATFORM: win32
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: ON
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
VS_VERSION: 11 2012
|
||||
VS_PLATFORM: x64
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: OFF
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
VS_VERSION: 12 2013
|
||||
VS_PLATFORM: win32
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: OFF
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
VS_VERSION: 12 2013
|
||||
VS_PLATFORM: x64
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: ON
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
VS_VERSION: 14 2015
|
||||
VS_PLATFORM: win32
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: ON
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
VS_VERSION: 14 2015
|
||||
VS_PLATFORM: x64
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: OFF
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
VS_VERSION: 15 2017
|
||||
VS_PLATFORM: win32
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: OFF
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
VS_VERSION: 15 2017
|
||||
VS_PLATFORM: x64
|
||||
CXX11: OFF
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: ON
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
VS_VERSION: 15 2017
|
||||
VS_PLATFORM: x64
|
||||
CXX11: ON
|
||||
CXX17: OFF
|
||||
MEMBERSMAP: OFF
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
VS_VERSION: 15 2017
|
||||
VS_PLATFORM: x64
|
||||
CXX11: OFF
|
||||
CXX17: ON
|
||||
MEMBERSMAP: OFF
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
VS_VERSION: 16 2019
|
||||
VS_PLATFORM: x64
|
||||
CXX11: OFF
|
||||
CXX17: ON
|
||||
MEMBERSMAP: ON
|
||||
|
||||
before_build:
|
||||
- git submodule update --init --recursive
|
||||
- cmake -H. -BBuild/VS -G "Visual Studio %VS_VERSION%" -DCMAKE_GENERATOR_PLATFORM=%VS_PLATFORM% -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=true -DRAPIDJSON_BUILD_CXX11=%CXX11% -DRAPIDJSON_BUILD_CXX17=%CXX17% -Wno-dev
|
||||
- cmake -H. -BBuild/VS -G "Visual Studio %VS_VERSION%" -DCMAKE_GENERATOR_PLATFORM=%VS_PLATFORM% -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=true -DRAPIDJSON_BUILD_CXX11=%CXX11% -DRAPIDJSON_BUILD_CXX17=%CXX17% -DRAPIDJSON_USE_MEMBERSMAP=%MEMBERSMAP% -Wno-dev
|
||||
|
||||
build:
|
||||
project: Build\VS\RapidJSON.sln
|
||||
|
BIN
bin/types/alotofkeys.json
Normal file
BIN
bin/types/alotofkeys.json
Normal file
Binary file not shown.
@ -16,6 +16,7 @@
|
||||
#define RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/meta.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -158,6 +159,7 @@ class MemoryPoolAllocator {
|
||||
|
||||
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.
|
||||
@ -417,6 +419,16 @@ private:
|
||||
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)
|
||||
@ -437,7 +449,6 @@ 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
|
||||
@ -601,6 +612,7 @@ public:
|
||||
|
||||
//! 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);
|
||||
|
@ -46,8 +46,8 @@ RAPIDJSON_DIAG_OFF(effc++)
|
||||
#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
|
||||
@ -732,18 +732,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 +869,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();
|
||||
Allocator::Free(e);
|
||||
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:
|
||||
Allocator::Free(const_cast<Ch*>(GetStringPointer()));
|
||||
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
|
||||
Allocator::Free(const_cast<Ch*>(GetStringPointer()));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1265,10 +1260,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;
|
||||
}
|
||||
|
||||
@ -1342,11 +1334,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); }
|
||||
|
||||
@ -1375,14 +1363,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;
|
||||
}
|
||||
|
||||
@ -1516,9 +1497,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.
|
||||
@ -1562,14 +1541,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.
|
||||
@ -1601,13 +1573,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.
|
||||
@ -1858,12 +1824,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.
|
||||
@ -2112,6 +2078,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); }
|
||||
@ -2119,6 +2092,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;
|
||||
@ -2136,9 +2389,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);
|
||||
@ -2259,6 +2519,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();
|
||||
}
|
||||
|
||||
|
@ -162,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
|
||||
|
||||
@ -578,6 +596,10 @@ 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 RAPIDJSON_HAS_CXX11
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
|
||||
|
@ -130,7 +130,8 @@ public:
|
||||
"integers.json",
|
||||
"mixed.json",
|
||||
"nulls.json",
|
||||
"paragraphs.json"
|
||||
"paragraphs.json",
|
||||
"alotofkeys.json"
|
||||
};
|
||||
|
||||
for (size_t j = 0; j < sizeof(typesfilenames) / sizeof(typesfilenames[0]); j++) {
|
||||
@ -158,7 +159,7 @@ public:
|
||||
free(whitespace_);
|
||||
json_ = 0;
|
||||
whitespace_ = 0;
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
free(types_[i]);
|
||||
types_[i] = 0;
|
||||
}
|
||||
@ -174,8 +175,8 @@ protected:
|
||||
size_t length_;
|
||||
char *whitespace_;
|
||||
size_t whitespace_length_;
|
||||
char *types_[7];
|
||||
size_t typesLength_[7];
|
||||
char *types_[8];
|
||||
size_t typesLength_[8];
|
||||
|
||||
static const size_t kTrialCount = 1000;
|
||||
};
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "rapidjson/memorystream.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef RAPIDJSON_SSE2
|
||||
#define SIMD_SUFFIX(name) name##_SSE2
|
||||
@ -52,7 +53,7 @@ public:
|
||||
// Parse as a document
|
||||
EXPECT_FALSE(doc_.Parse(json_).HasParseError());
|
||||
|
||||
for (size_t i = 0; i < 7; i++)
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
EXPECT_FALSE(typesDoc_[i].Parse(types_[i]).HasParseError());
|
||||
}
|
||||
|
||||
@ -68,7 +69,7 @@ private:
|
||||
protected:
|
||||
char *temp_;
|
||||
Document doc_;
|
||||
Document typesDoc_[7];
|
||||
Document typesDoc_[8];
|
||||
};
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler)) {
|
||||
@ -335,6 +336,23 @@ TEST_F(RapidJson, DocumentAccept) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, DocumentFind) {
|
||||
typedef Document::ValueType ValueType;
|
||||
typedef ValueType::ConstMemberIterator ConstMemberIterator;
|
||||
const Document &doc = typesDoc_[7]; // alotofkeys.json
|
||||
if (doc.IsObject()) {
|
||||
std::vector<const ValueType*> keys;
|
||||
for (ConstMemberIterator it = doc.MemberBegin(); it != doc.MemberEnd(); ++it) {
|
||||
keys.push_back(&it->name);
|
||||
}
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
for (size_t j = 0; j < keys.size(); j++) {
|
||||
EXPECT_TRUE(doc.FindMember(*keys[j]) != doc.MemberEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NullStream {
|
||||
typedef char Ch;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user