Merge pull request #1503 from ylavic/sub_value_assignment

Fix (Sub-)Value assignment
diff --git a/.travis.yml b/.travis.yml
index 8f34664..4be5ef2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,51 +28,63 @@
 matrix:
   include:
     # gcc
-    - env: CONF=release ARCH=x86    CXX11=ON
+    - env: CONF=release ARCH=x86    CXX11=ON CXX17=OFF
       compiler: gcc
       arch: amd64
-    - env: CONF=release ARCH=x86_64 CXX11=ON
+    - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF
       compiler: gcc
       arch: amd64
-    - env: CONF=debug   ARCH=x86    CXX11=OFF
+    - env: CONF=debug   ARCH=x86    CXX11=OFF CXX17=OFF
       compiler: gcc
       arch: amd64
-    - env: CONF=debug   ARCH=x86_64 CXX11=OFF
+    - env: CONF=debug   ARCH=x86_64 CXX11=OFF CXX17=OFF
       compiler: gcc
       arch: amd64
-    - env: CONF=release ARCH=aarch64 CXX11=ON
+    - 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'
+      compiler: gcc
+      arch: amd64
+    - env: CONF=release ARCH=aarch64 CXX11=ON CXX17=OFF
       compiler: gcc
       arch: arm64
-    - env: CONF=debug   ARCH=aarch64 CXX11=OFF
+    - env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=OFF
+      compiler: gcc
+      arch: arm64
+    - env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=ON
       compiler: gcc
       arch: arm64
     # clang
-    - env: CONF=debug   ARCH=x86    CXX11=ON CCACHE_CPP2=yes
+    - env: CONF=release ARCH=x86    CXX11=ON CXX17=OFF CCACHE_CPP2=yes
       compiler: clang
       arch: amd64
-    - env: CONF=debug   ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
+    - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF CCACHE_CPP2=yes
       compiler: clang
       arch: amd64
-    - env: CONF=debug   ARCH=x86    CXX11=OFF CCACHE_CPP2=yes
+    - env: CONF=debug   ARCH=x86    CXX11=OFF CXX17=OFF CCACHE_CPP2=yes
       compiler: clang
       arch: amd64
-    - env: CONF=debug   ARCH=x86_64 CXX11=OFF CCACHE_CPP2=yes
+    - env: CONF=debug   ARCH=x86_64 CXX11=OFF CXX17=OFF CCACHE_CPP2=yes
       compiler: clang
       arch: amd64
-    - env: CONF=release ARCH=x86    CXX11=ON CCACHE_CPP2=yes
+    - env: CONF=debug   ARCH=x86    CXX11=OFF CXX17=ON CCACHE_CPP2=yes
       compiler: clang
       arch: amd64
-    - env: CONF=release ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
+    - env: CONF=debug   ARCH=x86_64 CXX11=OFF CXX17=ON CCACHE_CPP2=yes
       compiler: clang
       arch: amd64
-    - env: CONF=debug   ARCH=aarch64 CXX11=ON CCACHE_CPP2=yes
+    - env: CONF=debug   ARCH=aarch64 CXX11=ON CXX17=OFF CCACHE_CPP2=yes
       compiler: clang
       arch: arm64
-    - env: CONF=debug   ARCH=aarch64 CXX11=OFF CCACHE_CPP2=yes
+    - env: CONF=debug   ARCH=aarch64 CXX11=OFF CXX17=OFF CCACHE_CPP2=yes
+      compiler: clang
+      arch: arm64
+    - env: CONF=debug   ARCH=aarch64 CXX11=OFF CXX17=ON CCACHE_CPP2=yes
       compiler: clang
       arch: arm64
     # coverage report
-    - env: CONF=debug   ARCH=x86    CXX11=ON GCOV_FLAGS='--coverage'
+    - env: CONF=debug   ARCH=x86     GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=OFF CXX17=OFF
       compiler: gcc
       arch: amd64
       cache:
@@ -81,7 +93,7 @@
       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'
+    - env: CONF=debug   ARCH=x86_64  GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=ON CXX17=OFF
       compiler: gcc
       arch: amd64
       cache:
@@ -90,7 +102,7 @@
       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=aarch64 GCOV_FLAGS='--coverage'
+    - env: CONF=debug   ARCH=aarch64 GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=OFF CXX17=ON
       compiler: gcc
       arch: arm64
       cache:
@@ -135,9 +147,10 @@
       (cd build && cmake
       -DRAPIDJSON_HAS_STDSTRING=ON
       -DRAPIDJSON_BUILD_CXX11=$CXX11
+      -DRAPIDJSON_BUILD_CXX17=$CXX17
       -DCMAKE_VERBOSE_MAKEFILE=ON
       -DCMAKE_BUILD_TYPE=$CONF
-      -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"
+      -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS $CXX_FLAGS"
       -DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS
       ..)
   - cd build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3b9ac51..dcca04f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,7 +35,8 @@
 option(RAPIDJSON_BUILD_THIRDPARTY_GTEST
     "Use gtest installation in `thirdparty/gtest` by default if available" OFF)
 
