Coverage Report

Created: 2026-10-13 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rapidjson/include/rapidjson/internal/stack.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_INTERNAL_STACK_H_
16
#define RAPIDJSON_INTERNAL_STACK_H_
17
18
#include "../allocators.h"
19
#include "swap.h"
20
#include <cstddef>
21
22
#if defined(__clang__)
23
RAPIDJSON_DIAG_PUSH
24
RAPIDJSON_DIAG_OFF(c++98-compat)
25
#endif
26
27
RAPIDJSON_NAMESPACE_BEGIN
28
namespace internal {
29
30
///////////////////////////////////////////////////////////////////////////////
31
// Stack
32
33
//! A type-unsafe stack for storing different types of data.
34
/*! \tparam Allocator Allocator for allocating stack memory.
35
*/
36
template <typename Allocator>
37
class Stack {
38
public:
39
    // Optimization note: Do not allocate memory for stack_ in constructor.
40
    // Do it lazily when first Push() -> Expand() -> Resize().
41
296
    Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
42
296
    }
43
44
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
45
    Stack(Stack&& rhs)
46
        : allocator_(rhs.allocator_),
47
          ownAllocator_(rhs.ownAllocator_),
48
          stack_(rhs.stack_),
49
          stackTop_(rhs.stackTop_),
50
          stackEnd_(rhs.stackEnd_),
51
          initialCapacity_(rhs.initialCapacity_)
52
    {
53
        rhs.allocator_ = 0;
54
        rhs.ownAllocator_ = 0;
55
        rhs.stack_ = 0;
56
        rhs.stackTop_ = 0;
57
        rhs.stackEnd_ = 0;
58
        rhs.initialCapacity_ = 0;
59
    }
60
#endif
61
62
296
    ~Stack() {
63
296
        Destroy();
64
296
    }
65
66
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
67
    Stack& operator=(Stack&& rhs) {
68
        if (&rhs != this)
69
        {
70
            Destroy();
71
72
            allocator_ = rhs.allocator_;
73
            ownAllocator_ = rhs.ownAllocator_;
74
            stack_ = rhs.stack_;
75
            stackTop_ = rhs.stackTop_;
76
            stackEnd_ = rhs.stackEnd_;
77
            initialCapacity_ = rhs.initialCapacity_;
78
79
            rhs.allocator_ = 0;
80
            rhs.ownAllocator_ = 0;
81
            rhs.stack_ = 0;
82
            rhs.stackTop_ = 0;
83
            rhs.stackEnd_ = 0;
84
            rhs.initialCapacity_ = 0;
85
        }
86
        return *this;
87
    }
88
#endif
89
90
    void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
91
        internal::Swap(allocator_, rhs.allocator_);
92
        internal::Swap(ownAllocator_, rhs.ownAllocator_);
93
        internal::Swap(stack_, rhs.stack_);
94
        internal::Swap(stackTop_, rhs.stackTop_);
95
        internal::Swap(stackEnd_, rhs.stackEnd_);
96
        internal::Swap(initialCapacity_, rhs.initialCapacity_);
97
    }
98
99
208
    void Clear() { stackTop_ = stack_; }
100
101
104
    void ShrinkToFit() { 
102
104
        if (Empty()) {
103
            // If the stack is empty, completely deallocate the memory.
104
104
            Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
105
104
            stack_ = 0;
106
104
            stackTop_ = 0;
107
104
            stackEnd_ = 0;
108
104
        }
109
0
        else
110
0
            Resize(GetSize());
111
104
    }
112
113
    // Optimization note: try to minimize the size of this function for force inline.
114
    // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
115
    template<typename T>
116
78.5M
    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
117
         // Expand the stack if needed
118
78.5M
        if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
119
1.85k
            Expand<T>(count);
120
78.5M
    }
void rapidjson::internal::Stack<rapidjson::CrtAllocator>::Reserve<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >(unsigned long)
Line
Count
Source
116
10.7M
    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
117
         // Expand the stack if needed
118
10.7M
        if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
119
752
            Expand<T>(count);
120
10.7M
    }
void rapidjson::internal::Stack<rapidjson::CrtAllocator>::Reserve<char>(unsigned long)
Line
Count
Source
116
67.7M
    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
117
         // Expand the stack if needed
118
67.7M
        if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
119
1.01k
            Expand<T>(count);
120
67.7M
    }
void rapidjson::internal::Stack<rapidjson::CrtAllocator>::Reserve<rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level>(unsigned long)
Line
Count
Source
116
15.4k
    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
117
         // Expand the stack if needed
118
15.4k
        if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
119
92
            Expand<T>(count);
120
15.4k
    }
Unexecuted instantiation: void rapidjson::internal::Stack<rapidjson::CrtAllocator>::Reserve<unsigned int>(unsigned long)
121
122
    template<typename T>
123
76.0M
    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
124
76.0M
        Reserve<T>(count);
125
76.0M
        return PushUnsafe<T>(count);
126
76.0M
    }
rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Push<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >(unsigned long)
Line
Count
Source
123
10.7M
    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
124
10.7M
        Reserve<T>(count);
125
10.7M
        return PushUnsafe<T>(count);
126
10.7M
    }
char* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Push<char>(unsigned long)
Line
Count
Source
123
65.2M
    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
124
65.2M
        Reserve<T>(count);
125
65.2M
        return PushUnsafe<T>(count);
126
65.2M
    }
rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Push<rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level>(unsigned long)
Line
Count
Source
123
15.4k
    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
124
15.4k
        Reserve<T>(count);
125
15.4k
        return PushUnsafe<T>(count);
126
15.4k
    }
Unexecuted instantiation: unsigned int* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Push<unsigned int>(unsigned long)
127
128
    template<typename T>
129
92.4M
    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
130
92.4M
        RAPIDJSON_ASSERT(stackTop_);
131
92.4M
        RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
132
92.4M
        T* ret = reinterpret_cast<T*>(stackTop_);
133
92.4M
        stackTop_ += sizeof(T) * count;
134
92.4M
        return ret;
135
92.4M
    }
rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >* rapidjson::internal::Stack<rapidjson::CrtAllocator>::PushUnsafe<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >(unsigned long)
Line
Count
Source
129
10.7M
    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
130
10.7M
        RAPIDJSON_ASSERT(stackTop_);
131
10.7M
        RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
132
10.7M
        T* ret = reinterpret_cast<T*>(stackTop_);
133
10.7M
        stackTop_ += sizeof(T) * count;
134
10.7M
        return ret;
135
10.7M
    }
char* rapidjson::internal::Stack<rapidjson::CrtAllocator>::PushUnsafe<char>(unsigned long)
Line
Count
Source
129
81.6M
    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
130
81.6M
        RAPIDJSON_ASSERT(stackTop_);
131
81.6M
        RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
132
81.6M
        T* ret = reinterpret_cast<T*>(stackTop_);
133
81.6M
        stackTop_ += sizeof(T) * count;
134
81.6M
        return ret;
135
81.6M
    }
rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level* rapidjson::internal::Stack<rapidjson::CrtAllocator>::PushUnsafe<rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level>(unsigned long)
Line
Count
Source
129
15.4k
    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
130
15.4k
        RAPIDJSON_ASSERT(stackTop_);
131
15.4k
        RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
132
15.4k
        T* ret = reinterpret_cast<T*>(stackTop_);
133
15.4k
        stackTop_ += sizeof(T) * count;
134
15.4k
        return ret;
135
15.4k
    }
Unexecuted instantiation: unsigned int* rapidjson::internal::Stack<rapidjson::CrtAllocator>::PushUnsafe<unsigned int>(unsigned long)
136
137
    template<typename T>
138
12.1M
    T* Pop(size_t count) {
139
12.1M
        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
140
12.1M
        stackTop_ -= count * sizeof(T);
141
12.1M
        return reinterpret_cast<T*>(stackTop_);
142
12.1M
    }
char* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Pop<char>(unsigned long)
Line
Count
Source
138
12.0M
    T* Pop(size_t count) {
139
12.0M
        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
140
12.0M
        stackTop_ -= count * sizeof(T);
141
12.0M
        return reinterpret_cast<T*>(stackTop_);
142
12.0M
    }
rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Pop<rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >(unsigned long)
Line
Count
Source
138
30.1k
    T* Pop(size_t count) {
139
30.1k
        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
140
30.1k
        stackTop_ -= count * sizeof(T);
141
30.1k
        return reinterpret_cast<T*>(stackTop_);
142
30.1k
    }
rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Pop<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >(unsigned long)
Line
Count
Source
138
19.2k
    T* Pop(size_t count) {
139
19.2k
        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
140
19.2k
        stackTop_ -= count * sizeof(T);
141
19.2k
        return reinterpret_cast<T*>(stackTop_);
142
19.2k
    }
rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Pop<rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level>(unsigned long)
Line
Count
Source
138
15.4k
    T* Pop(size_t count) {
139
15.4k
        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
140
15.4k
        stackTop_ -= count * sizeof(T);
141
15.4k
        return reinterpret_cast<T*>(stackTop_);
142
15.4k
    }
Unexecuted instantiation: unsigned int* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Pop<unsigned int>(unsigned long)
143
144
    template<typename T>
145
4.27M
    T* Top() { 
146
4.27M
        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
147
4.27M
        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
148
4.27M
    }
rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> >* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Top<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >()
Line
Count
Source
145
49.3k
    T* Top() { 
146
49.3k
        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
147
49.3k
        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
148
49.3k
    }
rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Top<rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level>()
Line
Count
Source
145
4.22M
    T* Top() { 
146
4.22M
        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
147
4.22M
        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
148
4.22M
    }
Unexecuted instantiation: unsigned int* rapidjson::internal::Stack<rapidjson::CrtAllocator>::Top<unsigned int>()
149
150
    template<typename T>
151
    const T* Top() const {
152
        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
153
        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
154
    }
