stack.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. #ifndef RAPIDJSON_INTERNAL_STACK_H_
  15. #define RAPIDJSON_INTERNAL_STACK_H_
  16. #include "../allocators.h"
  17. #include "swap.h"
  18. #include <cstddef>
  19. #if defined(__clang__)
  20. RAPIDJSON_DIAG_PUSH
  21. RAPIDJSON_DIAG_OFF(c++98-compat)
  22. #endif
  23. RAPIDJSON_NAMESPACE_BEGIN
  24. namespace internal {
  25. ///////////////////////////////////////////////////////////////////////////////
  26. // Stack
  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. }
  37. #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
  38. Stack(Stack&& rhs)
  39. : allocator_(rhs.allocator_),
  40. ownAllocator_(rhs.ownAllocator_),
  41. stack_(rhs.stack_),
  42. stackTop_(rhs.stackTop_),
  43. stackEnd_(rhs.stackEnd_),
  44. initialCapacity_(rhs.initialCapacity_)
  45. {
  46. rhs.allocator_ = 0;
  47. rhs.ownAllocator_ = 0;
  48. rhs.stack_ = 0;
  49. rhs.stackTop_ = 0;
  50. rhs.stackEnd_ = 0;
  51. rhs.initialCapacity_ = 0;
  52. }
  53. #endif
  54. ~Stack() {
  55. Destroy();
  56. }
  57. #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
  58. Stack& operator=(Stack&& rhs) {
  59. if (&rhs != this)
  60. {
  61. Destroy();
  62. allocator_ = rhs.allocator_;
  63. ownAllocator_ = rhs.ownAllocator_;
  64. stack_ = rhs.stack_;
  65. stackTop_ = rhs.stackTop_;
  66. stackEnd_ = rhs.stackEnd_;
  67. initialCapacity_ = rhs.initialCapacity_;
  68. rhs.allocator_ = 0;
  69. rhs.ownAllocator_ = 0;
  70. rhs.stack_ = 0;
  71. rhs.stackTop_ = 0;
  72. rhs.stackEnd_ = 0;
  73. rhs.initialCapacity_ = 0;
  74. }
  75. return *this;
  76. }
  77. #endif
  78. void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
  79. internal::Swap(allocator_, rhs.allocator_);
  80. internal::Swap(ownAllocator_, rhs.ownAllocator_);
  81. internal::Swap(stack_, rhs.stack_);
  82. internal::Swap(stackTop_, rhs.stackTop_);
  83. internal::Swap(stackEnd_, rhs.stackEnd_);
  84. internal::Swap(initialCapacity_, rhs.initialCapacity_);
  85. }
  86. void Clear() { stackTop_ = stack_; }
  87. void ShrinkToFit() {
  88. if (Empty()) {
  89. // If the stack is empty, completely deallocate the memory.
  90. Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
  91. stack_ = 0;
  92. stackTop_ = 0;
  93. stackEnd_ = 0;
  94. }
  95. else
  96. Resize(GetSize());
  97. }
  98. // Optimization note: try to minimize the size of this function for force inline.
  99. // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
  100. template<typename T>
  101. RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
  102. // Expand the stack if needed
  103. if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
  104. Expand<T>(count);
  105. }
  106. template<typename T>
  107. RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
  108. Reserve<T>(count);
  109. return PushUnsafe<T>(count);
  110. }
  111. template<typename T>
  112. RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
  113. RAPIDJSON_ASSERT(stackTop_);
  114. RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
  115. T* ret = reinterpret_cast<T*>(stackTop_);
  116. stackTop_ += sizeof(T) * count;
  117. return ret;
  118. }
  119. template<typename T>
  120. T* Pop(size_t count) {
  121. RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
  122. stackTop_ -= count * sizeof(T);
  123. return reinterpret_cast<T*>(stackTop_);
  124. }
  125. template<typename T>
  126. T* Top() {
  127. RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
  128. return reinterpret_cast<T*>(stackTop_ - sizeof(T));
  129. }
  130. template<typename T>
  131. const T* Top() const {
  132. RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
  133. return reinterpret_cast<T*>(stackTop_ - sizeof(T));
  134. }
  135. template<typename T>
  136. T* End() { return reinterpret_cast<T*>(stackTop_); }
  137. template<typename T>
  138. const T* End() const { return reinterpret_cast<T*>(stackTop_); }
  139. template<typename T>
  140. T* Bottom() { return reinterpret_cast<T*>(stack_); }
  141. template<typename T>
  142. const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
  143. bool HasAllocator() const {
  144. return allocator_ != 0;
  145. }
  146. Allocator& GetAllocator() {
  147. RAPIDJSON_ASSERT(allocator_);
  148. return *allocator_;
  149. }
  150. bool Empty() const { return stackTop_ == stack_; }
  151. size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
  152. size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
  153. private:
  154. template<typename T>
  155. void Expand(size_t count) {
  156. // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
  157. size_t newCapacity;
  158. if (stack_ == 0) {
  159. if (!allocator_)
  160. ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
  161. newCapacity = initialCapacity_;
  162. } else {
  163. newCapacity = GetCapacity();
  164. newCapacity += (newCapacity + 1) / 2;
  165. }
  166. size_t newSize = GetSize() + sizeof(T) * count;
  167. if (newCapacity < newSize)
  168. newCapacity = newSize;
  169. Resize(newCapacity);
  170. }
  171. void Resize(size_t newCapacity) {
  172. const size_t size = GetSize(); // Backup the current size
  173. stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
  174. stackTop_ = stack_ + size;
  175. stackEnd_ = stack_ + newCapacity;
  176. }
  177. void Destroy() {
  178. Allocator::Free(stack_);
  179. RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
  180. }
  181. // Prohibit copy constructor & assignment operator.
  182. Stack(const Stack&);
  183. Stack& operator=(const Stack&);
  184. Allocator* allocator_;
  185. Allocator* ownAllocator_;
  186. char *stack_;
  187. char *stackTop_;
  188. char *stackEnd_;
  189. size_t initialCapacity_;
  190. };
  191. } // namespace internal
  192. RAPIDJSON_NAMESPACE_END
  193. #if defined(__clang__)
  194. RAPIDJSON_DIAG_POP
  195. #endif
  196. #endif // RAPIDJSON_STACK_H_