stack.h 5.5 KB

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