stack.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // Tencent is pleased to support the open source community by making RapidJSON
  2. // available.
  3. //
  4. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
  5. // rights reserved.
  6. //
  7. // Licensed under the MIT License (the "License"); you may not use this file
  8. // except in compliance with the License. You may obtain a copy of the License
  9. // at
  10. //
  11. // http://opensource.org/licenses/MIT
  12. //
  13. // Unless required by applicable law or agreed to in writing, software
  14. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. // License for the specific language governing permissions and limitations under
  17. // the License.
  18. #ifndef RAPIDJSON_INTERNAL_STACK_H_
  19. #define RAPIDJSON_INTERNAL_STACK_H_
  20. #include <cstddef>
  21. #include "../allocators.h"
  22. #include "swap.h"
  23. #if defined(__clang__)
  24. RAPIDJSON_DIAG_PUSH
  25. RAPIDJSON_DIAG_OFF(c++ 98 - compat)
  26. #endif
  27. RAPIDJSON_NAMESPACE_BEGIN
  28. namespace internal {
  29. ///////////////////////////////////////////////////////////////////////////////
  30. // Stack
  31. //! A type-unsafe stack for storing different types of data.
  32. /*! \tparam Allocator Allocator for allocating stack memory.
  33. */
  34. template <typename Allocator>
  35. class Stack {
  36. public:
  37. // Optimization note: Do not allocate memory for stack_ in constructor.
  38. // Do it lazily when first Push() -> Expand() -> Resize().
  39. Stack(Allocator *allocator, size_t stackCapacity)
  40. : allocator_(allocator),
  41. ownAllocator_(0),
  42. stack_(0),
  43. stackTop_(0),
  44. stackEnd_(0),
  45. initialCapacity_(stackCapacity) {}
  46. #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
  47. Stack(Stack &&rhs)
  48. : allocator_(rhs.allocator_),
  49. ownAllocator_(rhs.ownAllocator_),
  50. stack_(rhs.stack_),
  51. stackTop_(rhs.stackTop_),
  52. stackEnd_(rhs.stackEnd_),
  53. initialCapacity_(rhs.initialCapacity_) {
  54. rhs.allocator_ = 0;
  55. rhs.ownAllocator_ = 0;
  56. rhs.stack_ = 0;
  57. rhs.stackTop_ = 0;
  58. rhs.stackEnd_ = 0;
  59. rhs.initialCapacity_ = 0;
  60. }
  61. #endif
  62. ~Stack() { Destroy(); }
  63. #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
  64. Stack &operator=(Stack &&rhs) {
  65. if (&rhs != this) {
  66. Destroy();
  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. rhs.allocator_ = 0;
  74. rhs.ownAllocator_ = 0;
  75. rhs.stack_ = 0;
  76. rhs.stackTop_ = 0;
  77. rhs.stackEnd_ = 0;
  78. rhs.initialCapacity_ = 0;
  79. }
  80. return *this;
  81. }
  82. #endif
  83. void Swap(Stack &rhs) RAPIDJSON_NOEXCEPT {
  84. internal::Swap(allocator_, rhs.allocator_);
  85. internal::Swap(ownAllocator_, rhs.ownAllocator_);
  86. internal::Swap(stack_, rhs.stack_);
  87. internal::Swap(stackTop_, rhs.stackTop_);
  88. internal::Swap(stackEnd_, rhs.stackEnd_);
  89. internal::Swap(initialCapacity_, rhs.initialCapacity_);
  90. }
  91. void Clear() { stackTop_ = stack_; }
  92. void ShrinkToFit() {
  93. if (Empty()) {
  94. // If the stack is empty, completely deallocate the memory.
  95. Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
  96. stack_ = 0;
  97. stackTop_ = 0;
  98. stackEnd_ = 0;
  99. } else
  100. Resize(GetSize());
  101. }
  102. // Optimization note: try to minimize the size of this function for force
  103. // inline. Expansion is run very infrequently, so it is moved to another
  104. // (probably non-inline) function.
  105. template <typename T>
  106. RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
  107. // Expand the stack if needed
  108. if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) >
  109. (stackEnd_ - stackTop_)))
  110. Expand<T>(count);
  111. }
  112. template <typename T>
  113. RAPIDJSON_FORCEINLINE T *Push(size_t count = 1) {
  114. Reserve<T>(count);
  115. return PushUnsafe<T>(count);
  116. }
  117. template <typename T>
  118. RAPIDJSON_FORCEINLINE T *PushUnsafe(size_t count = 1) {
  119. RAPIDJSON_ASSERT(stackTop_);
  120. RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <=
  121. (stackEnd_ - stackTop_));
  122. T *ret = reinterpret_cast<T *>(stackTop_);
  123. stackTop_ += sizeof(T) * count;
  124. return ret;
  125. }
  126. template <typename T>
  127. T *Pop(size_t count) {
  128. RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
  129. stackTop_ -= count * sizeof(T);
  130. return reinterpret_cast<T *>(stackTop_);
  131. }
  132. template <typename T>
  133. T *Top() {
  134. RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
  135. return reinterpret_cast<T *>(stackTop_ - sizeof(T));
  136. }
  137. template <typename T>
  138. const T *Top() const {
  139. RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
  140. return reinterpret_cast<T *>(stackTop_ - sizeof(T));
  141. }
  142. template <typename T>
  143. T *End() {
  144. return reinterpret_cast<T *>(stackTop_);
  145. }
  146. template <typename T>
  147. const T *End() const {
  148. return reinterpret_cast<T *>(stackTop_);
  149. }
  150. template <typename T>
  151. T *Bottom() {
  152. return reinterpret_cast<T *>(stack_);
  153. }
  154. template <typename T>
  155. const T *Bottom() const {
  156. return reinterpret_cast<T *>(stack_);
  157. }
  158. bool HasAllocator() const { return allocator_ != 0; }
  159. Allocator &GetAllocator() {
  160. RAPIDJSON_ASSERT(allocator_);
  161. return *allocator_;
  162. }
  163. bool Empty() const { return stackTop_ == stack_; }
  164. size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
  165. size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
  166. private:
  167. template <typename T>
  168. void Expand(size_t count) {
  169. // Only expand the capacity if the current stack exists. Otherwise just
  170. // create a stack with initial capacity.
  171. size_t newCapacity;
  172. if (stack_ == 0) {
  173. if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
  174. newCapacity = initialCapacity_;
  175. } else {
  176. newCapacity = GetCapacity();
  177. newCapacity += (newCapacity + 1) / 2;
  178. }
  179. size_t newSize = GetSize() + sizeof(T) * count;
  180. if (newCapacity < newSize) newCapacity = newSize;
  181. Resize(newCapacity);
  182. }
  183. void Resize(size_t newCapacity) {
  184. const size_t size = GetSize(); // Backup the current size
  185. stack_ = static_cast<char *>(
  186. allocator_->Realloc(stack_, GetCapacity(), newCapacity));
  187. stackTop_ = stack_ + size;
  188. stackEnd_ = stack_ + newCapacity;
  189. }
  190. void Destroy() {
  191. Allocator::Free(stack_);
  192. RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
  193. }
  194. // Prohibit copy constructor & assignment operator.
  195. Stack(const Stack &);
  196. Stack &operator=(const Stack &);
  197. Allocator *allocator_;
  198. Allocator *ownAllocator_;
  199. char *stack_;
  200. char *stackTop_;
  201. char *stackEnd_;
  202. size_t initialCapacity_;
  203. };
  204. } // namespace internal
  205. RAPIDJSON_NAMESPACE_END
  206. #if defined(__clang__)
  207. RAPIDJSON_DIAG_POP
  208. #endif
  209. #endif // RAPIDJSON_STACK_H_