-option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON)
+option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11" ON)
+option(RAPIDJSON_BUILD_CXX17 "Build rapidjson with C++17" OFF)
 if(RAPIDJSON_BUILD_CXX11)
     set(CMAKE_CXX_STANDARD 11)
     set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
@@ -77,6 +78,8 @@
         else()
             set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
         endif()
+    elseif (RAPIDJSON_BUILD_CXX17 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
     endif()
     if (RAPIDJSON_BUILD_ASAN)
         if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.0")
@@ -105,6 +108,8 @@
     set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough)
     if (RAPIDJSON_BUILD_CXX11 AND CMAKE_VERSION VERSION_LESS 3.1)
         set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+    elseif (RAPIDJSON_BUILD_CXX17 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.0")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
     endif()
     if (RAPIDJSON_BUILD_ASAN)
         set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
@@ -119,6 +124,18 @@
 elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
     add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
+    # CMake >= 3.10 should handle the above CMAKE_CXX_STANDARD fine, otherwise use /std:c++XX with MSVC >= 19.10
+    if (RAPIDJSON_BUILD_CXX11 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.10")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++11")
+    elseif (RAPIDJSON_BUILD_CXX17 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.14")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17")
+    endif()
+    # Always compile with /WX
+    if(CMAKE_CXX_FLAGS MATCHES "/WX-")
+        string(REGEX REPLACE "/WX-" "/WX" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+    else()
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX")
+    endif()
 elseif (CMAKE_CXX_COMPILER_ID MATCHES "XL")
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -qarch=auto")
 endif()
diff --git a/appveyor.yml b/appveyor.yml
index 376dc19..2e591ee 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -13,37 +13,72 @@
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
     VS_VERSION: 10 2010
     VS_PLATFORM: win32
+    CXX11: OFF
+    CXX17: OFF
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
     VS_VERSION: 10 2010
     VS_PLATFORM: x64
+    CXX11: OFF
+    CXX17: OFF
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
     VS_VERSION: 11 2012
     VS_PLATFORM: win32
+    CXX11: OFF
+    CXX17: OFF
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
     VS_VERSION: 11 2012
     VS_PLATFORM: x64
+    CXX11: OFF
+    CXX17: OFF
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
     VS_VERSION: 12 2013
     VS_PLATFORM: win32
+    CXX11: OFF
+    CXX17: OFF
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
     VS_VERSION: 12 2013
     VS_PLATFORM: x64
+    CXX11: OFF
+    CXX17: OFF
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
     VS_VERSION: 14 2015
     VS_PLATFORM: win32
+    CXX11: OFF
+    CXX17: OFF
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
     VS_VERSION: 14 2015
     VS_PLATFORM: x64
+    CXX11: OFF
+    CXX17: OFF
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
     VS_VERSION: 15 2017
     VS_PLATFORM: win32
+    CXX11: OFF
+    CXX17: OFF
   - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
     VS_VERSION: 15 2017
     VS_PLATFORM: x64
+    CXX11: OFF
+    CXX17: OFF
+  - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+    VS_VERSION: 15 2017
+    VS_PLATFORM: x64
+    CXX11: ON
+    CXX17: OFF
+  - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+    VS_VERSION: 15 2017
+    VS_PLATFORM: x64
+    CXX11: OFF
+    CXX17: ON
+  - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+    VS_VERSION: 16 2019
+    VS_PLATFORM: x64
+    CXX11: OFF
+    CXX17: 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 -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% -Wno-dev
 
 build:
   project: Build\VS\RapidJSON.sln
diff --git a/example/traverseaspointer.cpp b/example/traverseaspointer.cpp
new file mode 100644
index 0000000..7e0c899
--- /dev/null
+++ b/example/traverseaspointer.cpp
@@ -0,0 +1,39 @@
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/pointer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+
+void traverse(const Value& v, const Pointer& p) {
+    StringBuffer sb;
+    p.Stringify(sb);
+    std::cout << sb.GetString() << std::endl;
+
+    switch (v.GetType()) {
+    case kArrayType:
+        for (SizeType i = 0; i != v.Size(); ++i)
+            traverse(v[i], p.Append(i));
+        break;
+    case kObjectType:
+        for (Value::ConstMemberIterator m = v.MemberBegin(); m != v.MemberEnd(); ++m) 
+            traverse(m->value, p.Append(m->name.GetString(), m->name.GetStringLength()));
+        break;
+    default:
+        break;
+    }
+}
+
+int main(int, char*[]) {
+    char readBuffer[65536];
+    FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+    Document d;
+    d.ParseStream(is);
+
+    Pointer root;
+    traverse(d, root);
+
+    return 0;
+}
diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h
index 44ec529..cf8e75a 100644
--- a/include/rapidjson/allocators.h
+++ b/include/rapidjson/allocators.h
@@ -17,6 +17,12 @@
 
 #include "rapidjson.h"
 
+#include <memory>
+
+#if RAPIDJSON_HAS_CXX11
+#include <type_traits>
+#endif
+
 RAPIDJSON_NAMESPACE_BEGIN
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -89,7 +95,14 @@
         }
         return RAPIDJSON_REALLOC(originalPtr, newSize);
     }