155
156
    template<typename T>
157
    T* End() { return reinterpret_cast<T*>(stackTop_); }
158
159
    template<typename T>
160
    const T* End() const { return reinterpret_cast<T*>(stackTop_); }
161
162
    template<typename T>
163
44
    T* Bottom() { return reinterpret_cast<T*>(stack_); }
164
165
    template<typename T>
166
    const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
167
168
104
    bool HasAllocator() const {
169
104
        return allocator_ != 0;
170
104
    }
171
172
0
    Allocator& GetAllocator() {
173
0
        RAPIDJSON_ASSERT(allocator_);
174
0
        return *allocator_;
175
0
    }
176
177
4.22M
    bool Empty() const { return stackTop_ == stack_; }
178
24.1M
    size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
179
3.52k
    size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
180
181
private:
182
    template<typename T>
183
1.85k
    void Expand(size_t count) {
184
        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
185
1.85k
        size_t newCapacity;
186
1.85k
        if (stack_ == 0) {
187
185
            if (!allocator_)
188
185
                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
189
185
            newCapacity = initialCapacity_;
190
1.67k
        } else {
191
1.67k
            newCapacity = GetCapacity();
192
1.67k
            newCapacity += (newCapacity + 1) / 2;
193
1.67k
        }
194
1.85k
        size_t newSize = GetSize() + sizeof(T) * count;
195
1.85k
        if (newCapacity < newSize)
196
10
            newCapacity = newSize;
197
198
1.85k
        Resize(newCapacity);
199
1.85k
    }
void rapidjson::internal::Stack<rapidjson::CrtAllocator>::Expand<rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > >(unsigned long)
Line
Count
Source
183
752
    void Expand(size_t count) {
184
        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
185
752
        size_t newCapacity;
186
752
        if (stack_ == 0) {
187
70
            if (!allocator_)
188
70
                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
189
70
            newCapacity = initialCapacity_;
190
682
        } else {
191
682
            newCapacity = GetCapacity();
192
682
            newCapacity += (newCapacity + 1) / 2;
193
682
        }
194
752
        size_t newSize = GetSize() + sizeof(T) * count;
195
752
        if (newCapacity < newSize)
196
0
            newCapacity = newSize;
197
198
752
        Resize(newCapacity);
199
752
    }
void rapidjson::internal::Stack<rapidjson::CrtAllocator>::Expand<char>(unsigned long)
Line
Count
Source
183
1.01k
    void Expand(size_t count) {
184
        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
185
1.01k
        size_t newCapacity;
186
1.01k
        if (stack_ == 0) {
187
100
            if (!allocator_)
188
100
                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
189
100
            newCapacity = initialCapacity_;
190
912
        } else {
191
912
            newCapacity = GetCapacity();
192
912
            newCapacity += (newCapacity + 1) / 2;
193
912
        }
194
1.01k
        size_t newSize = GetSize() + sizeof(T) * count;
195
1.01k
        if (newCapacity < newSize)
196
10
            newCapacity = newSize;
197
198
1.01k
        Resize(newCapacity);
199
1.01k
    }
void rapidjson::internal::Stack<rapidjson::CrtAllocator>::Expand<rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Level>(unsigned long)
Line
Count
Source
183
92
    void Expand(size_t count) {
184
        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
185
92
        size_t newCapacity;
186
92
        if (stack_ == 0) {
187
15
            if (!allocator_)
188
15
                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
189
15
            newCapacity = initialCapacity_;
190
77
        } else {
191
77
            newCapacity = GetCapacity();
192
77
            newCapacity += (newCapacity + 1) / 2;
193
77
        }
194
92
        size_t newSize = GetSize() + sizeof(T) * count;
195
92
        if (newCapacity < newSize)
196
0
            newCapacity = newSize;
197
198
92
        Resize(newCapacity);
199
92
    }
Unexecuted instantiation: void rapidjson::internal::Stack<rapidjson::CrtAllocator>::Expand<unsigned int>(unsigned long)
200
201
1.85k
    void Resize(size_t newCapacity) {
202
1.85k
        const size_t size = GetSize();  // Backup the current size
203
1.85k
        stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
204
1.85k
        stackTop_ = stack_ + size;
205
1.85k
        stackEnd_ = stack_ + newCapacity;
206
1.85k
    }
207
208
296
    void Destroy() {
209
296
        Allocator::Free(stack_);
210
296
        RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
211
296
    }
212
213
    // Prohibit copy constructor & assignment operator.
214
    Stack(const Stack&);
215
    Stack& operator=(const Stack&);
216
217
    Allocator* allocator_;
218
    Allocator* ownAllocator_;
219
    char *stack_;
220
    char *stackTop_;
221
    char *stackEnd_;
222
    size_t initialCapacity_;
223
};
224
225
} // namespace internal
226
RAPIDJSON_NAMESPACE_END
227
228
#if defined(__clang__)
229
RAPIDJSON_DIAG_POP
230
#endif
231
232
#endif // RAPIDJSON_STACK_H_