Coverage Report

Created: 2026-07-25 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rapidjson/include/rapidjson/allocators.h
Line
Count
Source
1
// Tencent is pleased to support the open source community by making RapidJSON available.
2
// 
3
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
4
//
5
// Licensed under the MIT License (the "License"); you may not use this file except
6
// in compliance with the License. You may obtain a copy of the License at
7
//
8
// http://opensource.org/licenses/MIT
9
//
10
// Unless required by applicable law or agreed to in writing, software distributed 
11
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
12
// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
13
// specific language governing permissions and limitations under the License.
14
15
#ifndef RAPIDJSON_ALLOCATORS_H_
16
#define RAPIDJSON_ALLOCATORS_H_
17
18
#include "rapidjson.h"
19
#include "internal/meta.h"
20
21
#include <memory>
22
#include <limits>
23
24
#if RAPIDJSON_HAS_CXX11
25
#include <type_traits>
26
#endif
27
28
RAPIDJSON_NAMESPACE_BEGIN
29
30
///////////////////////////////////////////////////////////////////////////////
31
// Allocator
32
33
/*! \class rapidjson::Allocator
34
    \brief Concept for allocating, resizing and freeing memory block.
35
    
36
    Note that Malloc() and Realloc() are non-static but Free() is static.
37
    
38
    So if an allocator need to support Free(), it needs to put its pointer in 
39
    the header of memory block.
40
41
\code
42
concept Allocator {
43
    static const bool kNeedFree;    //!< Whether this allocator needs to call Free().
44
45
    // Allocate a memory block.
46
    // \param size of the memory block in bytes.
47
    // \returns pointer to the memory block.
48
    void* Malloc(size_t size);
49
50
    // Resize a memory block.
51
    // \param originalPtr The pointer to current memory block. Null pointer is permitted.
52
    // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
53
    // \param newSize the new size in bytes.
54
    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
55
56
    // Free a memory block.
57
    // \param pointer to the memory block. Null pointer is permitted.
58
    static void Free(void *ptr);
59
};
60
\endcode
61
*/
62
63
64
/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
65
    \ingroup RAPIDJSON_CONFIG
66
    \brief User-defined kDefaultChunkCapacity definition.
67
68
    User can define this as any \c size that is a power of 2.
69
*/
70
71
#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
72
#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
73
#endif
74
75
76
///////////////////////////////////////////////////////////////////////////////
77
// CrtAllocator
78
79
//! C-runtime library allocator.
80
/*! This class is just wrapper for standard C library memory routines.
81
    \note implements Allocator concept
82
*/
83
class CrtAllocator {
84
public:
85
    static const bool kNeedFree = true;
86
222
    void* Malloc(size_t size) { 
87
222
        if (size) //  behavior of malloc(0) is implementation defined.
88
222
            return RAPIDJSON_MALLOC(size);
89
0
        else
90
0
            return NULL; // standardize to returning NULL.
91
222
    }
92
1.44k
    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
93
1.44k
        (void)originalSize;
94
1.44k
        if (newSize == 0) {
95
0
            RAPIDJSON_FREE(originalPtr);
96
0
            return NULL;
97
0
        }
98
1.44k
        return RAPIDJSON_REALLOC(originalPtr, newSize);
99
1.44k
    }
100
594
    static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
101
102
0
    bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
103
0
        return true;
104
0
    }
105
0
    bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
106
0
        return false;
107
0
    }
108
};
109
110
///////////////////////////////////////////////////////////////////////////////
111
// MemoryPoolAllocator
112
113
//! Default memory allocator used by the parser and DOM.
114
/*! This allocator allocate memory blocks from pre-allocated memory chunks. 
115
116
    It does not free memory blocks. And Realloc() only allocate new memory.
117
118
    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
119
120
    User may also supply a buffer as the first chunk.
121
122
    If the user-buffer is full then additional chunks are allocated by BaseAllocator.
123
124
    The user-buffer is not deallocated by this allocator.
125
126
    \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
127
    \note implements Allocator concept
128
*/
129
template <typename BaseAllocator = CrtAllocator>
130
class MemoryPoolAllocator {
131
    //! Chunk header for perpending to each chunk.
132
    /*! Chunks are stored as a singly linked list.
133
    */
134
    struct ChunkHeader {
135
        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).
136
        size_t size;        //!< Current size of allocated memory in bytes.
137
        ChunkHeader *next;  //!< Next chunk in the linked list.
138
    };
