Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
stack.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
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
29namespace internal {
30
32// Stack
33
35
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
228
229#if defined(__clang__)
230RAPIDJSON_DIAG_POP
231#endif
232
233#endif // RAPIDJSON_STACK_H_
A type-unsafe stack for storing different types of data.
Definition stack.h:38
Concept for allocating, resizing and freeing memory block.
#define RAPIDJSON_UNLIKELY(x)
Compiler branching hint for expression with low probability to be true.
Definition rapidjson.h:477
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition rapidjson.h:407
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition rapidjson.h:122
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition rapidjson.h:125
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition rapidjson.h:652
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition rapidjson.h:648