-    static void Free(void *ptr) { RAPIDJSON_FREE(ptr); }
+    static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
+
+    bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
+        return true;
+    }
+    bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
+        return false;
+    }
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -113,6 +126,36 @@
 */
 template <typename BaseAllocator = CrtAllocator>
 class MemoryPoolAllocator {
+    //! Chunk header for perpending to each chunk.
+    /*! Chunks are stored as a singly linked list.
+    */
+    struct ChunkHeader {
+        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).
+        size_t size;        //!< Current size of allocated memory in bytes.
+        ChunkHeader *next;  //!< Next chunk in the linked list.
+    };
+
+    struct SharedData {
+        ChunkHeader *chunkHead;  //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+        BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
+        size_t refcount;
+        bool ownBuffer;
+    };
+
+    static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
+    static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
+
+    static inline ChunkHeader *GetChunkHead(SharedData *shared)
+    {
+        return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
+    }
+    static inline uint8_t *GetChunkBuffer(SharedData *shared)
+    {
+        return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
+    }
+
+    static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
+
 public:
     static const bool kNeedFree = false;    //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
 
@@ -120,9 +163,26 @@
     /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
         \param baseAllocator The allocator for allocating memory chunks.
     */
+    explicit
     MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 
-        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+        chunk_capacity_(chunkSize),
+        baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
+        shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
     {
+        RAPIDJSON_ASSERT(baseAllocator_ != 0);
+        RAPIDJSON_ASSERT(shared_ != 0);
+        if (baseAllocator) {
+            shared_->ownBaseAllocator = 0;
+        }
+        else {
+            shared_->ownBaseAllocator = baseAllocator_;
+        }
+        shared_->chunkHead = GetChunkHead(shared_);
+        shared_->chunkHead->capacity = 0;
+        shared_->chunkHead->size = 0;
+        shared_->chunkHead->next = 0;
+        shared_->ownBuffer = true;
+        shared_->refcount = 1;
     }
 
     //! Constructor with user-supplied buffer.
@@ -136,41 +196,101 @@
         \param baseAllocator The allocator for allocating memory chunks.
     */
     MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
-        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+        chunk_capacity_(chunkSize),
+        baseAllocator_(baseAllocator),
+        shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
     {
-        RAPIDJSON_ASSERT(buffer != 0);
-        RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
-        chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
-        chunkHead_->capacity = size - sizeof(ChunkHeader);
-        chunkHead_->size = 0;
-        chunkHead_->next = 0;
+        RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
+        shared_->chunkHead = GetChunkHead(shared_);
+        shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
+        shared_->chunkHead->size = 0;
+        shared_->chunkHead->next = 0;
+        shared_->ownBaseAllocator = 0;
+        shared_->ownBuffer = false;
+        shared_->refcount = 1;
     }
 
