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