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 27 RAPIDJSON_NAMESPACE_BEGIN 28 namespace internal { 29 30 /////////////////////////////////////////////////////////////////////////////// 31 // Stack 32 33 //! A type-unsafe stack for storing different types of data. 34 /*! \tparam Allocator Allocator for allocating stack memory. 35 */ 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(). Stack(Allocator * allocator,size_t stackCapacity)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 Stack(Stack && rhs)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 ~Stack()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 Swap(Stack & rhs)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 Clear()99 void Clear() { stackTop_ = stack_; } 100 ShrinkToFit()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> Pop(size_t count)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> Top()145 T* Top() { 146 RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); 147 return reinterpret_cast<T*>(stackTop_ - sizeof(T)); 148 } 149 150 template<typename T> Top()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> End()157 T* End() { return reinterpret_cast<T*>(stackTop_); } 158 159 template<typename T> End()160 const T* End() const { return reinterpret_cast<T*>(stackTop_); } 161 162 template<typename T> Bottom()163 T* Bottom() { return reinterpret_cast<T*>(stack_); } 164 165 template<typename T> Bottom()166 const T* Bottom() const { return reinterpret_cast<T*>(stack_); } 167 HasAllocator()168 bool HasAllocator() const { 169 return allocator_ != 0; 170 } 171 GetAllocator()172 Allocator& GetAllocator() { 173 RAPIDJSON_ASSERT(allocator_); 174 return *allocator_; 175 } 176 Empty()177 bool Empty() const { return stackTop_ == stack_; } GetSize()178 size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); } GetCapacity()179 size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); } 180 181 private: 182 template<typename T> Expand(size_t count)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 Resize(size_t newCapacity)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 Destroy()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 226 RAPIDJSON_NAMESPACE_END 227 228 #if defined(__clang__) 229 RAPIDJSON_DIAG_POP 230 #endif 231 232 #endif // RAPIDJSON_STACK_H_ 233