+    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT :
+        chunk_capacity_(rhs.chunk_capacity_),
+        baseAllocator_(rhs.baseAllocator_),
+        shared_(rhs.shared_)
+    {
+        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+        ++shared_->refcount;
+    }
+    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT
+    {
+        RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+        ++rhs.shared_->refcount;
+        this->~MemoryPoolAllocator();
+        baseAllocator_ = rhs.baseAllocator_;
+        chunk_capacity_ = rhs.chunk_capacity_;
+        shared_ = rhs.shared_;
+        return *this;
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT :
+        chunk_capacity_(rhs.chunk_capacity_),
+        baseAllocator_(rhs.baseAllocator_),
+        shared_(rhs.shared_)
+    {
+        RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+        rhs.shared_ = 0;
+    }
+    MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT
+    {
+        RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+        this->~MemoryPoolAllocator();
+        baseAllocator_ = rhs.baseAllocator_;
+        chunk_capacity_ = rhs.chunk_capacity_;
+        shared_ = rhs.shared_;
+        rhs.shared_ = 0;
+        return *this;
+    }
+#endif
+
     //! Destructor.
     /*! This deallocates all memory chunks, excluding the user-supplied buffer.
     */
-    ~MemoryPoolAllocator() {
+    ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT {
+        if (!shared_) {
+            // do nothing if moved
+            return;
+        }
+        if (shared_->refcount > 1) {
+            --shared_->refcount;
+            return;
+        }
         Clear();
-        RAPIDJSON_DELETE(ownBaseAllocator_);
+        BaseAllocator *a = shared_->ownBaseAllocator;
+        if (shared_->ownBuffer) {
+            baseAllocator_->Free(shared_);
+        }
+        RAPIDJSON_DELETE(a);
     }
 
-    //! Deallocates all memory chunks, excluding the user-supplied buffer.
-    void Clear() {
-        while (chunkHead_ && chunkHead_ != userBuffer_) {
-            ChunkHeader* next = chunkHead_->next;
-            baseAllocator_->Free(chunkHead_);
-            chunkHead_ = next;
+    //! Deallocates all memory chunks, excluding the first/user one.
+    void Clear() RAPIDJSON_NOEXCEPT {
+        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+        for (;;) {
+            ChunkHeader* c = shared_->chunkHead;
+            if (!c->next) {
+                break;
+            }
+            shared_->chunkHead = c->next;
+            baseAllocator_->Free(c);
         }
-        if (chunkHead_ && chunkHead_ == userBuffer_)
-            chunkHead_->size = 0; // Clear user buffer
+        shared_->chunkHead->size = 0;
     }
 
     //! Computes the total capacity of allocated memory chunks.
     /*! \return total capacity in bytes.
     */
-    size_t Capacity() const {
+    size_t Capacity() const RAPIDJSON_NOEXCEPT {
+        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
         size_t capacity = 0;
-        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+        for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
             capacity += c->capacity;
         return capacity;
     }
@@ -178,25 +298,35 @@
     //! Computes the memory blocks allocated.
     /*! \return total used bytes.
     */
-    size_t Size() const {
+    size_t Size() const RAPIDJSON_NOEXCEPT {
+        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
         size_t size = 0;
-        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+        for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
             size += c->size;
         return size;
     }
 
+    //! Whether the allocator is shared.
+    /*! \return true or false.
+    */
+    bool Shared() const RAPIDJSON_NOEXCEPT {
+        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+        return shared_->refcount > 1;
+    }
+
     //! Allocates a memory block. (concept Allocator)
     void* Malloc(size_t size) {
+        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
         if (!size)
             return NULL;
 
         size = RAPIDJSON_ALIGN(size);
-        if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+        if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity))
             if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
                 return NULL;
 
-        void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
-        chunkHead_->size += size;
+        void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size;
+        shared_->chunkHead->size += size;
         return buffer;
     }
 
@@ -205,6 +335,7 @@
         if (originalPtr == 0)
             return Malloc(newSize);
 
+        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
         if (newSize == 0)
             return NULL;
 
@@ -216,10 +347,10 @@
             return originalPtr;
 
         // Simply expand it if it is the last allocation and there is sufficient space
-        if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+        if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
             size_t increment = static_cast<size_t>(newSize - originalSize);
-            if (chunkHead_->size + increment <= chunkHead_->capacity) {
-                chunkHead_->size += increment;
+            if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) {
+                shared_->chunkHead->size += increment;
                 return originalPtr;
             }
         }
@@ -235,50 +366,315 @@
     }
 
     //! Frees a memory block (concept Allocator)
-    static void Free(void *ptr) { (void)ptr; } // Do nothing
+    static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing
+
+    //! Compare (equality) with another MemoryPoolAllocator
+    bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
+        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+        RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+        return shared_ == rhs.shared_;
+    }
+    //! Compare (inequality) with another MemoryPoolAllocator
+    bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
+        return !operator==(rhs);
+    }
 
 private:
-    //! Copy constructor is not permitted.
-    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
-    //! Copy assignment operator is not permitted.
-    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
-
     //! Creates a new chunk.
     /*! \param capacity Capacity of the chunk in bytes.
         \return true if success.
     */
     bool AddChunk(size_t capacity) {
         if (!baseAllocator_)
-            ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
-        if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
+            shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
+        if (ChunkHeader* chunk = static_cast<ChunkHeader*>(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) {
             chunk->capacity = capacity;
             chunk->size = 0;
-            chunk->next = chunkHead_;
-            chunkHead_ =  chunk;
+            chunk->next = shared_->chunkHead;
+            shared_->chunkHead = chunk;
             return true;
         }
         else
             return false;
     }
 
-    static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
+    static inline void* AlignBuffer(void* buf, size_t &size)
+    {
+        RAPIDJSON_NOEXCEPT_ASSERT(buf != 0);
+        const uintptr_t mask = sizeof(void*) - 1;
+        const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf);
+        if (RAPIDJSON_UNLIKELY(ubuf & mask)) {
+            const uintptr_t abuf = (ubuf + mask) & ~mask;
+            RAPIDJSON_ASSERT(size >= abuf - ubuf);
+            buf = reinterpret_cast<void*>(abuf);
+            size -= abuf - ubuf;
+        }
+        return buf;
+    }
 
