GDevelop Core
Core library for developing platforms and tools compatible with GDevelop.
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. All rights reserved.
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 
28 namespace internal {
29 
31 // Stack
32 
34 
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_);
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  // Use pointer subtraction rather than `stackTop_ + N > stackEnd_` because the
119  // stack is lazily allocated: stackTop_ and stackEnd_ are both null until the
120  // first Expand(), and `null + non-zero` is undefined behaviour (caught by UBSan).
121  if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
122  Expand<T>(count);
123  }
124 
125  template<typename T>
126  RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
127  Reserve<T>(count);
128  return PushUnsafe<T>(count);
129  }
130 
131  template<typename T>
132  RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
133  RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
134  T* ret = reinterpret_cast<T*>(stackTop_);
135  stackTop_ += sizeof(T) * count;
136  return ret;
137  }
138 
139  template<typename T>
140  T* Pop(size_t count) {
141  RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
142  stackTop_ -= count * sizeof(T);
143  return reinterpret_cast<T*>(stackTop_);
144  }
145 
146  template<typename T>
147  T* Top() {
148  RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
149  return reinterpret_cast<T*>(stackTop_ - sizeof(T));
150  }
151 
152  template<typename T>
153  const T* Top() const {
154  RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
155  return reinterpret_cast<T*>(stackTop_ - sizeof(T));
156  }
157 
158  template<typename T>
159  T* End() { return reinterpret_cast<T*>(stackTop_); }
160 
161  template<typename T>
162  const T* End() const { return reinterpret_cast<T*>(stackTop_); }
163 
164  template<typename T>
165  T* Bottom() { return reinterpret_cast<T*>(stack_); }
166 
167  template<typename T>
168  const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
169 
170  bool HasAllocator() const {
171  return allocator_ != 0;
172  }
173 
174  Allocator& GetAllocator() {
175  RAPIDJSON_ASSERT(allocator_);
176  return *allocator_;
177  }
178 
179  bool Empty() const { return stackTop_ == stack_; }
180  size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
181  size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
182 
183 private:
184  template<typename T>
185  void Expand(size_t count) {
186  // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
187  size_t newCapacity;
188  if (stack_ == 0) {
189  if (!allocator_)
190  ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
191  newCapacity = initialCapacity_;
192  } else {
193  newCapacity = GetCapacity();
194  newCapacity += (newCapacity + 1) / 2;
195  }
196  size_t newSize = GetSize() + sizeof(T) * count;
197  if (newCapacity < newSize)
198  newCapacity = newSize;
199 
200  Resize(newCapacity);
201  }
202 
203  void Resize(size_t newCapacity) {
204  const size_t size = GetSize(); // Backup the current size
205  stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
206  stackTop_ = stack_ + size;
207  stackEnd_ = stack_ + newCapacity;
208  }
209 
210  void Destroy() {
211  Allocator::Free(stack_);
212  RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
213  }
214 
215  // Prohibit copy constructor & assignment operator.
216  Stack(const Stack&);
217  Stack& operator=(const Stack&);
218 
219  Allocator* allocator_;
220  Allocator* ownAllocator_;
221  char *stack_;
222  char *stackTop_;
223  char *stackEnd_;
224  size_t initialCapacity_;
225 };
226 
227 } // namespace internal
229 
230 #if defined(__clang__)
231 RAPIDJSON_DIAG_POP
232 #endif
233 
234 #endif // RAPIDJSON_STACK_H_
A type-unsafe stack for storing different types of data.
Definition: stack.h:37
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:468
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:402
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:116
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:119
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:590
#define RAPIDJSON_NEW(x)
! customization point for global new
Definition: rapidjson.h:586