All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 "../rapidjson.h"
19 #include "swap.h"
20 
21 RAPIDJSON_NAMESPACE_BEGIN
22 namespace internal {
23 
24 ///////////////////////////////////////////////////////////////////////////////
25 // Stack
26 
27 //! A type-unsafe stack for storing different types of data.
28 /*! \tparam Allocator Allocator for allocating stack memory.
29 */
30 template <typename Allocator>
31 class Stack {
32 public:
33  // Optimization note: Do not allocate memory for stack_ in constructor.
34  // Do it lazily when first Push() -> Expand() -> Resize().
35  Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
36  RAPIDJSON_ASSERT(stackCapacity > 0);
37  }
38 
39 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
40  Stack(Stack&& rhs)
41  : allocator_(rhs.allocator_),
42  ownAllocator_(rhs.ownAllocator_),
43  stack_(rhs.stack_),
44  stackTop_(rhs.stackTop_),
45  stackEnd_(rhs.stackEnd_),
46  initialCapacity_(rhs.initialCapacity_)
47  {
48  rhs.allocator_ = 0;
49  rhs.ownAllocator_ = 0;
50  rhs.stack_ = 0;
51  rhs.stackTop_ = 0;
52  rhs.stackEnd_ = 0;
53  rhs.initialCapacity_ = 0;
54  }
55 #endif
56 
57  ~Stack() {
58  Destroy();
59  }
60 
61 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
62  Stack& operator=(Stack&& rhs) {
63  if (&rhs != this)
64  {
65  Destroy();
66 
67  allocator_ = rhs.allocator_;
68  ownAllocator_ = rhs.ownAllocator_;
69  stack_ = rhs.stack_;
70  stackTop_ = rhs.stackTop_;
71  stackEnd_ = rhs.stackEnd_;
72  initialCapacity_ = rhs.initialCapacity_;
73 
74  rhs.allocator_ = 0;
75  rhs.ownAllocator_ = 0;
76  rhs.stack_ = 0;
77  rhs.stackTop_ = 0;
78  rhs.stackEnd_ = 0;
79  rhs.initialCapacity_ = 0;
80  }
81  return *this;
82  }
83 #endif
84 
85  void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
86  internal::Swap(allocator_, rhs.allocator_);
87  internal::Swap(ownAllocator_, rhs.ownAllocator_);
88  internal::Swap(stack_, rhs.stack_);
89  internal::Swap(stackTop_, rhs.stackTop_);
90  internal::Swap(stackEnd_, rhs.stackEnd_);
91  internal::Swap(initialCapacity_, rhs.initialCapacity_);
92  }
93 
94  void Clear() { stackTop_ = stack_; }
95 
96  void ShrinkToFit() {
97  if (Empty()) {
98  // If the stack is empty, completely deallocate the memory.
99  Allocator::Free(stack_);
100  stack_ = 0;
101  stackTop_ = 0;
102  stackEnd_ = 0;
103  }
104  else
105  Resize(GetSize());
106  }
107 
108  // Optimization note: try to minimize the size of this function for force inline.
109  // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
110  template<typename T>
111  RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
112  // Expand the stack if needed
113  if (stackTop_ + sizeof(T) * count >= stackEnd_)
114  Expand<T>(count);
115 
116  T* ret = reinterpret_cast<T*>(stackTop_);
117  stackTop_ += sizeof(T) * count;
118  return ret;
119  }
120 
121  template<typename T>
122  T* Pop(size_t count) {
123  RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
124  stackTop_ -= count * sizeof(T);
125  return reinterpret_cast<T*>(stackTop_);
126  }
127 
128  template<typename T>
129  T* Top() {
130  RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
131  return reinterpret_cast<T*>(stackTop_ - sizeof(T));
132  }
133 
134  template<typename T>
135  T* Bottom() { return (T*)stack_; }
136 
137  Allocator& GetAllocator() { return *allocator_; }
138  bool Empty() const { return stackTop_ == stack_; }
139  size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
140  size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
141 
142 private:
143  template<typename T>
144  void Expand(size_t count) {
145  // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
146  size_t newCapacity;
147  if (stack_ == 0) {
148  if (!allocator_)
149  ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
150  newCapacity = initialCapacity_;
151  } else {
152  newCapacity = GetCapacity();
153  newCapacity += (newCapacity + 1) / 2;
154  }
155  size_t newSize = GetSize() + sizeof(T) * count;
156  if (newCapacity < newSize)
157  newCapacity = newSize;
158 
159  Resize(newCapacity);
160  }
161 
162  void Resize(size_t newCapacity) {
163  const size_t size = GetSize(); // Backup the current size
164  stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);
165  stackTop_ = stack_ + size;
166  stackEnd_ = stack_ + newCapacity;
167  }
168 
169  void Destroy() {
170  Allocator::Free(stack_);
171  RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
172  }
173 
174  // Prohibit copy constructor & assignment operator.
175  Stack(const Stack&);
176  Stack& operator=(const Stack&);
177 
178  Allocator* allocator_;
179  Allocator* ownAllocator_;
180  char *stack_;
181  char *stackTop_;
182  char *stackEnd_;
183  size_t initialCapacity_;
184 };
185 
186 } // namespace internal
187 RAPIDJSON_NAMESPACE_END
188 
189 #endif // RAPIDJSON_STACK_H_
#define RAPIDJSON_NEW(x)
! customization point for global new
Definition: rapidjson.h:480
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:484
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:344