-    //! Chunk header for perpending to each chunk.
-    /*! Chunks are stored as a singly linked list.
-    */
-    struct ChunkHeader {
-        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).
-        size_t size;        //!< Current size of allocated memory in bytes.
-        ChunkHeader *next;  //!< Next chunk in the linked list.
+    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.
+    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.
+    SharedData *shared_;        //!< The shared data of the allocator
+};
+
+
+template<typename T, typename A>
+inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
+{
+    RAPIDJSON_NOEXCEPT_ASSERT(old_n <= SIZE_MAX / sizeof(T) && new_n <= SIZE_MAX / sizeof(T));
+    return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
+}
+
+template<typename T, typename A>
+inline T *Malloc(A& a, size_t n = 1)
+{
+    return Realloc<T, A>(a, NULL, 0, n);
+}
+
+template<typename T, typename A>
+inline void Free(A& a, T *p, size_t n = 1)
+{
+    static_cast<void>(Realloc<T, A>(a, p, n, 0));
+}
+
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
+#endif
+
+template <typename T, typename BaseAllocator = CrtAllocator>
+class StdAllocator :
+    public std::allocator<T>
+{
+    typedef std::allocator<T> allocator_type;
+#if RAPIDJSON_HAS_CXX11
+    typedef std::allocator_traits<allocator_type> traits_type;
+#else
+    typedef allocator_type traits_type;
+#endif
+
+public:
+    typedef BaseAllocator BaseAllocatorType;
+
+    StdAllocator() RAPIDJSON_NOEXCEPT :
+        allocator_type(),
+        baseAllocator_()
+    { }
+
+    StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
+        allocator_type(rhs),
+        baseAllocator_(rhs.baseAllocator_)
+    { }
+
+    template<typename U>
+    StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
+        allocator_type(rhs),
+        baseAllocator_(rhs.baseAllocator_)
+    { }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT :
+        allocator_type(std::move(rhs)),
+        baseAllocator_(std::move(rhs.baseAllocator_))
+    { }
+#endif
+#if RAPIDJSON_HAS_CXX11
+    using propagate_on_container_move_assignment = std::true_type;
+    using propagate_on_container_swap = std::true_type;
+#endif
+
+    /* implicit */
+    StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT :
+        allocator_type(),
+        baseAllocator_(allocator)
+    { }
+
+    ~StdAllocator() RAPIDJSON_NOEXCEPT
+    { }
+
+    template<typename U>
+    struct rebind {
+        typedef StdAllocator<U, BaseAllocator> other;
     };
 
-    ChunkHeader *chunkHead_;    //!< Head of the chunk linked-list. Only the head chunk serves allocation.
-    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.
-    void *userBuffer_;          //!< User supplied buffer.
-    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.
-    BaseAllocator* ownBaseAllocator_;   //!< base allocator created by this object.
+    typedef typename traits_type::size_type         size_type;
+    typedef typename traits_type::difference_type   difference_type;
+
+    typedef typename traits_type::value_type        value_type;
+    typedef typename traits_type::pointer           pointer;
+    typedef typename traits_type::const_pointer     const_pointer;
+
+#if RAPIDJSON_HAS_CXX11
+
+    typedef typename std::add_lvalue_reference<value_type>::type &reference;
+    typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type &const_reference;
+
+    pointer address(reference r) const RAPIDJSON_NOEXCEPT
+    {
+        return std::addressof(r);
+    }
+    const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
+    {
+        return std::addressof(r);
+    }
+
+    size_type max_size() const RAPIDJSON_NOEXCEPT
+    {
+        return traits_type::max_size(*this);
+    }
+
+    template <typename ...Args>
+    void construct(pointer p, Args&&... args)
+    {
+        traits_type::construct(*this, p, std::forward<Args>(args)...);
+    }
+    void destroy(pointer p)
+    {
+        traits_type::destroy(*this, p);
+    }
+
+#else // !RAPIDJSON_HAS_CXX11
+
+    typedef typename allocator_type::reference       reference;
+    typedef typename allocator_type::const_reference const_reference;
+
+    pointer address(reference r) const RAPIDJSON_NOEXCEPT
+    {
+        return allocator_type::address(r);
+    }
+    const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
+    {
+        return allocator_type::address(r);
+    }
+
+    size_type max_size() const RAPIDJSON_NOEXCEPT
+    {
+        return allocator_type::max_size();
+    }
+
+    void construct(pointer p, const_reference r)
+    {
+        allocator_type::construct(p, r);
+    }
+    void destroy(pointer p)
+    {
+        allocator_type::destroy(p);
+    }
+
+#endif // !RAPIDJSON_HAS_CXX11
+
+    template <typename U>
+    U* allocate(size_type n = 1, const void* = 0)
+    {
+        return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
+    }
+    template <typename U>
+    void deallocate(U* p, size_type n = 1)
+    {
+        RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
+    }
+
+    pointer allocate(size_type n = 1, const void* = 0)
+    {
+        return allocate<value_type>(n);
+    }
+    void deallocate(pointer p, size_type n = 1)
+    {
+        deallocate<value_type>(p, n);
+    }
+
+#if RAPIDJSON_HAS_CXX11
+    using is_always_equal = std::is_empty<BaseAllocator>;
+#endif
+
+    template<typename U>
+    bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
+    {
+        return baseAllocator_ == rhs.baseAllocator_;
+    }
+    template<typename U>
+    bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
+    {
+        return !operator==(rhs);
+    }
+
+    //! rapidjson Allocator concept
+    static const bool kNeedFree = BaseAllocator::kNeedFree;
+    void* Malloc(size_t size)
+    {
+        return baseAllocator_.Malloc(size);
+    }
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
+    {
+        return baseAllocator_.Realloc(originalPtr, originalSize, newSize);
+    }
+    static void Free(void *ptr) RAPIDJSON_NOEXCEPT
+    {
+        BaseAllocator::Free(ptr);
+    }
+
+private:
+    template <typename, typename>
+    friend class StdAllocator; // access to StdAllocator<!T>.*
+
+    BaseAllocator baseAllocator_;
 };
 