139
140
    struct SharedData {
141
        ChunkHeader *chunkHead;  //!< Head of the chunk linked-list. Only the head chunk serves allocation.
142
        BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
143
        size_t refcount;
144
        bool ownBuffer;
145
    };
146
147
    static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
148
    static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
149
150
    static inline ChunkHeader *GetChunkHead(SharedData *shared)
151
108
    {
152
108
        return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
153
108
    }
154
    static inline uint8_t *GetChunkBuffer(SharedData *shared)
155
35.9k
    {
156
35.9k
        return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
157
35.9k
    }
158
159
    static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
160
161
public:
162
    static const bool kNeedFree = false;    //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
163
    static const bool kRefCounted = true;   //!< Tell users that this allocator is reference counted on copy
164
165
    //! Constructor with chunkSize.
166
    /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
167
        \param baseAllocator The allocator for allocating memory chunks.
168
    */
169
    explicit
170
    MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 
171
108
        chunk_capacity_(chunkSize),
172
108
        baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
173
108
        shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
174
108
    {
175
108
        RAPIDJSON_ASSERT(baseAllocator_ != 0);
176
108
        RAPIDJSON_ASSERT(shared_ != 0);
177
108
        if (baseAllocator) {
178
0
            shared_->ownBaseAllocator = 0;
179
0
        }
180
108
        else {
181
108
            shared_->ownBaseAllocator = baseAllocator_;
182
108
        }
183
108
        shared_->chunkHead = GetChunkHead(shared_);
184
108
        shared_->chunkHead->capacity = 0;
185
108
        shared_->chunkHead->size = 0;
186
108
        shared_->chunkHead->next = 0;
187
108
        shared_->ownBuffer = true;
188
108
        shared_->refcount = 1;
189
108
    }
190
191
    //! Constructor with user-supplied buffer.
192
    /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
193
194
        The user buffer will not be deallocated when this allocator is destructed.
195
196
        \param buffer User supplied buffer.
197
        \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
198
        \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
199
        \param baseAllocator The allocator for allocating memory chunks.
200
    */
201
    MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
202
        chunk_capacity_(chunkSize),
203
        baseAllocator_(baseAllocator),
204
        shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
205
    {
206
        RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
207
        shared_->chunkHead = GetChunkHead(shared_);
208
        shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
209
        shared_->chunkHead->size = 0;
210
        shared_->chunkHead->next = 0;
211
        shared_->ownBaseAllocator = 0;
212
        shared_->ownBuffer = false;
213
        shared_->refcount = 1;
214
    }
215
216
    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT :
217
        chunk_capacity_(rhs.chunk_capacity_),
218
        baseAllocator_(rhs.baseAllocator_),
219
        shared_(rhs.shared_)
220
    {
221
        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
222
        ++shared_->refcount;
223
    }
224
    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT
225
    {
226
        RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
227
        ++rhs.shared_->refcount;
228
        this->~MemoryPoolAllocator();
229
        baseAllocator_ = rhs.baseAllocator_;
230
        chunk_capacity_ = rhs.chunk_capacity_;
231
        shared_ = rhs.shared_;
232
        return *this;
233
    }
234
235
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
236
    MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT :
237
        chunk_capacity_(rhs.chunk_capacity_),
238
        baseAllocator_(rhs.baseAllocator_),
239
        shared_(rhs.shared_)
240
    {
241
        RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
242
        rhs.shared_ = 0;
243
    }
244
    MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT
245
    {
246
        RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
247
        this->~MemoryPoolAllocator();
248
        baseAllocator_ = rhs.baseAllocator_;
249
        chunk_capacity_ = rhs.chunk_capacity_;
250
        shared_ = rhs.shared_;
251
        rhs.shared_ = 0;
252
        return *this;
253
    }
254
#endif
255
256
    //! Destructor.
257
    /*! This deallocates all memory chunks, excluding the user-supplied buffer.
258
    */
259
108
    ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT {
260
108
        if (!shared_) {
261
            // do nothing if moved
262
0
            return;
263
0
        }
264
108
        if (shared_->refcount > 1) {
265
0
            --shared_->refcount;
266
0
            return;
267
0
        }
268
108
        Clear();
269
108
        BaseAllocator *a = shared_->ownBaseAllocator;
270
108
        if (shared_->ownBuffer) {
271
108
            baseAllocator_->Free(shared_);
272
108
        }
273
108
        RAPIDJSON_DELETE(a);
274
108
    }
