RapidJSON: include/rapidjson/internal/stack.h Source File

stack.h
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 Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
42 }
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 ~Stack() {
63 Destroy();
64 }
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 void Clear() { stackTop_ = stack_; }
100
101 void ShrinkToFit() {
102 if (Empty()) {
103 // If the stack is empty, completely deallocate the memory.
104 Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
105 stack_ = 0;
106 stackTop_ = 0;
107 stackEnd_ = 0;
108 }
109 else
110 Resize(GetSize());
111 }
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 RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
117 // Expand the stack if needed
118 if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
119 Expand<T>(count);
120 }
121
122 template<typename T>
123 RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
124 Reserve<T>(count);
125 return PushUnsafe<T>(count);
126 }
127
128 template<typename T>
129 RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
130 RAPIDJSON_ASSERT(stackTop_);
131 RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
132 T* ret = reinterpret_cast<T*>(stackTop_);
133 stackTop_ += sizeof(T) * count;
134 return ret;
135 }
136
137 template<typename T>
138 T* Pop(size_t count) {
139 RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
140 stackTop_ -= count * sizeof(T);
141 return reinterpret_cast<T*>(stackTop_);
142 }
143
144 template<typename T>
145 T* Top() {
146 RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
147 return reinterpret_cast<T*>(stackTop_ - sizeof(T));
148 }
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 T* Bottom() { return reinterpret_cast<T*>(stack_); }
164
165 template<typename T>
166 const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
167
168 bool HasAllocator() const {
169 return allocator_ != 0;
170 }
171
172 Allocator& GetAllocator() {
173 RAPIDJSON_ASSERT(allocator_);
174 return *allocator_;
175 }
176
177 bool Empty() const { return stackTop_ == stack_; }
178 size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
179 size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
180
181 private:
182 template<typename T>
183 void Expand(size_t count) {
184 // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
185 size_t newCapacity;
186 if (stack_ == 0) {
187 if (!allocator_)
188 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
189 newCapacity = initialCapacity_;
190 } else {
191 newCapacity = GetCapacity();
192 newCapacity += (newCapacity + 1) / 2;
193 }
194 size_t newSize = GetSize() + sizeof(T) * count;
195 if (newCapacity < newSize)
196 newCapacity = newSize;
197
198 Resize(newCapacity);
199 }
200
201 void Resize(size_t newCapacity) {
202 const size_t size = GetSize(); // Backup the current size
203 stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
204 stackTop_ = stack_ + size;
205 stackEnd_ = stack_ + newCapacity;
206 }
207
208 void Destroy() {
209 Allocator::Free(stack_);
210 RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
211 }
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_
Allocator
Concept for allocating, resizing and freeing memory block.
RAPIDJSON_ASSERT
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:406
RAPIDJSON_NEW
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition: rapidjson.h:663
RAPIDJSON_DELETE
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:667
RAPIDJSON_UNLIKELY
#define RAPIDJSON_UNLIKELY(x)
Compiler branching hint for expression with low probability to be true.
Definition: rapidjson.h:476