+#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
+template <typename BaseAllocator>
+class StdAllocator<void, BaseAllocator> :
+    public std::allocator<void>
+{
+    typedef std::allocator<void> allocator_type;
+
+public:
+    typedef BaseAllocator BaseAllocatorType;
+
+    StdAllocator() RAPIDJSON_NOEXCEPT :
+        allocator_type(),
+        baseAllocator_()
+    { }
+
+    StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
+        allocator_type(rhs),
+        baseAllocator_(rhs.baseAllocator_)
+    { }
+
+    template<typename U>
+    StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
+        allocator_type(rhs),
+        baseAllocator_(rhs.baseAllocator_)
+    { }
+
+    /* implicit */
+    StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT :
+        allocator_type(),
+        baseAllocator_(allocator)
+    { }
+
+    ~StdAllocator() RAPIDJSON_NOEXCEPT
+    { }
+
+    template<typename U>
+    struct rebind {
+        typedef StdAllocator<U, BaseAllocator> other;
+    };
+
+    typedef typename allocator_type::value_type value_type;
+
+private:
+    template <typename, typename>
+    friend class StdAllocator; // access to StdAllocator<!T>.*
+
+    BaseAllocator baseAllocator_;
+};
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
 RAPIDJSON_NAMESPACE_END
 
 #endif // RAPIDJSON_ENCODINGS_H_
diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h
index 78aa89a..1093581 100644
--- a/include/rapidjson/rapidjson.h
+++ b/include/rapidjson/rapidjson.h
@@ -125,6 +125,19 @@
 #endif
 
 ///////////////////////////////////////////////////////////////////////////////
+// __cplusplus macro
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+
+#if defined(_MSC_VER)
+#define RAPIDJSON_CPLUSPLUS _MSVC_LANG
+#else
+#define RAPIDJSON_CPLUSPLUS __cplusplus
+#endif
+
+//!@endcond
+
+///////////////////////////////////////////////////////////////////////////////
 // RAPIDJSON_HAS_STDSTRING
 
 #ifndef RAPIDJSON_HAS_STDSTRING
@@ -411,7 +424,7 @@
 
 // Prefer C++11 static_assert, if available
 #ifndef RAPIDJSON_STATIC_ASSERT
-#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
+#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
 #define RAPIDJSON_STATIC_ASSERT(x) \
    static_assert(x, RAPIDJSON_STRINGIFY(x))
 #endif // C++11
@@ -541,8 +554,14 @@
 ///////////////////////////////////////////////////////////////////////////////
 // C++11 features
 
+#ifndef RAPIDJSON_HAS_CXX11
+#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L)
+#endif
+
 #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
-#if defined(__clang__)
+#if RAPIDJSON_HAS_CXX11
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#elif defined(__clang__)
 #if __has_feature(cxx_rvalue_references) && \
     (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
 #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
@@ -560,7 +579,9 @@
 #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
 
 #ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
-#if defined(__clang__)
+#if RAPIDJSON_HAS_CXX11
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
+#elif defined(__clang__)
 #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
 #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
     (defined(_MSC_VER) && _MSC_VER >= 1900) || \
@@ -570,11 +591,13 @@
 #define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
 #endif
 #endif
+#ifndef RAPIDJSON_NOEXCEPT
 #if RAPIDJSON_HAS_CXX11_NOEXCEPT
 #define RAPIDJSON_NOEXCEPT noexcept
 #else
-#define RAPIDJSON_NOEXCEPT /* noexcept */
+#define RAPIDJSON_NOEXCEPT throw()
 #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
+#endif
 
 // no automatic detection, yet
 #ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
@@ -600,9 +623,17 @@
 ///////////////////////////////////////////////////////////////////////////////
 // C++17 features
 
-#if defined(__has_cpp_attribute)
-# if __has_cpp_attribute(fallthrough)
-#  define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
+#ifndef RAPIDJSON_HAS_CXX17
+#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L)
+#endif
+
+#if RAPIDJSON_HAS_CXX17
+# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
+#elif defined(__has_cpp_attribute)
+# if __has_cpp_attribute(clang::fallthrough)
+#  define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]]
+# elif __has_cpp_attribute(fallthrough)
+#  define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough))
 # else
 #  define RAPIDJSON_DELIBERATE_FALLTHROUGH
 # endif
@@ -628,12 +659,8 @@
 
 #ifndef RAPIDJSON_NOEXCEPT_ASSERT
 #ifdef RAPIDJSON_ASSERT_THROWS
-#if RAPIDJSON_HAS_CXX11_NOEXCEPT
-#define RAPIDJSON_NOEXCEPT_ASSERT(x)
-#else
 #include <cassert>
 #define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x)
-#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
 #else
 #define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
 #endif // RAPIDJSON_ASSERT_THROWS
diff --git a/test/unittest/allocatorstest.cpp b/test/unittest/allocatorstest.cpp
index c541f04..2ffc325 100644
--- a/test/unittest/allocatorstest.cpp
+++ b/test/unittest/allocatorstest.cpp
@@ -16,6 +16,11 @@
 
 #include "rapidjson/allocators.h"
 
+#include <map>
+#include <string>
+#include <utility>
+#include <functional>
+
 using namespace rapidjson;
 
 template <typename Allocator>
@@ -47,19 +52,206 @@
     EXPECT_TRUE(a.Realloc(a.Malloc(1), 1, 0) == 0);
 }
 