275
276
    //! Deallocates all memory chunks, excluding the first/user one.
277
108
    void Clear() RAPIDJSON_NOEXCEPT {
278
108
        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
279
222
        for (;;) {
280
222
            ChunkHeader* c = shared_->chunkHead;
281
222
            if (!c->next) {
282
108
                break;
283
108
            }
284
114
            shared_->chunkHead = c->next;
285
114
            baseAllocator_->Free(c);
286
114
        }
287
108
        shared_->chunkHead->size = 0;
288
108
    }
289
290
    //! Computes the total capacity of allocated memory chunks.
291
    /*! \return total capacity in bytes.
292
    */
293
    size_t Capacity() const RAPIDJSON_NOEXCEPT {
294
        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
295
        size_t capacity = 0;
296
        for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
297
            capacity += c->capacity;
298
        return capacity;
299
    }
300
301
    //! Computes the memory blocks allocated.
302
    /*! \return total used bytes.
303
    */
304
    size_t Size() const RAPIDJSON_NOEXCEPT {
305
        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
306
        size_t size = 0;
307
        for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
308
            size += c->size;
309
        return size;
310
    }
311
312
    //! Whether the allocator is shared.
313
    /*! \return true or false.
314
    */
315
    bool Shared() const RAPIDJSON_NOEXCEPT {
316
        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
317
        return shared_->refcount > 1;
318
    }
319
320
    //! Allocates a memory block. (concept Allocator)
321
35.9k
    void* Malloc(size_t size) {
322
35.9k
        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
323
35.9k
        if (!size)
324
0
            return NULL;
325
326
35.9k
        size = RAPIDJSON_ALIGN(size);
327
35.9k
        if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity))
328
114
            if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
329
0
                return NULL;
330
331
35.9k
        void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size;
332
35.9k
        shared_->chunkHead->size += size;
333
35.9k
        return buffer;
334
35.9k
    }
335
336
    //! Resizes a memory block (concept Allocator)
337
0
    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
338
0
        if (originalPtr == 0)
339
0
            return Malloc(newSize);
340
341
0
        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
342
0
        if (newSize == 0)
343
0
            return NULL;
344
345
0
        originalSize = RAPIDJSON_ALIGN(originalSize);
346
0
        newSize = RAPIDJSON_ALIGN(newSize);
347
348
        // Do not shrink if new size is smaller than original
349
0
        if (originalSize >= newSize)
350
0
            return originalPtr;
351
352
        // Simply expand it if it is the last allocation and there is sufficient space
353
0
        if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
354
0
            size_t increment = static_cast<size_t>(newSize - originalSize);
355
0
            if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) {
356
0
                shared_->chunkHead->size += increment;
357
0
                return originalPtr;
358
0
            }
359
0
        }
360
361
        // Realloc process: allocate and copy memory, do not free original buffer.
362
0
        if (void* newBuffer = Malloc(newSize)) {
363
0
            if (originalSize)
364
0
                std::memcpy(newBuffer, originalPtr, originalSize);
365
0
            return newBuffer;
366
0
        }
367
0
        else
368
0
            return NULL;
369
0
    }
370
371
    //! Frees a memory block (concept Allocator)
372
0
    static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing
373
374
    //! Compare (equality) with another MemoryPoolAllocator
375
    bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
376
        RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
377
        RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
378
        return shared_ == rhs.shared_;
379
    }
380
    //! Compare (inequality) with another MemoryPoolAllocator
381
    bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
382
        return !operator==(rhs);
383
    }
384
385
private:
386
    //! Creates a new chunk.
387
    /*! \param capacity Capacity of the chunk in bytes.
388
        \return true if success.
389
    */
