stack.h Source File

stack.h Source File#

Composable Kernel: stack.h Source File
stack.h
Go to the documentation of this file.
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__)
23RAPIDJSON_DIAG_PUSH
24RAPIDJSON_DIAG_OFF(c++ 98 - compat)
25#endif
26
28namespace internal {
29
31// Stack
32
34
36template <typename Allocator>
37class Stack
38{
39 public:
40 // Optimization note: Do not allocate memory for stack_ in constructor.
41 // Do it lazily when first Push() -> Expand() -> Resize().
42 Stack(Allocator* allocator, size_t stackCapacity)
43 : allocator_(allocator),
44 ownAllocator_(0),
45 stack_(0),
46 stackTop_(0),
47 stackEnd_(0),
48 initialCapacity_(stackCapacity)
49 {
50 }
51
52#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
53 Stack(Stack&& rhs)
54 : allocator_(rhs.allocator_),
55 ownAllocator_(rhs.ownAllocator_),
56 stack_(rhs.stack_),
57 stackTop_(rhs.stackTop_),
58 stackEnd_(rhs.stackEnd_),
59 initialCapacity_(rhs.initialCapacity_)
60 {
61 rhs.allocator_ = 0;
62 rhs.ownAllocator_ = 0;
63 rhs.stack_ = 0;
64 rhs.stackTop_ = 0;
65 rhs.stackEnd_ = 0;
66 rhs.initialCapacity_ = 0;
67 }
68#endif
69
70 ~Stack() { Destroy(); }
71
72#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
73 Stack& operator=(Stack&& rhs)
74 {
75 if(&rhs != this)
76 {
77 Destroy();
78
79 allocator_ = rhs.allocator_;
80 ownAllocator_ = rhs.ownAllocator_;
81 stack_ = rhs.stack_;
82 stackTop_ = rhs.stackTop_;
83 stackEnd_ = rhs.stackEnd_;
84 initialCapacity_ = rhs.initialCapacity_;
85
86 rhs.allocator_ = 0;
87 rhs.ownAllocator_ = 0;
88 rhs.stack_ = 0;
89 rhs.stackTop_ = 0;
90 rhs.stackEnd_ = 0;
91 rhs.initialCapacity_ = 0;
92 }
93 return *this;
94 }
95#endif
96
97 void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT
98 {
99 internal::Swap(allocator_, rhs.allocator_);
100 internal::Swap(ownAllocator_, rhs.ownAllocator_);
101 internal::Swap(stack_, rhs.stack_);
102 internal::Swap(stackTop_, rhs.stackTop_);
103 internal::Swap(stackEnd_, rhs.stackEnd_);
104 internal::Swap(initialCapacity_, rhs.initialCapacity_);
105 }
106
107 void Clear() { stackTop_ = stack_; }
108
110 {
111 if(Empty())
112 {
113 // If the stack is empty, completely deallocate the memory.
114 Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
115 stack_ = 0;
116 stackTop_ = 0;
117 stackEnd_ = 0;
118 }
119 else
120 Resize(GetSize());
121 }
122
123 // Optimization note: try to minimize the size of this function for force inline.
124 // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
125 template <typename T>
126 RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1)
127 {
128 // Expand the stack if needed
129 if(RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) >
130 (stackEnd_ - stackTop_)))
131 Expand<T>(count);
132 }
133
134 template <typename T>
135 RAPIDJSON_FORCEINLINE T* Push(size_t count = 1)
136 {
137 Reserve<T>(count);
138 return PushUnsafe<T>(count);
139 }
140
141 template <typename T>
142 RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1)
143 {
144 RAPIDJSON_ASSERT(stackTop_);
145 RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
146 T* ret = reinterpret_cast<T*>(stackTop_);
147 stackTop_ += sizeof(T) * count;
148 return ret;
149 }
150
151 template <typename T>
152 T* Pop(size_t count)
153 {
154 RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
155 stackTop_ -= count * sizeof(T);
156 return reinterpret_cast<T*>(stackTop_);
157 }
158
159 template <typename T>
160 T* Top()
161 {
162 RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
163 return reinterpret_cast<T*>(stackTop_ - sizeof(T));
164 }
165
166 template <typename T>
167 const T* Top() const
168 {
169 RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
170 return reinterpret_cast<T*>(stackTop_ - sizeof(T));
171 }
172
173 template <typename T>
174 T* End()
175 {
176 return reinterpret_cast<T*>(stackTop_);
177 }
178
179 template <typename T>
180 const T* End() const
181 {
182 return reinterpret_cast<T*>(stackTop_);
183 }
184
185 template <typename T>
187 {
188 return reinterpret_cast<T*>(stack_);
189 }
190
191 template <typename T>
192 const T* Bottom() const
193 {
194 return reinterpret_cast<T*>(stack_);
195 }
196
197 bool HasAllocator() const { return allocator_ != 0; }
198
200 {
201 RAPIDJSON_ASSERT(allocator_);
202 return *allocator_;
203 }
204
205 bool Empty() const { return stackTop_ == stack_; }
206 size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
207 size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
208
209 private:
210 template <typename T>
211 void Expand(size_t count)
212 {
213 // Only expand the capacity if the current stack exists. Otherwise just create a stack with
214 // initial capacity.
215 size_t newCapacity;
216 if(stack_ == 0)
217 {
218 if(!allocator_)
219 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
220 newCapacity = initialCapacity_;
221 }
222 else
223 {
224 newCapacity = GetCapacity();
225 newCapacity += (newCapacity + 1) / 2;
226 }
227 size_t newSize = GetSize() + sizeof(T) * count;
228 if(newCapacity < newSize)
229 newCapacity = newSize;
230
231 Resize(newCapacity);
232 }
233
234 void Resize(size_t newCapacity)
235 {
236 const size_t size = GetSize(); // Backup the current size
237 stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
238 stackTop_ = stack_ + size;
239 stackEnd_ = stack_ + newCapacity;
240 }
241
242 void Destroy()
243 {
244 Allocator::Free(stack_);
245 RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
246 }
247
248 // Prohibit copy constructor & assignment operator.
249 Stack(const Stack&);
250 Stack& operator=(const Stack&);
251
252 Allocator* allocator_;
253 Allocator* ownAllocator_;
254 char* stack_;
255 char* stackTop_;
256 char* stackEnd_;
257 size_t initialCapacity_;
258};
259
260} // namespace internal
262
263#if defined(__clang__)
264RAPIDJSON_DIAG_POP
265#endif
266
267#endif // RAPIDJSON_STACK_H_
A type-unsafe stack for storing different types of data.
Definition stack.h:38
void Clear()
Definition stack.h:107
const T * Top() const
Definition stack.h:167
T * Pop(size_t count)
Definition stack.h:152
const T * End() const
Definition stack.h:180
bool Empty() const
Definition stack.h:205
RAPIDJSON_FORCEINLINE T * Push(size_t count=1)
Definition stack.h:135
void ShrinkToFit()
Definition stack.h:109
void Swap(Stack &rhs) RAPIDJSON_NOEXCEPT
Definition stack.h:97
bool HasAllocator() const
Definition stack.h:197
size_t GetCapacity() const
Definition stack.h:207
T * Bottom()
Definition stack.h:186
RAPIDJSON_FORCEINLINE void Reserve(size_t count=1)
Definition stack.h:126
RAPIDJSON_FORCEINLINE T * PushUnsafe(size_t count=1)
Definition stack.h:142
T * Top()
Definition stack.h:160
Allocator & GetAllocator()
Definition stack.h:199
size_t GetSize() const
Definition stack.h:206
T * End()
Definition stack.h:174
const T * Bottom() const
Definition stack.h:192
Stack(Allocator *allocator, size_t stackCapacity)
Definition stack.h:42
~Stack()
Definition stack.h:70
Concept for allocating, resizing and freeing memory block.
#define RAPIDJSON_UNLIKELY(x)
Compiler branching hint for expression with low probability to be true.
Definition rapidjson.h:531
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition rapidjson.h:451
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition rapidjson.h:121
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition rapidjson.h:124
Definition allocators.h:459
void Swap(T &a, T &b) RAPIDJSON_NOEXCEPT
Custom swap() to avoid dependency on C++ <algorithm> header.
Definition swap.h:33
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition rapidjson.h:746
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition rapidjson.h:742