SimulationCraft
SimulationCraft is a tool to explore combat mechanics in the popular MMO RPG World of Warcraft (tm).
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 
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_); // 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
227 
228 #if defined(__clang__)
229 RAPIDJSON_DIAG_POP
230 #endif
231 
232 #endif // RAPIDJSON_STACK_H_
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:121
#define RAPIDJSON_UNLIKELY(x)
Compiler branching hint for expression with low probability to be true.
Definition: rapidjson.h:507
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:124
A type-unsafe stack for storing different types of data.
Definition: stack.h:37
Definition: allocators.h:422
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:437