+struct TestStdAllocatorData {
+    TestStdAllocatorData(int &constructions, int &destructions) :
+        constructions_(&constructions),
+        destructions_(&destructions)
+    {
+        ++*constructions_;
+    }
+    TestStdAllocatorData(const TestStdAllocatorData& rhs) :
+        constructions_(rhs.constructions_),
+        destructions_(rhs.destructions_)
+    {
+        ++*constructions_;
+    }
+    TestStdAllocatorData& operator=(const TestStdAllocatorData& rhs)
+    {
+        this->~TestStdAllocatorData();
+        constructions_ = rhs.constructions_;
+        destructions_ = rhs.destructions_;
+        ++*constructions_;
+        return *this;
+    }
+    ~TestStdAllocatorData()
+    {
+        ++*destructions_;
+    }
+private:
+    TestStdAllocatorData();
+    int *constructions_,
+        *destructions_;
+};
+
+template <typename Allocator>
+void TestStdAllocator(const Allocator& a) {
+#if RAPIDJSON_HAS_CXX17
+    typedef StdAllocator<bool, Allocator> BoolAllocator;
+#else
+    typedef StdAllocator<void, Allocator> VoidAllocator;
+    typedef typename VoidAllocator::template rebind<bool>::other BoolAllocator;
+#endif
+    BoolAllocator ba(a), ba2(a);
+    EXPECT_TRUE(ba == ba2);
+    EXPECT_FALSE(ba!= ba2);
+    ba.deallocate(ba.allocate());
+    EXPECT_TRUE(ba == ba2);
+    EXPECT_FALSE(ba != ba2);
+
+    unsigned long long ll = 0, *llp = &ll;
+    const unsigned long long cll = 0, *cllp = &cll;
+    StdAllocator<unsigned long long, Allocator> lla(a);
+    EXPECT_EQ(lla.address(ll), llp);
+    EXPECT_EQ(lla.address(cll), cllp);
+    EXPECT_TRUE(lla.max_size() > 0 && lla.max_size() <= SIZE_MAX / sizeof(unsigned long long));
+
+    int *arr;
+    StdAllocator<int, Allocator> ia(a);
+    arr = ia.allocate(10 * sizeof(int));
+    EXPECT_TRUE(arr != 0);
+    for (int i = 0; i < 10; ++i) {
+        arr[i] = 0x0f0f0f0f;
+    }
+    ia.deallocate(arr, 10);
+    arr = Malloc<int>(ia, 10);
+    EXPECT_TRUE(arr != 0);
+    for (int i = 0; i < 10; ++i) {
+        arr[i] = 0x0f0f0f0f;
+    }
+    arr = Realloc<int>(ia, arr, 10, 20);
+    EXPECT_TRUE(arr != 0);
+    for (int i = 0; i < 10; ++i) {
+        EXPECT_EQ(arr[i], 0x0f0f0f0f);
+    }
+    for (int i = 10; i < 20; i++) {
+        arr[i] = 0x0f0f0f0f;
+    }
+    Free<int>(ia, arr, 20);
+
+    int cons = 0, dest = 0;
+    StdAllocator<TestStdAllocatorData, Allocator> da(a);
+    for (int i = 1; i < 10; i++) {
+        TestStdAllocatorData *d = da.allocate();
+        EXPECT_TRUE(d != 0);
+
+        da.destroy(new(d) TestStdAllocatorData(cons, dest));
+        EXPECT_EQ(cons, i);
+        EXPECT_EQ(dest, i);
+
+        da.deallocate(d);
+    }
+
+    typedef StdAllocator<char, Allocator> CharAllocator;
+    typedef std::basic_string<char, std::char_traits<char>, CharAllocator> String;
+#if RAPIDJSON_HAS_CXX11
+    String s(CharAllocator{a});
+#else
+    CharAllocator ca(a);
+    String s(ca);
+#endif
+    for (int i = 0; i < 26; i++) {
+        s.push_back(static_cast<char>('A' + i));
+    }
+    EXPECT_TRUE(s == "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+    typedef StdAllocator<std::pair<const int, bool>, Allocator> MapAllocator;
+    typedef std::map<int, bool, std::less<int>, MapAllocator> Map;
+#if RAPIDJSON_HAS_CXX11
+    Map map(std::less<int>(), MapAllocator{a});
+#else
+    MapAllocator ma(a);
+    Map map(std::less<int>(), ma);
+#endif
+    for (int i = 0; i < 10; i++) {
+        map.insert(std::make_pair(i, (i % 2) == 0));
+    }
+    EXPECT_TRUE(map.size() == 10);
+    for (int i = 0; i < 10; i++) {
+        typename Map::iterator it = map.find(i);
+        EXPECT_TRUE(it != map.end());
+        EXPECT_TRUE(it->second == ((i % 2) == 0));
+    }
+}
+
 TEST(Allocator, CrtAllocator) {
     CrtAllocator a;
+
     TestAllocator(a);
+    TestStdAllocator(a);
+
+    CrtAllocator a2;
+    EXPECT_TRUE(a == a2);
+    EXPECT_FALSE(a != a2);
+    a2.Free(a2.Malloc(1));
+    EXPECT_TRUE(a == a2);
+    EXPECT_FALSE(a != a2);
 }
 
 TEST(Allocator, MemoryPoolAllocator) {
-    MemoryPoolAllocator<> a;
+    const size_t capacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY;
+    MemoryPoolAllocator<> a(capacity);
+
+    a.Clear(); // noop
+    EXPECT_EQ(a.Size(), 0u);
+    EXPECT_EQ(a.Capacity(), 0u);
+    EXPECT_EQ(a.Shared(), false);
+    {
+        MemoryPoolAllocator<> a2(a);
+        EXPECT_EQ(a2.Shared(), true);
+        EXPECT_EQ(a.Shared(), true);
+        EXPECT_TRUE(a == a2);
+        EXPECT_FALSE(a != a2);
+        a2.Free(a2.Malloc(1));
+        EXPECT_TRUE(a == a2);
+        EXPECT_FALSE(a != a2);
+    }
+    EXPECT_EQ(a.Shared(), false);
+    EXPECT_EQ(a.Capacity(), capacity);
+    EXPECT_EQ(a.Size(), 8u); // aligned
+    a.Clear();
+    EXPECT_EQ(a.Capacity(), 0u);
+    EXPECT_EQ(a.Size(), 0u);
+
     TestAllocator(a);
+    TestStdAllocator(a);
 
     for (size_t i = 1; i < 1000; i++) {
         EXPECT_TRUE(a.Malloc(i) != 0);
         EXPECT_LE(a.Size(), a.Capacity());
     }
+
+    CrtAllocator baseAllocator;
+    a = MemoryPoolAllocator<>(capacity, &baseAllocator);
+    EXPECT_EQ(a.Capacity(), 0u);
+    EXPECT_EQ(a.Size(), 0u);
+    a.Free(a.Malloc(1));
+    EXPECT_EQ(a.Capacity(), capacity);
+    EXPECT_EQ(a.Size(), 8u); // aligned
+
+    {
+        a.Clear();
+        const size_t bufSize = 1024;
+        char *buffer = (char *)a.Malloc(bufSize);
+        MemoryPoolAllocator<> aligned_a(buffer, bufSize);
+        EXPECT_TRUE(aligned_a.Capacity() > 0 && aligned_a.Capacity() <= bufSize);
+        EXPECT_EQ(aligned_a.Size(), 0u);
+        aligned_a.Free(aligned_a.Malloc(1));
+        EXPECT_TRUE(aligned_a.Capacity() > 0 && aligned_a.Capacity() <= bufSize);
+        EXPECT_EQ(aligned_a.Size(), 8u); // aligned
+    }
+
+    {
+        a.Clear();
+        const size_t bufSize = 1024;
+        char *buffer = (char *)a.Malloc(bufSize);
+        RAPIDJSON_ASSERT(bufSize % sizeof(void*) == 0);
+        MemoryPoolAllocator<> unaligned_a(buffer + 1, bufSize - 1);
+        EXPECT_TRUE(unaligned_a.Capacity() > 0 && unaligned_a.Capacity() <= bufSize - sizeof(void*));
+        EXPECT_EQ(unaligned_a.Size(), 0u);
+        unaligned_a.Free(unaligned_a.Malloc(1));
+        EXPECT_TRUE(unaligned_a.Capacity() > 0 && unaligned_a.Capacity() <= bufSize - sizeof(void*));
+        EXPECT_EQ(unaligned_a.Size(), 8u); // aligned
+    }
 }
 
 TEST(Allocator, Alignment) {