From 3a6302a020defdb1aa084cf624e1891c3172bd4d Mon Sep 17 00:00:00 2001 From: ylavic Date: Wed, 10 Apr 2019 19:14:37 +0200 Subject: [PATCH 1/4] Add std::allocator concept to CrtAllocator and MemoryPoolAllocator. Introduce the new StdBseAllocator class, inherited by both allocators, which allows to pass rapidjson's allocators to standard containers used internally. StdBaseAllocator also provides the new Allocate() and Reallocate() helpers which allow to simplify allocation code like: value = static_cast(allocator.Malloc(sizeof(Value)); newValues = static_cast(allocator.Realloc(oldValues, oldCount * sizeof(Value), newCount * sizeof(Value)); to: value = allocator.template Allocate(/*1*/); newValues = allocator.Reallocate(oldValues, oldCount, newCount); which is a common pattern in rapidjson. This commit makes this change only in "rapidjson/document.h" only for now, though. --- include/rapidjson/allocators.h | 135 ++++++++++++++++++++++++++++++++- include/rapidjson/document.h | 14 ++-- include/rapidjson/rapidjson.h | 2 +- 3 files changed, 139 insertions(+), 12 deletions(-) diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h index cc67c8971..6de4abd48 100644 --- a/include/rapidjson/allocators.h +++ b/include/rapidjson/allocators.h @@ -17,6 +17,11 @@ #include "rapidjson.h" +#include +#if RAPIDJSON_HAS_CXX11_TYPETRAITS +#include +#endif + RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// @@ -64,6 +69,117 @@ concept Allocator { #define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024) #endif +template +class StdBaseAllocator { +public: + typedef ValueType value_type; + + typedef value_type* pointer; + typedef const value_type* const_pointer; + + typedef value_type& reference; + typedef const value_type& const_reference; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + template + struct rebind { + typedef StdBaseAllocator other; + }; + + StdBaseAllocator(Allocator &allocator) RAPIDJSON_NOEXCEPT : + allocator_(allocator) { + } + + StdBaseAllocator(const StdBaseAllocator& other) RAPIDJSON_NOEXCEPT : + allocator_(other.allocator_) { + } + + template + StdBaseAllocator(const StdBaseAllocator& other) RAPIDJSON_NOEXCEPT : + allocator_(other.allocator_) { + } + + size_type max_size() const RAPIDJSON_NOEXCEPT { + return static_cast(-1) / sizeof(value_type); + } + + pointer address(reference x) const RAPIDJSON_NOEXCEPT { + return &x; + } + const_pointer address(const_reference x) const RAPIDJSON_NOEXCEPT { + return &x; + } + + pointer allocate(size_type n = 1, const void* hint = 0) { + static_cast(hint); // unused + return Reallocate(NULL, 0, n); + } + + void deallocate(pointer p, size_type n = 1) { + static_cast(Reallocate(p, n, 0)); + } + template + void deallocate(OtherType* p, size_type n = 1) { + static_cast(Reallocate(p, n, 0)); + } + + void construct(pointer p, const_reference r) { + ::new(static_cast(p)) value_type(r); + } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + template + void construct(OtherType* p, Args&&... args) { + ::new(static_cast(p)) OtherType(std::forward(args)...); + } +#endif + + void destroy(pointer p) { + p->~value_type(); + } + template + void destroy(OtherType* p) { + p->~OtherType(); + } + + // Rapidjson's style + template + OtherType* Allocate(size_type n = 1) { + typename rebind::other a(*this); + return a.Reallocate(NULL, 0, n); + } + template + OtherType* Reallocate(OtherType* old, size_type old_n, size_type new_n) { + typename rebind::other a(*this); + return a.Reallocate(old, old_n, new_n); + } + pointer Reallocate(pointer old, size_type old_n, size_type new_n) { + RAPIDJSON_ASSERT(sizeof(value_type) == 1 || new_n <= max_size()); + return static_cast(allocator_.Realloc(old, old_n * sizeof(value_type), + new_n * sizeof(value_type))); + } +#if 0 && RAPIDJSON_HAS_CXX11_RVALUE_REFS + template + OtherType *New(Args&&... args) { + typename rebind::other a(*this); + return a.construct(a.allocate(1), std::forward(args)...); + } + template + void Delete(OtherType *p) { + if (!p) + return; + typename rebind::other a(*this); + a.destroy(p); + a.deallocate(p); + } +#endif + +private: + StdBaseAllocator() /* = delete */; + template friend class StdBaseAllocator; // OtherType::allocator_ + Allocator &allocator_; +}; /////////////////////////////////////////////////////////////////////////////// // CrtAllocator @@ -72,9 +188,15 @@ concept Allocator { /*! This class is just wrapper for standard C library memory routines. \note implements Allocator concept */ -class CrtAllocator { +class CrtAllocator : public StdBaseAllocator { + typedef StdBaseAllocator StdBaseAllocatorType; public: static const bool kNeedFree = true; + + CrtAllocator() RAPIDJSON_NOEXCEPT : + StdBaseAllocatorType(*this) { + } + void* Malloc(size_t size) { if (size) // behavior of malloc(0) is implementation defined. return std::malloc(size); @@ -112,7 +234,8 @@ class CrtAllocator { \note implements Allocator concept */ template -class MemoryPoolAllocator { +class MemoryPoolAllocator : public StdBaseAllocator > { + typedef StdBaseAllocator > StdBaseAllocatorType; public: static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) @@ -121,7 +244,9 @@ class MemoryPoolAllocator { \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + StdBaseAllocatorType(*this), + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), + baseAllocator_(baseAllocator), ownBaseAllocator_(0) { } @@ -136,7 +261,9 @@ class MemoryPoolAllocator { \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) + StdBaseAllocatorType(*this), + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), + baseAllocator_(baseAllocator), ownBaseAllocator_(0) { RAPIDJSON_ASSERT(buffer != 0); RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index d1b90eb0b..934e50356 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -653,7 +653,7 @@ class GenericValue { switch (rhs.GetType()) { case kObjectType: { SizeType count = rhs.data_.o.size; - Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); + Member* lm = allocator.template Allocate(count); const typename GenericValue::Member* rm = rhs.GetMembersPointer(); for (SizeType i = 0; i < count; i++) { new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); @@ -666,7 +666,7 @@ class GenericValue { break; case kArrayType: { SizeType count = rhs.data_.a.size; - GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); + GenericValue* le = allocator.template Allocate(count); const GenericValue* re = rhs.GetElementsPointer(); for (SizeType i = 0; i < count; i++) new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); @@ -1178,7 +1178,7 @@ class GenericValue { GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsObject()); if (newCapacity > data_.o.capacity) { - SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); + SetMembersPointer(allocator.Reallocate(GetMembersPointer(), data_.o.capacity, newCapacity)); data_.o.capacity = newCapacity; } return *this; @@ -1614,7 +1614,7 @@ class GenericValue { GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsArray()); if (newCapacity > data_.a.capacity) { - SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); + SetElementsPointer(allocator.Reallocate(GetElementsPointer(), data_.a.capacity, newCapacity)); data_.a.capacity = newCapacity; } return *this; @@ -2034,7 +2034,7 @@ class GenericValue { void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { data_.f.flags = kArrayFlag; if (count) { - GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); + GenericValue* e = allocator.template Allocate(count); SetElementsPointer(e); std::memcpy(static_cast(e), values, count * sizeof(GenericValue)); } @@ -2047,7 +2047,7 @@ class GenericValue { void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { data_.f.flags = kObjectFlag; if (count) { - Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); + Member* m = allocator.template Allocate(count); SetMembersPointer(m); std::memcpy(static_cast(m), members, count * sizeof(Member)); } @@ -2073,7 +2073,7 @@ class GenericValue { } else { data_.f.flags = kCopyStringFlag; data_.s.length = s.length; - str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); + str = allocator.template Allocate(s.length + 1); SetStringPointer(str); } std::memcpy(str, s, s.length * sizeof(Ch)); diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 549936ffe..2a0400e6d 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -567,7 +567,7 @@ RAPIDJSON_NAMESPACE_END #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT noexcept #else -#define RAPIDJSON_NOEXCEPT /* noexcept */ +#define RAPIDJSON_NOEXCEPT throw() #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT // no automatic detection, yet From 434dd354e91eda1c0f29e518294bc2d2a9ba56ed Mon Sep 17 00:00:00 2001 From: ylavic Date: Wed, 10 Apr 2019 20:30:09 +0200 Subject: [PATCH 2/4] Make use of an (std::multi)map for object members, if #defined. When RAPIDJSON_USE_MEMBERS_MAP is #defined, an object Value will store its members in an (re)allocated array of Member(s) like before, but also in an std::multimap where the key and value reference the corresponding Member by its name and index in the array, respectively, and in a relocatable manner. The layout of the members map/array is now: {multimap}<>{capacity}<>{Member[capacity]}<>{multimap::iterator[capacity]} where <> stands for the RAPIDJSON_ALIGN-ment of each part, if needed. This layout needs to be reallocated when the current capacity is exhausted, which requires to take care of the multimap and its iterators explicitely; the former (likely not a POD) can simply be saved/restored by swapping (twice), and the old/alive iterators must be moved to their new offset (according to the new capacity). With this in place, it's immediate to get the multimap::iterator from a MemberIterator and vice versa, thus Find/Remove/EraseMember() working on a MemberIterator keep the same complexity (O(1) for find/remove, and still O(n-m) for EraseMember() due to the move/copy). For operations by name, the lookups complexity switches from O(n)/linear to the multimap's, usually rbtree's logarithmic/O(log n), including for AddMember() which without RAPIDJSON_USE_MEMBERS_MAP is otherwise O(1). Consequently parsing will be slower, up to ~20% measured in perftests on my laptop (since it's mainly composed of insertions). But later work on the Document [usually the goal of parsing...] will be much faster; the new DocumentFind perftest included in this commit is 8 times faster with RAPIDJSON_USE_MEMBERS_MAP (still on my laptop). Overall the tests are 4% slower (mainly composed of parsing), and notably 15% slower for schemas parsing/validation (which supposedly comes from the larger JSON files parsing, still). As a side note, when RAPIDJSON_USE_MEMBERS_MAP is not defined, this commit does not change the perfs (same results for perftest with regard to previous version). Finally, the multimaps are allocated/constructed on/with the Value's Allocator (thanks to StdBaseAllocator), so they are integrated into the memory model like the native classes, and thus will benefit from the same performance/safety/security/whatever provided by the user given Allocator. --- bin/types/alotofkeys.json | 502 ++++++++++++++++++++++++++++++++ include/rapidjson/document.h | 344 ++++++++++++++++++---- test/perftest/perftest.h | 9 +- test/perftest/rapidjsontest.cpp | 22 +- 4 files changed, 817 insertions(+), 60 deletions(-) create mode 100644 bin/types/alotofkeys.json diff --git a/bin/types/alotofkeys.json b/bin/types/alotofkeys.json new file mode 100644 index 000000000..3fc052e34 --- /dev/null +++ b/bin/types/alotofkeys.json @@ -0,0 +1,502 @@ +{ + "4BABQZ5SZJSO3KFKBOG36EIXXTOF34HVFCELHA2DWOMIL44K": null, + "RSZNOTRIJFCHRKG4IKNOW4ZEBMVXPDBYBXBGDGNWTSVLMJ2U": null, + "AOGQPY32FQ7T7WZWQPON3X6GU74GOYI6HHVNPATDTBXRUQ4G": null, + "3PMTZEGLZNHSOWWJ23BE6PWOXD2VZRDN7MMLUMQ4EIRERVCG": null, + "PD2FMQGI5HTGK6MT76OYS2ER2LXFBON44WOMELDY5MRKQI6I": null, + "6L6QMMVSE4UQLB4OGX3LVDRNGAL6MOJ6S3RBBUSQ3F5PPHYR": null, + "LYVVXT7U7WN7PGGUHCLFXVOBJBSSR6ES2P7AY7XGBXEBLTDD": null, + "G5RWOLHDDZOXYEFGGSVWG3C2UHYDW6UOFVBQQLQJVZNCF4TB": null, + "3QPIK2M3ZPICZQFQTX22A7VDCAFIGAX2PXIXKDOZX7XUM32R": null, + "JR75L2BXOA5LVLNKT4EEZO2P45OHWRPMMWMFENTFFIY7A2V3": null, + "TESL546MN7IR7AT3C5HRSESIFHZ5NW6TNRWZXZ43OSRYOZKP": null, + "62EJKIAFWGFGPUS6YP2X6E26AV2TZCTCAJMZNWBBNFRPCCRN": null, + "5ZDD3KPTPGE2CAWR3MTFUSBMGQAS4ZP5WZKXJTXUNFSYABD6": null, + "XQ7TMN5YMQLAND54B4VIVWJAHU3TNZKT2S4SVRW6WKHNJBX2": null, + "O456GV3HBAWFDQRCECX6HY3PBTP6WNQIDSKVP2MZIPV3TCBL": null, + "WXCN25EBQH5WWN2JBHWNFNDUTYSFDLIAOWO5AE6D5HDO7VNE": null, + "THO3I3KDRIMTD6DKNIETIOWDY7FXQ5GJ3P2KUQJWYAEL3LXV": null, + "7OMI7VIOKFRZATMNLGIWH7ZBDARZ6ARXIAH5S3GPG5KV52IC": null, + "ESUPY3ELKCEGFRSYFGPGFBJOAUGXMYZ6XCWXDFOKHBJHNGVR": null, + "TNXSJIEFJLUFUDTR2S5LV73PD6ACFYNHOCRZPUSDPXDD3B7M": null, + "T6TISG6P4W66F37634QU4BNJY4RZ77QXXNPGTYH5LCCRDSX6": null, + "QTVAA56JKNDYTMV7DXAIL4QVLZPW3UHGLTKDI2BED6S3MGDQ": null, + "DTJREAQBCS6I2AJ6MOGTPIXK3ADB4BPNDIHI2YSQP6Y2BMH7": null, + "XDGH2OYCTAJ75IEMZ32O644YLT73PRYDORFKBLYEMCHOQ7Q6": null, + "4KDDQZRBLNS33DRHZHDMENCWGMNFEJGBZJXSGIQW7VBWOTHT": null, + "5KSH3GKWFNXV55KI2FPUDSD57O25N52UTZAAYDFVMFUSEE6O": null, + "7AGEUBM5FQZ2JCMUSKTEI6COA3Q5CE5WYB7TP2F5OX3ETMTK": null, + "HFHZ5ZE5TC45W4WIF6H7ONTHXKAVWRY2LXN2GN2TXZPIP6PQ": null, + "S3U2JJBPKZHZNOM3SWVFQ7OMS7F5M2KDJHHHZKXHZXQRNUSE": null, + "YHJBGJ6T6A7PMK5AYXDITDV37BJJIM4TP7I2XHSVYN76724O": null, + "TH42A7M3645OUKC54JQMDB5BTGS3URFUCYJ2VOEM6IAGZ5QQ": null, + "OYBKULFLWL2MER745QTDL2X2HJNR77QGH2M2P6TSCHVGUJLV": null, + "JDU37GHQUOCYA5I5LFS3WAEKKR6C55XJCCLJCCCQJEGUJEP6": null, + "CB5HEJZNJ2SWZM426TWIWLHTWAPWPT2AVVHBILEVGFD6NPHI": null, + "D4A5SJA2VRB4JGJFC7PHT35S7XAMHPZZ2PZC5YYVV7RLKSUQ": null, + "BBVT6NRRU55KNRK5G745FNMZVIFHVZJICEMODF4ZBJFQ3EGL": null, + "XBV57OEMT4GYPTTH56A6XKF2ZPMXSMHY7L3LUIS5ZZWRP2OB": null, + "GTFJ3NP4VJR6HG2DRNTDKVIWTMIALYUQIQTBJMKVM2I3QKGE": null, + "77BMBFMRGASXE5XXT6BRH2DRBNJMIAUDDMEXIJT3RMHTUPI4": null, + "FWZZMG7I2JWAHX4LBYAK2G4L4TZYLHXMJWIDGT6JC5TEBCPJ": null, + "J3324OXU2BG2NGFMSOYMVKXE6OEJNGENI7EESHDSEWSUVDVV": null, + "C636AVNC5C5EKILXT2AQPXYLSNH7LCAJKVDHP67MVHULFSQN": null, + "OXTDOQG2VIEVYFC23SKOBSSPGE55AVZZADK6PIHP3APVPHND": null, + "JLQVKV4Q2BQHK355NQXZVX4WJBPFOWSD7WIJX2P433KYO4SO": null, + "E4XHPOPWH3PRCV5MGQHR3BCTKZMOK46OH4Q6STZDPF2FG6SD": null, + "J5IP4A3DV3BHGGU3J72JVVTWNIQOLNC6GQES22MVATK5H7BZ": null, + "HHCCDMLNGOU2ABP57ION5TC33UF3NUHL2L3WUYCGZDWLDNTL": null, + "54Q67RURG4THOANPT3RAVF72TGKJE425GC5GD3EOKPY6MKVW": null, + "TG3BH3HBKFEXAUM5O67VVDTXZA6MHWSVNNLXLXIL2SE2ZEDO": null, + "Q5KJ25G2A4CWNGPPYXBZM6QVYA466MQX3HCUMUO5Z24D5JX3": null, + "QQZET7VFHGJROUQZSWSRDI5ADXVH26KEPDVL6PZ36ISHOKMQ": null, + "KWNJME4V365ZIC7SA7BYCVQUAG6URC2T6MHSO3OVDBJAUPFB": null, + "XHQYKGYVLE2PFNXQPD4OUWBASZO5OFVZISCVEFTU6K6KDKHS": null, + "Z4SPXMJIAMYD2H4U4F23FALBDZP6NRLUBDFU4PRGZ4SXGTI2": null, + "HSCK3PEXH3I3XMMEMIHTM7SDJD3GOKXUMCGOL6UXJXLCSCGN": null, + "BIUYMIDY4EVGRLZ6OLJK2CE2FS5TTELIWSEA6UHKUDUYX5LM": null, + "IJJDLN5ANXTMX54P6GW2J2EJGGWG257YEAOZMXUSWK7D76LH": null, + "CLMTO3VSAOBAOBSA5IGOO4W7KEMLOFUOIR564IBKMJA7RWEY": null, + "JU5DNSHLUW34DT3IQ36JBV6M7EPILLMBALURDAB2KJXF6HQB": null, + "VXZXWLNQZFJPNQVPTOFWUPLORZD2XRAFXRVRNLUYTPBO22U5": null, + "HNACM55ZSGJ2FGRMOTXLVVLA32BC333QGC4HFCDSZ335YA4N": null, + "6J5GIOVKU4PKHHU35DWL3D7GTJFF75FF4FKSP2HPGJ7SQ2DP": null, + "O3NJM537IQSKKWM3K7EOQSNQDTR6XKUA7ZR7CWYHYYLHKH63": null, + "B4QMXK2EAR5E7KGHLODCP56DX5HW7IQVXWHFFCZ4SPSSNGJK": null, + "A5AUZBXKF67OXO34ZSEGVXI5PAIG6W2VG3U5C2Q72SNWYNEI": null, + "ZGDQ2AA2IFBSU3APKAFL5AO4C4DXY2YBEHXE5UPPVCTFZ36K": null, + "N3XZ5FYZEO3ZX37OMUJX3PIWEEV7TVEXX64KKEZEJICKXMTB": null, + "3EVOEEWTD7OABLQJIJYLOSVHBS4SB6QGX7GPDFGWI2DGAWKR": null, + "HNAEL3D7E2S7IYLKLIK4CGI56DRGAXA5S6KG3RX75PMJ6BVI": null, + "VGVW32CIRX3M45J2CPCUPPHNRGNG55MKAU7YF3CDNMGONW2T": null, + "QV5MW2W6WQSHNC6OYMWJAWEQM7LHXRMGWCJ7RI5WQ3JGHARW": null, + "IND2PUTLFWXTEUY4MMEXCFJA7JN7DODE5HVWC5CL5ED5IEUB": null, + "W2IA75XHJRBRKXLHGB7LXD7ECYEZI4V5N5I37UFXJMFWQMYR": null, + "AWTZO6OG6TCOUVYYJCWVP2JYEXRXZ7S7F7QKUKZS7JLPKN3H": null, + "TCARJATK42Y66SPMGOZ2LHLT2ZPZW7MHGXL5IVTS272FJV4U": null, + "XVHBOY5WQDOTWXVFZYQKZ6GNRWMITJDDLXSJ2T3UWF6PFOHL": null, + "CY5FGDYLB4UFR4AJRGLGPQT3W3OERGCXC4JHYKJ4HKSFTGK6": null, + "B3SJGD67GKIEAOZISX7HWENPDBYJHNJ47JCREGXQ6G2RXPUZ": null, + "LWVJYH7M5KXMLPFAHTMF6FKT3PSIW2GRC37AHF65PQY7OUE4": null, + "UUFKWC2DOV4ZQHPDPQPRCBEYNAX6OFZ7ZVJNYGW5YZCMSQIS": null, + "K5EC26CUN365DZ3LE2NHOINGZHXQ752A3VTPN5IMSRYSTOMT": null, + "22RV6RSSZIAFXOZIRAWJAIMMVHYWGL2TY42U3TG2SPFN3I6P": null, + "Q7VEOUC52OLXL53CR4XQSGGR5QZ2QXZTRCBACHQFP2HKN4SZ": null, + "OZ2ZBCTBC32VOHHBDABY2U462OHUEUS724RUS7Z6TW5K5ZFQ": null, + "EYXYWTX2UYI6MUK5L65WSTX2FDOJASIMG6ER22NLABNGAEMI": null, + "U4FJU7RQMXXDMHG7B5WFLXCZBNE5PMV43CE5X4RJSJUABT3U": null, + "K3T56AL7IXTAGTVIWZHYRKVPHLLD7UVHV4UNU76F764VGY75": null, + "U2BRKWY2RBYV5S3XVZTUZXT55CXMB45KDMNFMVY6LENW2DH5": null, + "YKLPZ7SDAG2O6NSJFLVGFVCYMY4WZKXQGHH7OO2BKGGVLQNP": null, + "WSC2BHA7H6Q62HJIIGQFX2OU64QX4AEU2RZQVIC7LSIO2JSJ": null, + "QIFNFKPJJCYPITMAYDAOEXBVEDAKBBR3DV5ZB7DAVBIAWI5K": null, + "NMBGIDIK3BMS5ZPZS6ATTID5BOAXZAH2VUED52JSC5XGI42P": null, + "LTSG7BGZVBLLXM5U2QDW5LNNPM3B5EQZPHES7JXU2EAQG266": null, + "5MZMVLLM7YHR4PTQCGDGWFQQLNN532WMTFGX5CFTDURBYEOH": null, + "UOMT2ERDBVXC3LRYKCVVUNROBWPGFHFWKFCW65HAPXN2H4FD": null, + "RFYZPAIVYHTITTR5AKOBAMYKOA3VSKRTK4P4ZOS7JFSVEY53": null, + "QQJGQV6BSW6PL4DZGQDWWVTF7U5MEVPQABOA4IRP7NOD4V4V": null, + "EFOSJBHVPSGTB3O374JFJW6MVW47ODOZQNKYSWHR5W6UZECP": null, + "YTL42MLIGIUD6Q3AMVMJ6ZMWNSXSUWCKV4ZUQWSGTEOATQC4": null, + "F5IL5OV3Y6E4QEE7JMQTKV6ULJ5AQQKQPZ23VXK72AV2P7XG": null, + "AZEV37T65EWVWQJSISCHTYHLWRXWCR6XD4LJ4KFLJ6RAOPF5": null, + "T5TAAFPNZLVDYHSNNHIJW4KBZWNFT5CMIPIWW3EFKPU4REYG": null, + "W326OLSKXRLU6MEIVUTKFFHFGXEH3VM43F353L3NHQP6HE2Q": null, + "MIIUZQ4KGTLA66VIE7WPN4T43SR6Q42YUKWEP6467AYWKU62": null, + "AXSJHLTL4FXCMLLJTQS4HIBRGUY6ATR3GZPV4MGXLWNFHDYU": null, + "MC2CMWSKD2HMTVIWCMSPZWHEGW73RWEZKU3IFZJM33IW3VI6": null, + "ZGOZHC22WZN6LSY3KK4HK6RF6F73VWSB7U47KZSLTYOQZAVH": null, + "HU26VJYM5YNEXCOCWCVEQNNZ2WAPFEVYK67JZOHMSZIOUWJN": null, + "6ZA46O27SWCAX5MQUHZYFV5UNQUDLZG4LDA6VILK6YRQMMZ5": null, + "LMGGW3CAN4T6DSVJZB46LOBI6KTZN7CKHNZ6BMWRBL5PVYXX": null, + "RZKIP3F5SY2P4NWANAQZJHPH34CU3GMQ4VCN4QXMP7ZBSQ43": null, + "CMUAX53FME5Y62VC7T7ZOUZMOPHBDFVLMVVMHYDDBZEHMOOA": null, + "ORTA47K5MLIHEUXQTFFTQNW2RMYQSTVDJXUNIF334SAJJYMC": null, + "XEGLAWIOOPE25FDXHN65P4FYJVB46M4NGGXFAWZ5VDWBBMU4": null, + "WZGXOCCN6GENKYYAYCH6UQD45BIPSYMQOZYAYRU3S2JNJLU3": null, + "MXDDSZA6VTTYU56ONDE4QZMB3L2D7A5SCRCIVBYYVIKFDFLU": null, + "JJMW475CTRXRR4R3GEZ77STHMKHTQZYFZHFUFXEB77SV2W3H": null, + "J3TNJVNF7QSTIJDEEZMLTQECNOES4PXQALSR5ZPYDTIVVKUB": null, + "Q5EHPI6GHPPZBATKHYYEXNDSYMW6QVAVKKHC2XO7RU7XXKQ3": null, + "B6WGKJEZH7XBZ4VFFRCBFYKC2Z2ZQXMY2HJQUH4LVI3EDMMU": null, + "NZ737IT3LUIMH56R66WFETEHFDOZSNVPTHMQTW3JHVTN562C": null, + "B52PWLRNPFN73AA63O6JFLEYSPFQEIHQ6AI6YC7KWOYFE5OW": null, + "7UTTRFE2I5WB2XZA37L6F7RWCII6S6HLXZRTLSJYFOENAYPI": null, + "TJJDGG7R4RNVAOXWRZRZB5K7W2Y6XB7LUYBDOY6H5IDRM3ML": null, + "TOG35JU7ULNRY3DE2XYDZ25WZETRSO5WSFFYSZT5IIALO3ZP": null, + "2QZKK4CMZNIKUWZZB22ASDR2BYNRAMTNS7MVLBA7Z7RDKZDV": null, + "US4C6FXHKR4GCRU6IJQHSAJXLNQGUDCDEPEQDU5C5D76I6XX": null, + "QOPUXM3ZKXTPVGMVVDMUZZ75KH2S7DKYXSFCQ3R5RYO5WP2J": null, + "GZ2T37SKRE3ZX7FARFWWF3WG443LVP5X6ENDLDHO7GBWYHHM": null, + "VSOOUSBMGIPEVAPYAGWZOLDUW5HSTRMTBRTUYLQNHKVUBLJ7": null, + "45HJFJQ3YKDBFDZPNDO46YT7DLG754XZWMGJQ7YPJXQ4G4N4": null, + "4KY77KV2OWWFEVIBSUZRGZF2V47BEFFHIHNMAQVK65E34ZF3": null, + "NB334WI2DNPLWHGXBNHSU4436ZYDQ4D2S3JMLDOM35QINZTR": null, + "7K23M4FJGIQFWUMPRDZIK32MF7HZULYYSS5Z7N7QTEJGET3D": null, + "ZBMNFKSEG2PXKJZIXIK2MHJQ2ONRJUJVCDBOCHNERPGMN2NQ": null, + "YMCOX2NMBDL4J6Z7JBEWHFSCWON4ZSBSBU2WONEYYOYRA75K": null, + "GDOVKPAWZFHLAPQ5YHCFWL4NAMC5G2DDXFWUTR27XQ7LEOOQ": null, + "CYBYK7ESXTUUHYQVPMDI7VWAZO5TVGLIB3GB7NYRYVDLMYKG": null, + "4IYLX3IDNUJ2DWT4RM3QJ3IMVE22X67EW5KWSMZHIU4W2W5B": null, + "EBWXJZ3PX7LE4JNB2XWJJNXL5QBVSJQSXAUJMJ34YJKR3JJU": null, + "LEKOXMXHU57JTRZUKMCW4WDCAKEOXPHJ34ULXN5P6DIEOYLL": null, + "BESPMR4LBE3G4MTWR22CVBYH6NW43HO4ILTSV3P543JZUBD7": null, + "5SYIBXIHGJGE4WHL2HYUNK3X4JUGOJOUMKVJMMXSQDKJZHFJ": null, + "XN42HP3QOV34GMJA5VINVW3O7KWW2GV7VDKAZDFBCC6SSHNQ": null, + "326BDEDWGYW3IMEHP63I6LVGSRMS6DUUNMPY3YVWXCH3YA67": null, + "FYNTVFBPC37FYGOXFIXJP57FNX5MYDGUWIMUYMFOJSOXRRDS": null, + "7DRCBIQP4EXAVNEMWOZHAEZ2W2EIMKD77PH6JJWP2BDN6NFN": null, + "7Z7LWVFB2Z26EVYZPLQAOQ7LXLADTHUA7QGKDRFLXRQ3ZJUX": null, + "EOZ2S4T75U62LD4QUZNTOHP7SNVJUNNSE7WWGHCMC75O4XPW": null, + "TVG4ZY3YVNQV7WPZ2CEW26QTGWUBVJV7FTRF4TE54446J5SI": null, + "MQ62OHPXMGGASRXKOH5MEVGLYHKNWBT3DC7XSXPXFHFXFO5C": null, + "MBRTEJLOZ6U43EOO2IS3AHNDCT7WUEK4XN5ZRMTPBKUFXUWU": null, + "24WJGDPNT4E7SQT2IBSTHJGYBMEBKS7VPGJYBRRAT5YXNBC4": null, + "3KD7I6FOTRB4U2JBT7CIJOPD5XHFWHESYJJQTQVUQ3IGIPVZ": null, + "25XHQ7A3DWKVDBX2ZFNIHKOGJCXY73N4Q6PUBEWGH2I55XVP": null, + "GE3YTUBPOT5CFJU2LQVMZVC67NFNLXVWNTV4ERN6BHVGCGYL": null, + "VXE2WHW6UWRE4WYTAVFAQ75IBYUPNZVMHJC44DGDPIAEOVVE": null, + "5JRWFOAEX5TNCAMYGF44C72EWF5NTXIRSVST5J3N6N5SLGFF": null, + "TYNIMWTDY2D565BJUNMFXTJHBUMWOTD4YSAFILKXPKX6FKRO": null, + "RDUDIY6N4RRUA6YEBBBFPBNYFZQUWRVURNYGJPEU6EHJA64H": null, + "MMRLX63PFJLWBJUTXCSLALIGK5YOHTLAY64WFQIYQJCX4QID": null, + "P4T7UPQNUAFMAJ3G4KBRHOQP5GCJP46XXYKPTTENUI36YQEP": null, + "VNAKVK3A4TN7WEZAJBJVMUVIKIUWCNH7B373DP7WAM7ZXYDD": null, + "VAPNA5BJL7OF7VRVSUEFAG6RZWENO5VOGMFVN6AB4A7H4VU3": null, + "TLVHDKN7326OHNXMBBJIVQW5FFFGPXSUR2IVTMPLOLPPJQW2": null, + "LD4OK3CY7MQGHUMQOMPAJY2NZUASJLSLWVSIIKIYYYAFYHIK": null, + "DXHC3XJCJJG2SMU4O2HDPMJHO4PNNYGIMLB5KSCQPNLBAJER": null, + "SANGKO55HOXMBC627JYHVBE3FH6KJL74ITOVF5GYODRRMEMP": null, + "TOQW7HYYWSFH3NKL7SITPX5H4HLAH7BKL35ECCAILLJ5B4TA": null, + "WUKAWAQHSBKAUAYEQ4UA5PKFB4676VQNQFLXUIX6UCDFZ472": null, + "BDU5VYNLNHR6HOLMZI4XSDERPTMVJ4LBUX5XP6W2BQWH3NLR": null, + "R6BT3RGKODHZN2AEX26XHNSLCHGPGMQ7IS2ONRTZEPJECW7A": null, + "E7Z4FLW3UW2ALRLPSMHQWJWBK7VWS63H3AUZZL6LHCIG3Q5B": null, + "FUZAITDO5EH4BU3ZAN55R2RQZ75LRAYI4X3MEJKJD44VHOT7": null, + "7SZ7VZ5O2OFPJL3K5JJKH3C2ZYAJCWW5GYXSLVFHRRATZDFA": null, + "6H7VKVPSP4MHB6P7H5KLQQN3Q6ZSS65OMK6GJ3JIUMHQINMC": null, + "QNCN75MNVAVH2OQR3JE53SGCKLXPSB2XBTZ55J3AX37AV5HT": null, + "JCSYRKMHDGVUVZO65VQVAV5SGQS5IRS4UGFNFKMYP6CXMHXN": null, + "JXX5VCQU2Q73TK5ICSFX3QIGA6E4IFRTGKPZZY32UTB2RY2Z": null, + "BMUAPYFGRJO7ZQAMMSSEADU2RC3LPAAXTORXLSIUCXCSSC2P": null, + "3SPFCAR2V2PQA3RWOY5ZZXI2V6UEUCZWL6SNCGEAGNR2JQZV": null, + "KUW7Z4ZHRUX6DI6Y3ME7A33SXUAQPXFAHRG4IEU32ETMGTLC": null, + "64F67UZGQHZUXLN6HCATAAX2FUQNK2WVOEJGBQ27H5DVZFC3": null, + "GHMJSW2TE6E3JLFDD7T6FI67HBDHNDVLGEKATAO5G33TID57": null, + "6BZEOJR372ZLNXUMEQQUKHHDCAOE5W4YDT3VWGI3YYPYDC5R": null, + "62JOKD5O25I7DBDFMM2BRQP4HI2VJTUHMEF3G3C7JFJF2VNL": null, + "NEF5ANHSBNEXLOP7FFH7ZVHPDOCHQQ6EYOG64JDZNIHBT44L": null, + "ZKLJACJIQT6M7KUY3VWTMQ4WD7RETAWN7LDUB7UQA3NZHZLC": null, + "VBZVHDFHE464JTYWCLYNAA65RDMVURJHVZHWRL3IKTNT6AH6": null, + "FHBYZO5SUBQ56J72DWYOUZSDKXE3SKDRWBEGLQPHWUGVSW5B": null, + "HHWRIAY52UXIOIKQOL3PBERZFDCQXAAUIDT4RTZF2VETEY3Q": null, + "JALKMRCQEIXX3JPLOACUZ2DKA5I2RWSSSIYDVSURW475XHR7": null, + "IMQUFG6JBGWA7R3D3NRMJNOF5MKE2NU4H2LAI6UPIHUEY2ZD": null, + "GWSUUFLKG23Z4BXTLB2HJHYVRWAWHKV5MA5RVOEE77Z65ILK": null, + "ILKEEWZSHVZSQ5M5VAZH6MJPBVQVV63SCQSX73YGTOQZBFKB": null, + "TBU3SS7AG7QISWIK2KKNE77ISJUEVH3ZV7QZJAEHLMAOUCEZ": null, + "EPN2PRVPXZGZ6WRX5ZMG6UPIM2V2NEA4BBC7ZDAIVCEKMHR5": null, + "Z7GJAUSWDAH2JUMVX6IZB2PRSIUHYUKXGKJDM7FXVFDJNDUU": null, + "APOEQP3DLJGKFU7424CJJBFDTWODGF45H7HSXT3GO2UC3VCI": null, + "LCYBWI4HYCSVGBSWWDJYDCWQZGJP2KVSXUUJBO3XFUWOS4SA": null, + "KOTWM653HSOQ2JHNAZGZZA5FGBBJCCBYPDVDE7WDXXIHTULF": null, + "TIPJO4GHBUJQKWKVHK5RF2NI5Z6FAIEBGFPR5L4SSCLS6IE6": null, + "QJZMGE4B6UPJ35KTTNIAHWTFV7DFQZ2QMF6DLHB2AHZQ45CD": null, + "SDV2RDMAXCYWHJJRPTEIZVE6SJST7KQJB57AXCWFVO54E2GX": null, + "4NW6WJDWXCXG2TS24H4I7WF2IGROPO4UBN2HJ64M3CWBU2M7": null, + "GJPMFWNBHZ63VB5XWIM52UO22ANEXDYLHTF24LGBC7XXI4SH": null, + "I3TPFLVZ47TOOMM2G35JFQAYHLAIU3OXV4SXZEP67DNGYXN3": null, + "QMPKHHYWWSV32R2LHCWFKBFDXUDUXTZ7FRZK3TCF25CSFNWD": null, + "J3C6XZSMIXH2SQMBUEVWEI6UZVX2GJZCAYSPD74BBUUK45RS": null, + "WHK5HZ42VH6IJ4U4EUKKVLRAID2FH2YISR7IV6FMNHQPPSH7": null, + "C62NUQB2FUJTY5VRNI6ND26FXCUVACSUTTR6NZMNQPYK6357": null, + "2JXXJE7WN7QWO6X3ESQCSDDBTZXOY43L5AODQUIR5P6Y4PZB": null, + "FQVJ4Y4GES3RGRABQCJIDIYEUNTIGETQ5EOXW25SZSYNJENT": null, + "IH2YJNGRU5Y3ODZHMWNV3TIU2MGCNLIPV75QL3JL4I7PH5ZI": null, + "RYUBMVYE4PL6JJOSBM57NE2RFKCY2EB3EQR3QU45MJHEX5IN": null, + "KRVCQJ6VSHM52MLDNS65PKDYHNBJAHCONQCNLXBD76LDCOFY": null, + "W7MB2FYKYWXDXNOKVWJW7TSUANZIGE25NABNIAK7VLPLKQQH": null, + "QUJNQSAHDXMNHKHHIRBEFONX6NRV4NA7NKFRDI72ZKVZXR32": null, + "SRQAJHTEQYVNHCJDTYHA72VSYS4FPTHXGPFYP6CQRTEUIWVN": null, + "GYQMORZKT4JGWGOD4KBEMUB3XZNUM7H4G5IRA6SYDZOGAPVF": null, + "73P37OKSAJ5SWM5NJ2QWCTKPTFNLORRRGBNJWR7BTCRLKNCO": null, + "D7YVGR63MRZ5YS3UTCUZ7REPWGB6EMGNI3LXZUDAYBSZVGHZ": null, + "JNUZON5EE4CF5UIPXIAU5HKQSBN6O2C3OXJ5IT6HPZMUBXRK": null, + "3UMKRHCWRV2WNUWPF4WKESLI6EOHPFC6FOXF2MGP6E7GPKF7": null, + "ZPWCDBHEOCZRBAVIQNGRQ4WNKSE4XCXWH3PQSBJWVTMLP6AD": null, + "RCOP6UXD6CG5XYUXFXT7HDAWQA2LRA52R2NVABFBB574N62D": null, + "6EHQW3VGWSY5MQKBQ4PWU2YD4KKXPBUFJCBEEY6GKOGGGT4P": null, + "V72EUDLMYSS47DCO7XIEYQO4S6KK7ME4C6VN6IWLZALPDIR2": null, + "EX6JHHNN4R7BQVBTVXYRD54J6BLOJTRHM64QBK3DHUWW37KF": null, + "6GGFMOEZN5PBE67AJM6XJKDL7V6X26X3TH2WVOO4X2MEQJKO": null, + "LYM2NDKVFTJ2IJV2G5HTDDXFDAAHVHVMVTNGBAOABW4JLB7V": null, + "5GPR3EHGCAFLKH4CTOZK3JBHCJSEEFD2Y5GS5Y3B5FPXAK6H": null, + "3TVZ6BP47YPHI4HKRIK43AJPRVM5UO736FF7WEXI6FJMTKY7": null, + "XDL7LZWG4CIO574WINYHCXMGRRZV5BMZQH6GPTTVPBWGV4MD": null, + "OHDX42IVKOGGQVXFE7Q3DKX2HNXGIZRAZ5TVVKQ34BO7UKPB": null, + "QHSOVA5SCRL5AK65IALQZWLHPSMLOOHHS6JN3LHDCN7DEHJ7": null, + "EI2J32TUZKPKSWOYH7EPPKHISCJ5SPTUFJXENKZJFAPEFQJL": null, + "3FFPGZBSH57RTBR326VUSL4G3DELAIPWCCHB77LFG5CBS2YU": null, + "VOLJPHGJOQKGKQ3PQGRLYJBZCIF3T355GXCQQKV34USNOXNX": null, + "ZASYP4G3K3DX6MMU2CK2P6GJ2PKRQFQGFVEZGTMIRAZBDMOC": null, + "MSLOXTCY6MPU6XRGIJ7ZGFBB5J4RTGTEC2UW2LO5MIKPXFJO": null, + "DM3ZAC4JV4IDN7ZZ2OLHAUCUEWYTMLZSQQEARJF4JVBUTE2D": null, + "KWIXQOXXGHTUPBDCHXV6ET4YZXIDCYZEQTFIRHD7DTMSGZ3X": null, + "SOF4BRIWEU5XLSXVFE6IHVVDYG73RK5HJACKPUNFRNEDHRWS": null, + "4FECMJE2AGQGN54LFXTIQFZC6ZVJN3LY62YCS4E65PMW2K5J": null, + "VDCWL2B5OEDDB2YGM7Y23WLJPJBFESITFU5AWDPUKDUMFPBO": null, + "W6VC6MV4GBWJ7IDAX4DQHWJSBUJHJN7ADFJ53NBVND3TXUCZ": null, + "Z3TTBMVW3FCTJPLHXITOVK4LPLUFJJY3CIYKJ4QY2DANJ53R": null, + "O6N3PZGXI5B6NBTOFPB5WWIRJ66O4FYLSGHDIJLVPT25YPWK": null, + "RXCNDGG7CDEMAOGCALTPXWLUL7A67D3JSKOZSZEQBLDW2F3S": null, + "XVKBWW7HRXDBW3YXSBMO7WVEUPVQ7LRZ44RVFI27PYZO3NTS": null, + "XUSRB4YQDOYJALL7CK2OYFPL7GKI6XOFYHP7HTW5H3PF333V": null, + "PCCHIGPV6SWW2O4YRPMFMNF5YVW6QY5IF7JPYAULF5WPTYKB": null, + "MHRU7JFEPHHUAULYL34RAEAGBU2ARZG63TGIIS7MHEQUKWPY": null, + "Y6EDYRAB7V6NAP57DRIKQ3SB57XBPN7MAWD7F3DM4DKWIAMA": null, + "JQXEFOTP5HPBTKL4VAXYCMJFZVGSAM3JVLFJPQ6KHVLCRXFI": null, + "U53PDNGH4IKMP4PW6AJV6K5Q43PYB6VUZ3IJVEKZK32IR5WJ": null, + "52CB2E7VQJ3JJ2SXPHQZZMER64TM2JQBSW3JMX7XITCNSWDT": null, + "3JLBHZFBPZQTO3MLCW6S5N3RIR42N6RGDHMP4U6IO6STOOVT": null, + "YTFVKDUY6LHHBY5JBBTT75RYI73Y2Y2DFT5PBMOLEVBJEN4Y": null, + "TAHMINQIUDTCEBCJ4UH2PUXO5TYMIIZTH4BX26S4NRMPFD6Q": null, + "4VJIQ6FLWV6ONBHRWDR34KXCTHL7HIXSQAF3FAKOMZ2C7QV7": null, + "IQWFFVGP6CPSAQWMKA3SWYOXAUL2YCD3EJYRQ56S3VXWAMUF": null, + "J2FABCRQ7HZFV4FKZKY2UOXRUO4FYXANTTWL27ANRYY6XZC2": null, + "G3TOY5CIOYIELRC2S35CGAS2E36TDLTO5XYXHFVKZNDFQC6F": null, + "SDKQB4B47LL6CAFDDYJWDS4X7COKTZOCQ6ELJBL2YF6RHZJC": null, + "L76D3LKKTUAWNPDXKTWE7JCFCRFVI4UX6NKQS3CAA2OWVF4K": null, + "QVYYK2GQF7DHSJACSOZPOQUCWWIYTRGEWMBIR5RRCV2EPQ5X": null, + "UM3PJVMZNDU2GJ6KVY5VQ2HPGMSJKVAQBDRKZKHBPBRCU5SO": null, + "RDIJQSPXHAUB7XSQQPOL3CNUR5AJAJEWAFYFSDO5G4QWZQCV": null, + "3CAVVDQOCSMOPC54JWKI5ITUIHAOV6SKAIIAAPAAJLBDTXEM": null, + "JHLSLTDSRVKDHWRGT55OZ5NC6YHGD35WHW4GPK77VZWPNVKN": null, + "6K266T5MHDGFA2XECSFBMTQDEE2C4S45S53XBODESR4ERZQ2": null, + "VJVWAFFKWR2KSTFIWGAKDUG5VQTO3BPTI7YFYZWZSBMMQOIN": null, + "LBSXWCQNCHYUG5M255T3W72NBPR5MBEPO7DFBCD277HSH4DU": null, + "WHJGXILLMK23VGXI2OY76SYJQOQHQOM6OSLT4BWU2KSD3OAD": null, + "DVNEV7ANOMDRQDHTEMD6CXCTO7NOY2MQQOLI47U4DDOJ2A2M": null, + "TV752NASHG7FG2JOGS5P6QLJ7E4W5NX7F3OYYRPOEFZ2NREE": null, + "S4DHHYVQ4RQ7HBAXW5ZKISZMULMLCFTSBFICXNLI2OD7YNF6": null, + "HSRHOS56TX6EEDHUZX7K4K6Y3R2UNHRINXWVK5WBWHDPE5HF": null, + "I67YQZJ4PXHFWHNHMK5SKUEFIL4EEP5B4BH3TJNHZPQOUXDM": null, + "5AJTMUDFBWW3EGM2TH2YAJYXIR6GKM7RPBYBRV6KEQPDDLM6": null, + "6V3SAQQC44I3CSDERRKA2533GYIWWHUZVR67JAWIBPJJBDBI": null, + "5I6EFWIWLDNJQAZNZN326TUHCUY5YOD4ITIT6NL7LWIK6RP4": null, + "NVT5LE35FIT6LKWBI5XZO2Q7CTQBFJ3IOIAFNXI7PGVHEE5W": null, + "E5I534XUV7GRNCMHBVFI7FMTSPYBGXKOFVXXSEQYYLVGCASL": null, + "3XDVU325YQTEXC7HFJKKKH7CTCCNNJZMV6VRT5GVED7HFKMZ": null, + "3UJYDR6QUVSSCRHJT6WWNEHC5OMYXOPL3EF26PU2A5HESFG5": null, + "UPRVTQXNXYCZG4JZIR7GZCCYTXR5VTUR2OKAJXEWGATCSIOH": null, + "2QLXXZPU57ZXMLJHEYDS6IHFLQHOKANOE5URI2TRNFNSIFUG": null, + "JFL3SN7LZ7M4RUZXRTYFQTUMYWYHO4P3ZKBGFDC2GGWZBPEA": null, + "SBLHOHHAOCNEVQI3UPBY5S4UKTTIH3DEJEDJHWMJ6VEWWTCL": null, + "TIE3GNWA2BE2WGFA7Y3KEHF4IF77M5XHZB3DIQLOE3GG4VQM": null, + "BB7XBWIYV33TZGTKHTBL4PDPH5ZQ6X7ZCMHS3KIQEJOLOXVH": null, + "6WO2JPOCRLCUSXS7BHNKFBDGFSEXCWYUFPK5SDZJTFJAEJRV": null, + "RCJUMHWKL3IBJ4ZVWHK4RCZ4RCVVTMG5ZO2KWZOIVZLJTSMT": null, + "YIXCNMIMZBA7NK2A5QOCLE77QFF6QDS7NGIHKMILIUB37EMH": null, + "ZSI25IY4L2U7CRPBLOYY5TCSAVG22XHHZFC7JZCRAVY46BWH": null, + "HUSGTJENHNIBJ7VSWZPOWFHHKKYH7H2YSP32LLQ2N7CWKRME": null, + "WTIJK6LZPBOCIJFBZEG26BETKTY5PJKQK5D3M5WVPWVSV7LN": null, + "ITSWONDXALFBD4WMGSMRKQXCVTL7JRKVFEHOAOODRQEFFSWC": null, + "IY3RQGYC2ME2TEUBYAQG5WJ7WOAJV5GTO6P3FKXWOLSJWGCD": null, + "MDSHVZ5WHCTCYB34ZABEUJJRXHQDKO5MSC5YVTGPMNJRXQK7": null, + "KHNSXQTOSCRSTX63S7OVO2LGMD7OVR6PZIGEKL5ZDYPCEKK6": null, + "LECVNJKLFT6P2HWX3H7ZC5DKJSSRZ7PWZVBN735K7I45SOX4": null, + "HFEO55KM3XH34UWCRYM5CFNQ6OFRAKM3U6TABNQDP74DT4JQ": null, + "QZOWC3TAAU67PVSBRJOOVZCBSRIOZCMLPB3FH4GS37WOSTEZ": null, + "TSB72AJ4HHOBEYK4CGFX3W4RW3SIECQYJMYISHTPPCGQNLFD": null, + "6AB4YKYVMU2PXRABAUBBBF4BJ3IOFKYWBJ2IMFMRVLCBI4S4": null, + "E3TI3V725PEP7U2CYZUUKJEBPAHOEI5SYCR3YZCMGD5EGYHF": null, + "APKJUBCO5NHY6QBYNA2ADB5TTPLCNZMHG7HGXXOLRBOZD46Y": null, + "QKL26OQG6L54OCKFPLMXI6M3EG2HI4EG34D7BNI5SBZG6OF7": null, + "W4KKIH4RPYXL4JZY24JWLHOATFNENBMSEQQ3DI7WW4PQIJQ3": null, + "4XJPWCDQXS6MSKI4EMFPENOX5FV7KMKKZ77LV6GJ6S7ZBVB2": null, + "LWMCTL5CEAVQDT5PEXFKRK7Q264CNVV6AU657OQ3SSPCDGSQ": null, + "CBMCT6STEYDOVXT6OW34OXGZBN2A77OGBPDRN5AZK4RXNEV5": null, + "OUGRMVL7PTQ3GJNWQ5WP7XXNYBIMVWKSNQ2QZH5RZRDEGUND": null, + "XKVAYVNQL7KW5EHGEWYRPSWDXNUEKP3YC3OXGEHKG7PGNZHL": null, + "ZLO6BOTXUEEW7UOENY2NVIFLSG37YPUETQBYYCQBJM5VXNG4": null, + "QMZJWAJYYE6WZQX3OKY34BPU7ZZN6ECDNIZOIXREE6AP3WJF": null, + "B5FU7VNVUSA3ODDEUDVTKE7GWPU3JQXWHRWYGLT6VFKSFYAA": null, + "HLHSAJUSHU5EY26UTR2UDJAM3BIHYYHF46MNLTQZJWDAUCDO": null, + "N73SLU2EDTPQ54MY5NWT7KPSVTO3TOGPO3DGX4HQYPZMFYJV": null, + "7B47MDGTJA3P2WX3KWLLESWTC7RJUSVUSBI42SATEYZVPL5K": null, + "YYLWTHMS5POBP3WVX5Q4NXQ77STWJTAHE6QK7GYMBIJU3TSX": null, + "JI7Q6GUWUTSJPHKUII5IVOUZ2QQ53EWNWCUM4PKECXWSVSEK": null, + "XR4W6GZYNYIDAFU7MWMIGFGF63OLKU4FWQZ4RAN3HWNXUINB": null, + "3KX2TVZZAQSYQHLDSWMVZVF4UAXYONTXXFWSGI6CJ56DXU6O": null, + "UR6JGWK36D4CU63DYI722UFUKLB2S52ZI4OAVZM7CVGGY3SW": null, + "VGQOGZH3H5IAFESOYWHOQGU5FHP4BJAUUK2B7AKDCJX3PUE5": null, + "Y5GO3VITRDTHWTMUULEA44BVX3GHVLIWFMTNUY2APWRL3JLD": null, + "F7U4AV4VU7YAEDK6SI64JJUNEHG2MEFLKNOI77IVDQS7BGJK": null, + "D77762UIMSS52GNAPWFCEEFPWGYLBPKWMBN75S3HCOI2SYCL": null, + "NNRBK2PM7FI7MVFBSUUCZVFTDOKXLNVK6I4MMUXU4AKDPTCK": null, + "YSGZXEZQRGZ3DSMNCNH6GSWGCRWQSIRD3IOR5E3XEUH5RORJ": null, + "P6KRZXZTESTNZHYLZFTDLZMIGIN5H74H2KYUTNRIC3JWCNJ2": null, + "QK36OWDC6RHQIASJXU2HZVIBARNIESSCWKICTRQ4B3OFUB6D": null, + "JQBWWRLDDMH3HACHKR7EKXFCAAR5E62DX3ALK22Y5AFA4JDZ": null, + "WWOLYDEZIQARIEC65MFSVB5RH3236B3E2YSGNEN2QY6A2G54": null, + "QT5UVU5QUPEY7VCTTW26JTO2FBUUBCRBYZORWGTYQZ2JZSCH": null, + "PJQFD75BGF35X4N33WD423KSDLIAWJNAZUBXQTUGHOW4PTXJ": null, + "A5VRG2DRN3CKKTP2DN5YNILXVCZRTKFXWILKWLZ6PNVKJTM5": null, + "TY4YPLWS4MDSKPG2HHIRSAWK37LFVB357RGGBRFP2P332HJL": null, + "SUC7ZGB6YKDYNAP6NTUZVEVNDL22KBCRZIGAWSOBUAL55LDE": null, + "Z5I7WKVA6754S4G7QWWXYTRZ3SGEG4B3KG5MLHP3GJDI3H7M": null, + "VLGCWOT665AT2R6EMOAVHNKVM2NKPSV4KI4CMNEUZ2YMI3UP": null, + "YJMQW3C2NIIZKTJY34XRL4HQ5A7EUMLMXTJFHHRE3NR3QGZF": null, + "TOEB56GVW7OQ7QLL25ZY3ABP4ZQS2ZZMIJRNTILE5CWA2IZB": null, + "5RGLCKE6D2MM5YH74OJBDHTOZIM7LN3EIYBLXVF4PGNBZON4": null, + "QMQPPFLB6NCEBYCQ5U2YWVYWRKZSFJLCDAAPYSPURDLXAU6G": null, + "UTAFBURT6XHHZV3Y5OZJBJJQT4342SSCOLWT35GZIJUPWTTM": null, + "XCIXTAB5SB5EMQLZW7GCBUS2N3XU44YELMLSYIFAJHHGP3VS": null, + "LWL5AM7Q4JPEDEORTLNDWUF5X4AIUI4QC5S4CWUXKXIWP6FP": null, + "M4RONO5HAPE25Q46SSRBVQLEXPCVQLKOKX2NYQWX2SNNGEVB": null, + "UVSHBLSXOHEF3AGG5PDTTDFVXNQPRHCNUTXYDEXJVXI7JCPL": null, + "C3PB24XOHCI52DU64XQL2V2OKZZYG5B4T6PUU44DZCH4DMSS": null, + "VGACAPDUB2J7KLW5PA474JQZWZ6QCDYYB2I32ZFYGXR64M2Y": null, + "NNDVFWEC2OE56D5PLJWEEVG25TMXCXISOUOYDOUEMUZRMZK4": null, + "57TIZBR3DXRX74YXCSJ2RXLZRXKX3K7H6WPS7DVONX7DOJY3": null, + "RFSCST6ITGG53EAZEBXD2VFQTJ53ATEOORQV6SQG5OSDR3FM": null, + "YLIXTKYNMODZNBM3L2EL435GD2LRJ5XAJBDZSYCU3OPZ4N4V": null, + "FBEPPECF3L4RB6QBQLGL44JDBCQCTQ5MOFYFCUQVNL4DCQYV": null, + "PAJST32KEXY6I2Y57OASSUFLF2BLPQQ7NZMVN6EVR7JS5LY3": null, + "76MHL43MEQWH6R552TULI3TLBOR22YDMJC5ZYQVWCNI4BWF2": null, + "A6KZM4OXBKW2NJ7X545F4LIDSC7LIAFYJ4CJSWW2BWSIRWUY": null, + "VND76C7TCKQT6R4X56OD4UYSOBZGC5BQ3LR6RXOX6LA3I5F6": null, + "CE2NODHXCRS4ML26HTI77Q57R7ZXKZO433LHHA66I5U3Y5GP": null, + "3DGAXWQDLZBPUYZPBGMRZG5DOBPTIHKAXFSCBLMEQHZ2A4W2": null, + "NAOTRV3ZNB2PK6RZJZ4UEQVF5M3YISGJNFZQQWPV2S5RL7XM": null, + "HLCSR65OBO7BJQPOA65Q6BRDVFPOL7FJII2LOANRJNUM2DDU": null, + "YCBI6X4JLTHKGAFR7XYKELWE7JW6VHLMFJIWF2ZC7BPCQFFR": null, + "QEF3LB5GFEMHAUDKPPNYGRKUUV6PAWU5XXYCFIHXI7PLGVGW": null, + "ABBQK5JKJZLMX4KGFODWSEHOPDTRHGDZCBO3ULBVOGUIAAGI": null, + "HZLWUQNBAZJSDZEB6IPXQIUMVWUPYVMVP2N72NJ4MOZFUKGT": null, + "7SQCYMGSMYW47TXUWC2J5674L4CRDIAO34D342D7IJ6OE23F": null, + "YAQCDYBXIOY3KZGFJCPS5VD7YQBPBFFFYEA4DPWFWJCWCJXA": null, + "HCZ7SSO422NW6O3ARCBUGNBCMUVEAHXMVKAJSDBHAQSFXIMV": null, + "DPX2FNJNMFQT34DLAOEIN4KMWJYLOEGV7U4VDH635AG6UA5T": null, + "QUO6FPOFFXUUKAZXYRN7N2MMT7IOJEG6NLFIH7B5JI5V2Y44": null, + "UJ6G5JMOINYVRLVISHWTGQDDDWA6X3QDFICKY4QQIHG3QMF4": null, + "ZR3VRUOZMQE4EMVT2WDB45TJ7KB5AGU5UBBPNL2A2D255MOL": null, + "2AFEUH4R6YAJZEODKJBMLDM4ANLCKRU2C33HFSVU2LLXZW5Y": null, + "3S4PV2VOBFB6GFRPG5SB3EHMZE5M7VAAFRJ3JQYHZEFTEKFX": null, + "6EFK4THSCBEG4LDSVE5N5FXSQJTYB5SQ7LKJRBL6IYIREWTN": null, + "HHYCWLKLIII7MJ4MYU7CJZ4YPOOUVWOKLXHZV5NT6LU7WWGX": null, + "XYRSXFI6XRY3YACAIVIZJAVKFTZPRH5FXD7E4P4LYUGX6I5U": null, + "6W72FMK5AP56TNCZ3LE5OTYZ3WYPARBB5AOXDVHGCBOTWZTO": null, + "7YNUW4DUCHUDJSSAWSYOYM2QXWTVSJWGDPIG2EAABTU4QLU5": null, + "HNVXP5XULHDT666ND2M3X2APGXOBCB7SCQB2D7MFQKKNVOS4": null, + "MLCMV4777C55OEVW3SFO4VHH56O7BSIDLZFYYTY3JXNN4DWG": null, + "MSNRSOCYC3HQCUXRLCBYFYQOMJFBDOSHJ3HYYYOHEPODETEE": null, + "BJB2U3W5ZF7WQVTL6R2F542WSS6FQDSVDMXNYWIC5PHED4HH": null, + "E26RFAVZYOV5WZ6WQDVINCGNG6ZYU2XCV4FPEKR45IASGARQ": null, + "4BK33GLSBFLRZHOHECAVVYT3LJHSQ5RFBSMKLMGTK4Z5RGZO": null, + "5I3526BP3QPLNDBEIPVQL2GOAMRBAYWOMILMQK5IT7RES3EV": null, + "IBHOZ4VNFYMLMUNOZIGK743IVASI3DXHCY2RH6SO4EKNGR4A": null, + "CCZT4EOMTISCMIVGMB2ZRUGFIR3R6WKU3ISSJ3VZVA6SBLFC": null, + "OGJUH7B3WKG3W2UFEBL63KLQGPSPRNIHUUKWTKQMBN5QG42E": null, + "Y6JCIA2AYVA3RDOUQFYWI4EMF64H5FIFNAHSKZ6LXCRXCFGW": null, + "VX3OCLLJZPGXWTLGERIMK5IS4OXKU65SMC4YS5JZND6VEPO7": null, + "UXWF26BRES53JKXYXEG5DWJXCR6USGPBWQBDJEVEBA2PPUAI": null, + "IB5SSNMYSFCNB4ODT5OQ2GAGPIVDWOBEI3P3EBWI7AUGC7BR": null, + "ASIAQKC3VSFJE7ZW472ZOAXX2T7JTCLZBN5BYEOAE7E67F5Z": null, + "BKQ3GY255BDDVZ52IIR5K3NFIEKV6GXBVTX3ROY3IN7XDAHA": null, + "JTV5ULWFJJOSFTX32FA6DJWADX5UL3NV4RZZS3Z64IPXDZNK": null, + "GSZ7MZXCFKAWFBXKRVYUDULPJEH3WSI2K634LAAA36M2FRF3": null, + "HSPTZMNCONTGJGIUWP7ZR277AYWTDIKPAWO4RODOIHQGEUF3": null, + "4ABCWRBBUAO5TVOSOZDF3KMCUCKIUCRJSBGH4WGKDHWH3LLN": null, + "K3BK4XFUTDJLS7KY4WJBS7RTZ65HY4N5NJ6AMKNKGO3K6DXG": null, + "S4VZEKYRNOXUITHJENCBKJN6CC6QV7Y4MIHQ6NLN24OJFMBP": null, + "MRM4HMHS2KAISLXU2XYFQCQH7XRVVC3EXSP6JU7FIM2DJHVV": null, + "QMNCR2JQYOST5MD3HI2I4MCTSJDFCAGUTEE6XKM2THC4WXI3": null, + "ANIF4DT5IA4IY7M5OISD4IW4J2TDVHHFIPEONUU4CV75LOFZ": null, + "TQHJIX3NKO5CMVRNOG4WP3YDSGPLTTCRBA3RDBPECWO6EN5U": null, + "6KI4L4RRXZ6WL3TRMCZLAA2W7AQRXDCC43O6AGYJ75NUEQO6": null, + "VL57QTQMHQOAX5MFQTX7GUWOECHVTLYJHIBRKMWIRF4QMN6M": null, + "JFTGBEP2LSZGDDFGV6IV2JAS3J3HB7BDRB6WEYHSC5EIFNA3": null, + "WLEZIN5PPCJE4W2LGEPW4N6AWQ4RLE2AOGFBTETY5HNRSZCY": null, + "LUJRHNRDNK7YOKST7KRVQGVE2ERU3LUVPZLC5YYLCUAX2EEU": null, + "F2OOXAP3FFVMQMJP5IVDLRVV6IP2NUTGT5MGZCJMR2IFNA55": null, + "SVL525L4TVBTLMH22DTXVCNECAZVUTMMYDTA3UQGV7U6P3YU": null, + "546BD77L33PUPQ7TW3GJJVVJTYKHIIKF7YOO4SSGIIIOIJ2Z": null, + "FCZRNOURTDJI2BE7HJ3P4MMY4WYAPFFBCTVFXVTYSK4UB4JK": null, + "S2U5XQEC7I4HOUUR6HFXUF2PR2CLNF5UEIPJHTNF2JM5BZUJ": null, + "JTQGSOTIPVYKGYJBUQC3Y44RWE372S7MPMFDETMH6OEGUJWA": null, + "W3DTWDN6YOEPVUJVUDNPWCLQMXXCLXQPVYU27675LZM4ONDF": null, + "LJ7P7AJNNHJE24PNWQDK7J4VGGNZKKR3OPVRFV5A4U6LRFRW": null, + "I4QO3SZC4455G5PQIJPUUNI4A2BPJKTH5MBA7LN3HRIW6EFZ": null, + "NNR3EXDDDPBTOKTRBPR5SO4OFPXU376ZIEHA6YHEJK57ZRGH": null, + "4MBIV5HD4ZMXY5NIKZQIFKFO7S642PC7CWVX7ATXAXWQWNGU": null, + "A6S5KTN66UWYBWG5CZXJVCJ2F2EA22BCZDFQMM523DU7VFBG": null, + "AOAPML4IEVJZSZUOONTTDYSEN465IHW7MZXHSQ55E47TJ2NW": null, + "ZIW5DXTPGQLTTRHPRQB7SADQPCSTXQRMKHZIXA6T6YW2BMRS": null, + "OUHF6P7JPB5Z2C2E5MEPNQ5R3NY56KNQFHG3RYGWXBYKRRI7": null, + "M3JXOC3CTIEMVHTQW7HB2WQ7L7Q54AWFY6F2UBTSZMDXHTDI": null, + "WQQA7JW5NTSAI73WVQMMAJ4IO6OKZR32GTQTMUWE2HLC7DRH": null, + "WGDVRLD5YWTXFOFTGBBEFCG455EK3BZCZEE2POAX56O3EOQW": null, + "6KAR3LTBYTJ6WRGOUQ2TEPZKWVVBPGCO4OVAN2ADNDNLTOSM": null, + "VEWL2DORBATRWF5HJ7LG66NYWMXH37JJU6XWVGJNDVL3OSAM": null, + "B4HXCGMG5S3VEOZR5IUYOZAEFL6WPRLXB26SLWZHRY3WL3ZU": null, + "REKI5EIO6TNXBWJIENJDQ5CAYEYZC2GXVPAOIWGVXKN2K3OE": null, + "RBOY2SVFDRIKJZWTWVEGSJLHGIMAZXIF5HNBZAKPVRTEFR3A": null, + "SIOSHIHS52CHIB73RFONJOM2HJBTRLGGDFW6JAWTR6UPJBVB": null, + "ZGHKTW43CXC3CBOLSENIMDQUIR22VNXSE6HFBT6ZUA3TPODL": null, + "XA576OGJNZK3AXE3FJLSSGN5MGRK4FJJ2XX3UHHFI6NO7P25": null, + "22VL7B7ZI53VMYEYHKBI7XYNKRQW634B6RLBRXRJN4CQJA6G": null, + "YVHEMU6OLF3FI2MTMZ25QKT5F2OUO3H6CX4WRNEXVH4BO3WZ": null, + "3VJOBPUJI5DUFHNRM456UWSAHIZYXICY7ZFYMECCUHDTG444": null, + "BXLYOEBYW7R4MWPNTOZ2ZJPDDXBHV7JMH75NCD26VGS2VRH7": null, + "GCZOZTTLMHTAKVUQ4TSDOOPHEGK6PH4JQ3ULKZCUIEDW2HLX": null, + "TE6B4JOPAY2CEQ46KJV7N6MY7OAI4VA3UBBXGPOELN7KY5T7": null, + "62BPAKDHZ7ZRJOMVZ2SX2WAKFQATUQLKDQ7YGACJPL2NP4UR": null, + "6U3MTBST24MIPS3HSZJPTBSZJ54T63GMZGZQPGFBS7JGBUVX": null, + "SXBYC5BKXYT4DFNVSS4OVRYLNA5JY4TXMVTIFSCRT6Q5C265": null, + "TAMMZOCU5GDDOIRG6U53NW3UUEUGI3QWW6YY6GWNE7WIHRNE": null, + "O37BSKPNGDUUN24XFSCR2IQHWFYUZJBPWSNC4L43MH5HV272": null, + "AZFWV3I3DANXV3HJB66QMCFJ3UTVJGS3R3IP7VROF2D5JF6U": null, + "W2BLY5MU4PA7HSENYW4MO6VHHPBXUFCFMSBWTCL5F3BIPBFT": null, + "ILFL3JG2XQGZCFBJHZFQRZMLGHZWVRBX3M5Z3HXW2A4GDMNK": null, + "O7VDC3EDG5I567RK5BKXMKA2R6XPHQQPDXQTCZP7BHKV5BK6": null, + "5ZMIJOTL3NPRKBEPS7542ICCNHHUJ2BNOZ7LSL2ICTCUFGSC": null, + "FCTKLPX7PYRSVVBH4KN46HEYLJEYSRTQ3PCUU5RY3BROUZKU": null, + "7EAMJ4C7NUA3XMDDOF3YRJA7Q2BFXFCI4J24ZXSVE7REBRFU": null, + "NOQ6OL6G7QD4ILQ3FAEMEMROBCK4OK3LX3CRMHMA6GG5YIYK": null, + "N3XXFRDRYPWGZ3LDGLIXGLLJYKEHPW4565BUUL67OLMXP554": null, + "GFHEEY3HHESZDI2YHTDDCBKGE3ZPWPXW2WE5AKNL2Y2TJCNJ": null, + "JTUQIEPPBM2QC6XBY3KP2NSDM6WUCJMORCBXNU6ZPXPOHEIW": null, + "V5VTVJ36JZDDO5FIOEZNAKYWPRQSUSTEZAKARDOHQEIFLACE": null, + "KUTOUNOS2QL4O6HF266ANCBNYUSIT66TANXCGYALCPZXULQH": null, + "CJILUW3VUBZCSO5DXTSE4HSVW5UJAJHHCSHGHADKCQE5OTBU": null, + "HD72YVUCR4IY5MG3E73UM35ARFCUIHEPIMUSQXOKLVTT2V67": null, + "ELVTZXW3ZAKR76K6IV6ZHX7WTMKPKIFRPHIU3LK67WQR6IQG": null, + "NIZTNRLCIS4JDLMOTEAKPA6B2JOE76ZBQDEUUGXENEJBYJFV": null, + "FE743ELPJYDYWTJ374PZVE4TNGZPDZWSNUO5PATNYUYBDTBJ": null, + "FIT3JHSZMFJ7N2E7BL6PHEUUHSBHU55YBIH763TGSZQTIAZY": null, + "AP7SXAQ6HW373QPCHKKA4R7NFFUCD7CFB7EERZBNXRGM2Z7R": null, + "BAW6TALQRWXK2OWS2O2UV72BKZGBZCUPR6AXKFZ7WHZXZXWX": null, + "SM3FE7H4NI76AS5YCH6O34LTROZKJ7FEP4IKL33JUBI7FWZJ": null, + "BNO2EJXVMAPFDVF34NBTPSIYKI3UPFI5G2K6KGVU35TIHOQL": null, + "INHCLRC6WPTE2U7OQRSSRGCN4B5K4BUVSGFHEKG5DWJWICOF": null, + "OEHWM7QZ3H67QC4ZQY2USKQA62NLMESA543KWPBUKV7N65TQ": null, + "BN3U5KDJP3QGOSBX3TH5R2DR6PZA5Z7BEGVG6MYRW5GWUCGT": null, + "ID7S7JEGBCI7ES3ZN7PIW5NEP67WTL5H5IB6WVRYS47EEEJ2": null, + "BG4MHZNCCLZQN563CZ2D72CPT5TASZZ6N6L4JOW2XPR7GIDQ": null, + "IAQKAEEUCCT3ZZY5LCO4AZW6F6ZNGUAF56UCD43OPOKSMBHR": null, + "LFCSYYMAFZ5IAB5O4QIEN5GERYIGTH4JH266LORQ36SB2A26": null, + "J7W62H5B42N3YUEFS5F2MECESYBUVHXSIGRMZL6ZNQMCYQMQ": null, + "J24FG5J3MUQOCDAVVCHM6BJWZW4Y7VCSC73DW32TMKIUOXPB": null, + "DGJE6OPBSV3JW45P5WC3EGUMIETVT7MIZX4EA5SCY2F3JKFL": null, + "KWTJYJJT2LMBHE6WH4LNJEHNMNJVOEQ7SLLXGJKWPGOFDYHQ": null, + "7XZDDO3CCV34UECRKEM344EDKKUFD6YDUJ7EW4OAETABTYWV": null, + "BPS2OSY2SOAFFPRY24IEXGZVBEUNVIWZYTVVZRUWT7XM727T": null, + "6GRVGHI3FMCQ5MQ4JR7ORANBXK6GMSI4XRQVE35LPH44XROO": null, + "MZHRR2BS6HII6JD3H32DPSYTTHCVXE4WSC7NUURU43Z5SD56": null, + "QJBSWHFQKABG4CALELT62JWLMW2JVZP35RDYHWHQPZYTIX5M": null, + "K2Y3YRBFB7F5PJJUFJDH5Z5NL2MYOQWGT5T5VI5SP7TVM5NW": null, + "QLONNH4NMZX5WLEJPQEWJECL5JTLTWDSK234NU5H55GA6PFG": null, + "NSSRUR3GI6B7NBK77ZQIIHOA4TEEA5UXVVMRWVLMRIP6SN3T": null, + "WB2TXRE7EPSBGACXUA4YE23M4WLMG3PVRMD2OOCIHNGQVDRY": null, + "3MDCQC5BPGFGGFDO4C4IY53NPTWZMRK5MWLJG2KX7OWVQNFO": null +} diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 934e50356..2bd9e0dfa 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -47,6 +47,11 @@ RAPIDJSON_DIAG_OFF(effc++) #include // std::move #endif +#define RAPIDJSON_USE_MEMBERS_MAP +#ifdef RAPIDJSON_USE_MEMBERS_MAP +#include +#endif + RAPIDJSON_NAMESPACE_BEGIN // Forward declaration. @@ -404,6 +409,24 @@ inline GenericStringRef StringRef(const std::basic_string& s } #endif +#ifdef RAPIDJSON_USE_MEMBERS_MAP +template +struct GenericMemberMap { + typedef Allocator AllocatorType; + typedef typename Encoding::Ch Ch; + typedef GenericStringRef KeyType; + struct KeyLess { + bool operator()(const KeyType &s1, const KeyType &s2) const { + int cmp = std::memcmp(s1.s, s2.s, sizeof(Ch) * (s1.length < s2.length ? s1.length : s2.length)); + return cmp < 0 || (cmp == 0 && s1.length < s2.length); + } + }; + typedef std::multimap Map; + typedef typename Map::iterator Iterator; + typedef typename Map::value_type Pair; +}; +#endif + /////////////////////////////////////////////////////////////////////////////// // GenericValue type traits namespace internal { @@ -651,18 +674,8 @@ class GenericValue { template GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { switch (rhs.GetType()) { - case kObjectType: { - SizeType count = rhs.data_.o.size; - Member* lm = allocator.template Allocate(count); - const typename GenericValue::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; @@ -810,9 +823,7 @@ class GenericValue { break; case kObjectFlag: - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - Allocator::Free(GetMembersPointer()); + DoClearMembers(true); break; case kCopyStringFlag: @@ -1177,10 +1188,7 @@ class GenericValue { */ GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsObject()); - if (newCapacity > data_.o.capacity) { - SetMembersPointer(allocator.Reallocate(GetMembersPointer(), data_.o.capacity, newCapacity)); - data_.o.capacity = newCapacity; - } + DoReserveMembers(newCapacity, allocator); return *this; } @@ -1254,11 +1262,7 @@ class GenericValue { MemberIterator FindMember(const GenericValue& 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 ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } @@ -1287,14 +1291,7 @@ class GenericValue { 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; } @@ -1428,9 +1425,7 @@ class GenericValue { */ void RemoveAllMembers() { RAPIDJSON_ASSERT(IsObject()); - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) - m->~Member(); - data_.o.size = 0; + DoClearMembers(false); } //! Remove a member in object by its name. @@ -1474,14 +1469,7 @@ class GenericValue { 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. @@ -1513,13 +1501,7 @@ class GenericValue { 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(&*pos), &*last, static_cast(MemberEnd() - last) * sizeof(Member)); - data_.o.size -= static_cast(last - first); - return pos; + return DoEraseMember(first, last); } //! Erase a member in object by its name. @@ -2030,6 +2012,250 @@ class GenericValue { 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); } +#ifdef RAPIDJSON_USE_MEMBERS_MAP + typedef typename GenericMemberMap::Map MemberMap; + typedef typename GenericMemberMap::KeyLess MemberMapKeyLess; + typedef typename GenericMemberMap::Iterator MemberMapIterator; + typedef typename GenericMemberMap::Pair MemberMapPair; + + RAPIDJSON_FORCEINLINE size_t GetMapAllocSize(SizeType capacity) { + return RAPIDJSON_ALIGN(sizeof(MemberMap)) + + RAPIDJSON_ALIGN(sizeof(SizeType)) + + RAPIDJSON_ALIGN(capacity * sizeof(Member)) + + capacity * sizeof(MemberMapIterator); + } + + RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(MemberMap* map) { + return *reinterpret_cast(reinterpret_cast(map) + + RAPIDJSON_ALIGN(sizeof(MemberMap))); + } + + RAPIDJSON_FORCEINLINE Member* GetMapMembers(MemberMap* map) { + return reinterpret_cast(reinterpret_cast(map) + + RAPIDJSON_ALIGN(sizeof(MemberMap)) + + RAPIDJSON_ALIGN(sizeof(SizeType))); + } + RAPIDJSON_FORCEINLINE MemberMap* GetMembersMap(Member* members) { + return reinterpret_cast(reinterpret_cast(members) - + RAPIDJSON_ALIGN(sizeof(SizeType)) - + RAPIDJSON_ALIGN(sizeof(MemberMap))); + } + + RAPIDJSON_FORCEINLINE MemberMapIterator* GetMapIterators(MemberMap* map, SizeType capacity) { + return reinterpret_cast(reinterpret_cast(map) + + RAPIDJSON_ALIGN(sizeof(MemberMap)) + + RAPIDJSON_ALIGN(sizeof(SizeType)) + + RAPIDJSON_ALIGN(capacity * sizeof(Member))); + } + RAPIDJSON_FORCEINLINE MemberMapIterator* GetMapIterators(MemberMap* map) { + return GetMapIterators(map, GetMapCapacity(map)); + } + + MemberMap* DoReallocMap(MemberMap* oldMap, SizeType newCapacity, Allocator& allocator) { + MemberMap* newMap; + if (oldMap) { + // An (std::)map can't be reallocated (supposedly), + // let's save/restore it before/after with a double swap + MemberMap tmpMap(MemberMapKeyLess(), allocator); + tmpMap.swap(*oldMap); + oldMap->~MemberMap(); + SizeType oldCapacity = GetMapCapacity(oldMap); + void *newRoom = allocator.Realloc(oldMap, + GetMapAllocSize(oldCapacity), + GetMapAllocSize(newCapacity)); + newMap = new(newRoom) MemberMap(MemberMapKeyLess(), allocator); + // Move the old iterators to their new place + std::memmove(GetMapIterators(newMap, newCapacity), + GetMapIterators(newMap, oldCapacity), + oldCapacity * sizeof(MemberMapIterator)); + // Restore the old (std::)map + newMap->swap(tmpMap); + } + else { + void *newRoom = allocator.Malloc(GetMapAllocSize(newCapacity)); + newMap = new(newRoom) MemberMap(MemberMapKeyLess(), allocator); + } + GetMapCapacity(newMap) = newCapacity; + return newMap; + } + + Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { + return GetMapMembers(DoReallocMap(NULL, capacity, allocator)); + } + + void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { + ObjectData& o = data_.o; + if (newCapacity > o.capacity) { + Member* oldMembers = GetMembersPointer(); + MemberMap* oldMap = oldMembers ? GetMembersMap(oldMembers) : 0; + MemberMap* newMap = DoReallocMap(oldMap, newCapacity, allocator); + RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap)); + o.capacity = newCapacity; + } + } + + template + MemberIterator DoFindMember(const GenericValue& name) { + if (Member* members = GetMembersPointer()) { + MemberMap* map = GetMembersMap(members); + StringRefType k(name.GetString(), name.GetStringLength()); + MemberMapIterator mit = map->find(k); + if (mit != map->end()) { + return MemberIterator(members + mit->second); + } + } + return MemberEnd(); + } +#else // !RAPIDJSON_USE_MEMBERS_MAP + Member* DoAllocMembers(SizeType capacity, Allocator& allocator) { + return allocator.template Allocate(capacity); + } + + void DoReserveMembers(SizeType newCapacity, Allocator& allocator) { + ObjectData& o = data_.o; + if (newCapacity > o.capacity) { + Member* newMembers = allocator.Reallocate(GetMembersPointer(), o.capacity, newCapacity); + RAPIDJSON_SETPOINTER(Member, o.members, newMembers); + o.capacity = newCapacity; + } + } + + template + MemberIterator DoFindMember(const GenericValue& name) { + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } +#endif + + 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); +#ifdef RAPIDJSON_USE_MEMBERS_MAP + MemberMap* map = GetMembersMap(members); + MemberMapIterator* mit = GetMapIterators(map); + StringRefType k(m->name.GetString(), m->name.GetStringLength()); + mit[o.size] = map->insert(MemberMapPair(k, o.size)); +#endif + ++o.size; + } + + MemberIterator DoRemoveMember(MemberIterator m) { + ObjectData& o = data_.o; + Member* members = GetMembersPointer(); + MemberIterator last(members + (o.size - 1)); + if (o.size > 1 && m != last) { +#ifdef RAPIDJSON_USE_MEMBERS_MAP + MemberMap* map = GetMembersMap(members); + MemberMapIterator* mit = GetMapIterators(map); + SizeType mpos = static_cast(&*m - members); + map->erase(mit[mpos]); + mit[mpos] = mit[&*last - members]; + mit[mpos]->second = mpos; +#endif + *m = *last; // Move the last one to this place + } + else { +#ifdef RAPIDJSON_USE_MEMBERS_MAP + MemberMap* map = GetMembersMap(members); + MemberMapIterator* mit = GetMapIterators(map); + map->erase(mit[m - MemberBegin()]); +#endif + m->~Member(); // Only one left, just destroy + } + --o.size; + return m; + } + + MemberIterator DoEraseMember(ConstMemberIterator first, ConstMemberIterator last) { + ObjectData& o = data_.o; + MemberIterator beg = MemberBegin(), + pos = beg + (first - beg), + end = MemberEnd(); +#ifdef RAPIDJSON_USE_MEMBERS_MAP + MemberMap* map = GetMembersMap(GetMembersPointer()); + MemberMapIterator *mit = GetMapIterators(map); +#endif + for (MemberIterator itr = pos; itr != last; ++itr) { +#ifdef RAPIDJSON_USE_MEMBERS_MAP + map->erase(mit[itr - beg]); +#endif + itr->~Member(); + } +#ifdef RAPIDJSON_USE_MEMBERS_MAP + if (pos != last) { + MemberIterator next = pos + (last - first); + for (MemberIterator itr = pos; next != end; ++itr, ++next) { + std::memcpy(static_cast(&*itr), &*next, sizeof(Member)); + SizeType mpos = static_cast(itr - beg); + mit[mpos] = mit[next - beg]; + mit[mpos]->second = mpos; + } + } +#else + std::memmove(static_cast(&*pos), &*last, + static_cast(end - last) * sizeof(Member)); +#endif + o.size -= static_cast(last - first); + return pos; + } + + template + void DoCopyMembers(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings) { + RAPIDJSON_ASSERT(rhs.GetType() == kObjectType); + + data_.f.flags = kObjectFlag; + SizeType count = rhs.data_.o.size; + Member* m = DoAllocMembers(count, allocator); + const typename GenericValue::Member* rm = rhs.GetMembersPointer(); +#ifdef RAPIDJSON_USE_MEMBERS_MAP + MemberMap* map = GetMembersMap(m); + MemberMapIterator* mit = GetMapIterators(map); +#endif + for (SizeType i = 0; i < count; i++) { + new (&m[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); + new (&m[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); +#ifdef RAPIDJSON_USE_MEMBERS_MAP + StringRefType k(m[i].name.GetString(), m[i].name.GetStringLength()); + mit[i] = map->insert(MemberMapPair(k, i)); +#endif + } + data_.o.size = data_.o.capacity = count; + SetMembersPointer(m); + } + + void DoClearMembers(bool free) { + if (Member* members = GetMembersPointer()) { + ObjectData& o = data_.o; + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + if (free) { + RAPIDJSON_SETPOINTER(Member, o.members, 0); +#ifdef RAPIDJSON_USE_MEMBERS_MAP + MemberMap* map = GetMembersMap(members); + map->~MemberMap(); + Allocator::Free(map); +#else + Allocator::Free(members); +#endif + o.capacity = 0; + } +#ifdef RAPIDJSON_USE_MEMBERS_MAP + else { + GetMembersMap(members)->clear(); + } +#endif + o.size = 0; + } + } + // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { data_.f.flags = kArrayFlag; @@ -2047,13 +2273,23 @@ class GenericValue { void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { data_.f.flags = kObjectFlag; if (count) { - Member* m = allocator.template Allocate(count); - SetMembersPointer(m); + Member* m = DoAllocMembers(count, allocator); std::memcpy(static_cast(m), members, count * sizeof(Member)); +#ifdef RAPIDJSON_USE_MEMBERS_MAP + MemberMap* map = GetMembersMap(m); + MemberMapIterator* mit = GetMapIterators(map); + for (SizeType i = 0; i < count; i++) { + StringRefType k(m[i].name.GetString(), m[i].name.GetStringLength()); + mit[i] = map->insert(MemberMapPair(k, i)); + } +#endif + data_.o.size = data_.o.capacity = count; + SetMembersPointer(m); } - else + else { + data_.o.size = data_.o.capacity = 0; SetMembersPointer(0); - data_.o.size = data_.o.capacity = count; + } } //! Initialize this value as constant string, without calling destructor. diff --git a/test/perftest/perftest.h b/test/perftest/perftest.h index 953f95de8..3c0bd0868 100644 --- a/test/perftest/perftest.h +++ b/test/perftest/perftest.h @@ -130,7 +130,8 @@ class PerfTest : public ::testing::Test { "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 @@ class PerfTest : public ::testing::Test { 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 @@ class PerfTest : public ::testing::Test { 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; }; diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 9492cc57d..ee0008b65 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -26,6 +26,7 @@ #include "rapidjson/memorystream.h" #include +#include #ifdef RAPIDJSON_SSE2 #define SIMD_SUFFIX(name) name##_SSE2 @@ -52,7 +53,7 @@ class RapidJson : public PerfTest { // 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 @@ class RapidJson : public PerfTest { 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 typename Document::ValueType ValueType; + typedef typename ValueType::ConstMemberIterator ConstMemberIterator; + const Document &doc = typesDoc_[7]; // alotofkeys.json + if (doc.IsObject()) { + std::vector 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; From 32d006d554dece6cf2880edf24969805792a1528 Mon Sep 17 00:00:00 2001 From: ylavic Date: Thu, 11 Apr 2019 18:09:48 +0200 Subject: [PATCH 3/4] RAPIDJSON_NOEXCEPT_ASSERT() should never throw. clang warns about throwing from RAPIDJSON_NOEXCEPT_ASSERT() in a nothrow context. If RAPIDJSON_ASSERT() throws it can never be used for _NOEXCEPT_ASSERT(), so use C assert() instead. Finally (and originally), since RAPIDJSON_ASSERT() in "unittest.h" throws, make it define RAPIDJSON_ASSERT_THROWS for RAPIDJSON_NOEXCEPT_ASSERT() to now do the right thing. --- include/rapidjson/rapidjson.h | 3 ++- test/unittest/unittest.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 2a0400e6d..968dd8fac 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -612,7 +612,8 @@ RAPIDJSON_NAMESPACE_END #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT_ASSERT(x) #else -#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) +#include +#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT #else #define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index 84c1b7348..0afac09cb 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -122,6 +122,9 @@ class AssertException : public std::logic_error { #ifndef RAPIDJSON_ASSERT #define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u) +#ifndef RAPIDJSON_ASSERT_THROWS +#define RAPIDJSON_ASSERT_THROWS +#endif #endif class Random { From 41e5efecc1dbd2befbe8888e783930ac0854a330 Mon Sep 17 00:00:00 2001 From: ylavic Date: Thu, 11 Apr 2019 19:56:58 +0200 Subject: [PATCH 4/4] Address some compilation failures with various compilers. --- include/rapidjson/allocators.h | 50 ++++++++++++++++++++++++++++------ include/rapidjson/document.h | 4 +-- include/rapidjson/rapidjson.h | 4 +++ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h index 6de4abd48..801558fd1 100644 --- a/include/rapidjson/allocators.h +++ b/include/rapidjson/allocators.h @@ -18,12 +18,17 @@ #include "rapidjson.h" #include -#if RAPIDJSON_HAS_CXX11_TYPETRAITS +#if RAPIDJSON_HAS_CXX11 #include #endif RAPIDJSON_NAMESPACE_BEGIN +RAPIDJSON_DIAG_PUSH +#ifdef __GNUC__ +RAPIDJSON_DIAG_OFF(effc++) +#endif + /////////////////////////////////////////////////////////////////////////////// // Allocator @@ -89,7 +94,7 @@ class StdBaseAllocator { }; StdBaseAllocator(Allocator &allocator) RAPIDJSON_NOEXCEPT : - allocator_(allocator) { + allocator_(&allocator) { } StdBaseAllocator(const StdBaseAllocator& other) RAPIDJSON_NOEXCEPT : @@ -101,6 +106,14 @@ class StdBaseAllocator { allocator_(other.allocator_) { } +#if RAPIDJSON_HAS_CXX11 + StdBaseAllocator(StdBaseAllocator&& other) RAPIDJSON_NOEXCEPT : + allocator_(other.allocator_) { + } + using propagate_on_container_move_assignment = std::true_type; + using is_always_equal = std::is_empty; +#endif + size_type max_size() const RAPIDJSON_NOEXCEPT { return static_cast(-1) / sizeof(value_type); } @@ -128,7 +141,7 @@ class StdBaseAllocator { void construct(pointer p, const_reference r) { ::new(static_cast(p)) value_type(r); } -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if RAPIDJSON_HAS_CXX11 template void construct(OtherType* p, Args&&... args) { ::new(static_cast(p)) OtherType(std::forward(args)...); @@ -156,10 +169,11 @@ class StdBaseAllocator { } pointer Reallocate(pointer old, size_type old_n, size_type new_n) { RAPIDJSON_ASSERT(sizeof(value_type) == 1 || new_n <= max_size()); - return static_cast(allocator_.Realloc(old, old_n * sizeof(value_type), - new_n * sizeof(value_type))); + return static_cast(allocator_->Realloc(old, old_n * sizeof(value_type), + new_n * sizeof(value_type))); } -#if 0 && RAPIDJSON_HAS_CXX11_RVALUE_REFS + +#if RAPIDJSON_HAS_CXX11 template OtherType *New(Args&&... args) { typename rebind::other a(*this); @@ -176,11 +190,29 @@ class StdBaseAllocator { #endif private: + Allocator *allocator_; + StdBaseAllocator() /* = delete */; - template friend class StdBaseAllocator; // OtherType::allocator_ - Allocator &allocator_; + + // For OtherType::allocator_ + template + friend class StdBaseAllocator; + template + friend bool operator==(const StdBaseAllocator& a1, + const StdBaseAllocator& a2) RAPIDJSON_NOEXCEPT; }; +template +bool operator==(const StdBaseAllocator& a1, + const StdBaseAllocator& a2) RAPIDJSON_NOEXCEPT { + return a1.allocator_ == a2.allocator_; +} +template +bool operator!=(const StdBaseAllocator& a1, + const StdBaseAllocator& a2) RAPIDJSON_NOEXCEPT { + return !(a1 == a2); +} + /////////////////////////////////////////////////////////////////////////////// // CrtAllocator @@ -406,6 +438,8 @@ class MemoryPoolAllocator : public StdBaseAllocator StringRef(const std::basic_string& s #ifdef RAPIDJSON_USE_MEMBERS_MAP template struct GenericMemberMap { - typedef Allocator AllocatorType; typedef typename Encoding::Ch Ch; typedef GenericStringRef KeyType; struct KeyLess { @@ -421,9 +420,10 @@ struct GenericMemberMap { return cmp < 0 || (cmp == 0 && s1.length < s2.length); } }; + typedef std::pair Pair; + typedef typename Allocator::template rebind::other AllocatorType; typedef std::multimap Map; typedef typename Map::iterator Iterator; - typedef typename Map::value_type Pair; }; #endif diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 968dd8fac..240c2db15 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -535,6 +535,10 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // C++11 features +#ifndef RAPIDJSON_HAS_CXX11 +#define RAPIDJSON_HAS_CXX11 (__cplusplus >= 201103L) +#endif + #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS #if defined(__clang__) #if __has_feature(cxx_rvalue_references) && \