390
114
    bool AddChunk(size_t capacity) {
391
114
        if (!baseAllocator_)
392
0
            shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
393
114
        if (ChunkHeader* chunk = static_cast<ChunkHeader*>(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) {
394
114
            chunk->capacity = capacity;
395
114
            chunk->size = 0;
396
114
            chunk->next = shared_->chunkHead;
397
114
            shared_->chunkHead = chunk;
398
114
            return true;
399
114
        }
400
0
        else
401
0
            return false;
402
114
    }
403
404
    static inline void* AlignBuffer(void* buf, size_t &size)
405
    {
406
        RAPIDJSON_NOEXCEPT_ASSERT(buf != 0);
407
        const uintptr_t mask = sizeof(void*) - 1;
408
        const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf);
409
        if (RAPIDJSON_UNLIKELY(ubuf & mask)) {
410
            const uintptr_t abuf = (ubuf + mask) & ~mask;
411
            RAPIDJSON_ASSERT(size >= abuf - ubuf);
412
            buf = reinterpret_cast<void*>(abuf);
413
            size -= abuf - ubuf;
414
        }
415
        return buf;
416
    }
417
418
    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.
419
    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.
420
    SharedData *shared_;        //!< The shared data of the allocator
421
};
422
423
namespace internal {
424
    template<typename, typename = void>
425
    struct IsRefCounted :
426
        public FalseType
427
    { };
428
    template<typename T>
429
    struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> :
430
        public TrueType
431
    { };
432
}
433
434
template<typename T, typename A>
435
inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
436
0
{
437
0
    RAPIDJSON_NOEXCEPT_ASSERT(old_n <= (std::numeric_limits<size_t>::max)() / sizeof(T) && new_n <= (std::numeric_limits<size_t>::max)() / sizeof(T));
438
0
    return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
439
0
}
440
441
template<typename T, typename A>
442
inline T *Malloc(A& a, size_t n = 1)
443
0
{
444
    return Realloc<T, A>(a, NULL, 0, n);
445
0
}
446
447
template<typename T, typename A>
448
inline void Free(A& a, T *p, size_t n = 1)
449
{
450
    static_cast<void>(Realloc<T, A>(a, p, n, 0));
451
}
452
453
#ifdef __GNUC__
454
RAPIDJSON_DIAG_PUSH
455
RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
456
#endif
457
458
template <typename T, typename BaseAllocator = CrtAllocator>
459
class StdAllocator :
460
    public std::allocator<T>
461
{
462
    typedef std::allocator<T> allocator_type;
463
#if RAPIDJSON_HAS_CXX11
464
    typedef std::allocator_traits<allocator_type> traits_type;
465
#else
466
    typedef allocator_type traits_type;
467
#endif
468
469
public:
470
    typedef BaseAllocator BaseAllocatorType;
471
472
    StdAllocator() RAPIDJSON_NOEXCEPT :
473
        allocator_type(),
474
        baseAllocator_()
475
    { }
476
477
    StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
478
        allocator_type(rhs),
479
        baseAllocator_(rhs.baseAllocator_)
480
    { }
481
482
    template<typename U>
483
    StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
484
        allocator_type(rhs),
485
        baseAllocator_(rhs.baseAllocator_)
486
    { }
487
488
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
489
    StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT :
490
        allocator_type(std::move(rhs)),
491
        baseAllocator_(std::move(rhs.baseAllocator_))
492
    { }
493
#endif
494
#if RAPIDJSON_HAS_CXX11
495
    using propagate_on_container_move_assignment = std::true_type;
496
    using propagate_on_container_swap = std::true_type;
497
#endif
498
499
    /* implicit */
500
    StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
501
        allocator_type(),
502
        baseAllocator_(baseAllocator)
503
    { }
504
505
    ~StdAllocator() RAPIDJSON_NOEXCEPT
506
    { }
507
508
    template<typename U>
509
    struct rebind {
510
        typedef StdAllocator<U, BaseAllocator> other;
511
    };
512
513
    typedef typename traits_type::size_type         size_type;
514
    typedef typename traits_type::difference_type   difference_type;
515
516
    typedef typename traits_type::value_type        value_type;
517
    typedef typename traits_type::pointer           pointer;
518
    typedef typename traits_type::const_pointer     const_pointer;
519
520
#if RAPIDJSON_HAS_CXX11
521
522
    typedef typename std::add_lvalue_reference<value_type>::type &reference;
523
    typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type &const_reference;
524
525
    pointer address(reference r) const RAPIDJSON_NOEXCEPT
526
    {
527
        return std::addressof(r);
528
    }
529
    const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
530
    {
531
        return std::addressof(r);
532
    }
533
534
    size_type max_size() const RAPIDJSON_NOEXCEPT
535
    {
536
        return traits_type::max_size(*this);
537
    }
538
539
    template <typename ...Args>
540
    void construct(pointer p, Args&&... args)
541
    {
542
        traits_type::construct(*this, p, std::forward<Args>(args)...);
543
    }
544
    void destroy(pointer p)
545
    {
546
        traits_type::destroy(*this, p);
547
    }
548
549
#else // !RAPIDJSON_HAS_CXX11
550
551
    typedef typename allocator_type::reference       reference;
552
    typedef typename allocator_type::const_reference const_reference;
553
554
    pointer address(reference r) const RAPIDJSON_NOEXCEPT
555
    {
556
        return allocator_type::address(r);
557
    }
558
    const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
559
    {
560
        return allocator_type::address(r);
561
    }
562
563
    size_type max_size() const RAPIDJSON_NOEXCEPT
564
    {
565
        return allocator_type::max_size();
566
    }
567
568
    void construct(pointer p, const_reference r)
569
    {
570
        allocator_type::construct(p, r);
571
    }
572
    void destroy(pointer p)
573
    {
574
        allocator_type::destroy(p);
575
    }
576
577
#endif // !RAPIDJSON_HAS_CXX11
578
579
    template <typename U>
580
    U* allocate(size_type n = 1, const void* = 0)
581
    {
582
        return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
583
    }
584
    template <typename U>
585
    void deallocate(U* p, size_type n = 1)
586
    {
587
        RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
588
    }
589
590
    pointer allocate(size_type n = 1, const void* = 0)
591
    {
592
        return allocate<value_type>(n);
593
    }
594
    void deallocate(pointer p, size_type n = 1)
595
    {
596
        deallocate<value_type>(p, n);
597
    }
598
599
#if RAPIDJSON_HAS_CXX11
600
    using is_always_equal = std::is_empty<BaseAllocator>;
601
#endif
602
603
    template<typename U>
604
    bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
605
    {
606
        return baseAllocator_ == rhs.baseAllocator_;
607
    }
608
    template<typename U>
609
    bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
610
    {
611
        return !operator==(rhs);
612
    }
613
614
    //! rapidjson Allocator concept
615
    static const bool kNeedFree = BaseAllocator::kNeedFree;
616
    static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::Value;
617
    void* Malloc(size_t size)
618
    {
619
        return baseAllocator_.Malloc(size);
620
    }
621
    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
622
    {
623
        return baseAllocator_.Realloc(originalPtr, originalSize, newSize);
624
    }
625
    static void Free(void *ptr) RAPIDJSON_NOEXCEPT
626
    {
627
        BaseAllocator::Free(ptr);
628
    }
629
630
private:
631
    template <typename, typename>
632
    friend class StdAllocator; // access to StdAllocator<!T>.*
633
634
    BaseAllocator baseAllocator_;
635
};
636
637
#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
638
template <typename BaseAllocator>
639
class StdAllocator<void, BaseAllocator> :
640
    public std::allocator<void>
641
{
642
    typedef std::allocator<void> allocator_type;
643
644
public:
645
    typedef BaseAllocator BaseAllocatorType;
646
647
    StdAllocator() RAPIDJSON_NOEXCEPT :
648
        allocator_type(),
649
        baseAllocator_()
650
    { }
651
652
    StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
653
        allocator_type(rhs),
654
        baseAllocator_(rhs.baseAllocator_)
655
    { }
656
657
    template<typename U>
658
    StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
659
        allocator_type(rhs),
660
        baseAllocator_(rhs.baseAllocator_)
661
    { }
662
663
    /* implicit */
664
    StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
665
        allocator_type(),
666
        baseAllocator_(baseAllocator)
667
    { }
668
669
    ~StdAllocator() RAPIDJSON_NOEXCEPT
670
    { }
671
672
    template<typename U>
673
    struct rebind {
674
        typedef StdAllocator<U, BaseAllocator> other;
675
    };
676
677
    typedef typename allocator_type::value_type value_type;
678
679
private:
680
    template <typename, typename>
681
    friend class StdAllocator; // access to StdAllocator<!T>.*
682
683
    BaseAllocator baseAllocator_;
684
};
685
#endif
686
687
#ifdef __GNUC__
688
RAPIDJSON_DIAG_POP
689
#endif
690
691
RAPIDJSON_NAMESPACE_END
692
693
#endif // RAPIDJSON_ENCODINGS_H_