Add Stack::ShrinkToFit() and some refactoring.
Lazy allocation. (so Document not for parsing don't need to allocate stack). Remove redundant stackCapacity member variable.
This commit is contained in:
parent
4600680a56
commit
4a2ddf8075
@ -33,67 +33,84 @@ namespace internal {
|
|||||||
template <typename Allocator>
|
template <typename Allocator>
|
||||||
class Stack {
|
class Stack {
|
||||||
public:
|
public:
|
||||||
Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {
|
// Optimization note: Do not allocate memory for stack_ in constructor.
|
||||||
RAPIDJSON_ASSERT(stack_capacity_ > 0);
|
// Do it lazily when first Push() -> Expand() -> Resize().
|
||||||
|
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
|
||||||
|
RAPIDJSON_ASSERT(stackCapacity > 0);
|
||||||
if (!allocator_)
|
if (!allocator_)
|
||||||
own_allocator_ = allocator_ = new Allocator();
|
ownAllocator = allocator_ = new Allocator();
|
||||||
stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);
|
|
||||||
stack_end_ = stack_ + stack_capacity_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~Stack() {
|
~Stack() {
|
||||||
Allocator::Free(stack_);
|
Allocator::Free(stack_);
|
||||||
delete own_allocator_; // Only delete if it is owned by the stack
|
delete ownAllocator; // Only delete if it is owned by the stack
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
|
void Clear() { stackTop_ = stack_; }
|
||||||
|
|
||||||
|
void ShrinkToFit() {
|
||||||
|
if (Empty()) {
|
||||||
|
// If the stack is empty, completely deallocate the memory.
|
||||||
|
Allocator::Free(stack_);
|
||||||
|
stack_ = 0;
|
||||||
|
stackTop_ = 0;
|
||||||
|
stackEnd_ = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Resize(GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
// Optimization note: try to minimize the size of this function for force inline.
|
// Optimization note: try to minimize the size of this function for force inline.
|
||||||
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||||
// Expand the stack if needed
|
// Expand the stack if needed
|
||||||
if (stack_top_ + sizeof(T) * count >= stack_end_)
|
if (stackTop_ + sizeof(T) * count >= stackEnd_)
|
||||||
Expand<T>(count);
|
Expand<T>(count);
|
||||||
|
|
||||||
T* ret = reinterpret_cast<T*>(stack_top_);
|
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||||
stack_top_ += sizeof(T) * count;
|
stackTop_ += sizeof(T) * count;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* Pop(size_t count) {
|
T* Pop(size_t count) {
|
||||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||||
stack_top_ -= count * sizeof(T);
|
stackTop_ -= count * sizeof(T);
|
||||||
return reinterpret_cast<T*>(stack_top_);
|
return reinterpret_cast<T*>(stackTop_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* Top() {
|
T* Top() {
|
||||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||||
return reinterpret_cast<T*>(stack_top_ - sizeof(T));
|
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* Bottom() { return (T*)stack_; }
|
T* Bottom() { return (T*)stack_; }
|
||||||
|
|
||||||
Allocator& GetAllocator() { return *allocator_; }
|
Allocator& GetAllocator() { return *allocator_; }
|
||||||
bool Empty() const { return stack_top_ == stack_; }
|
bool Empty() const { return stackTop_ == stack_; }
|
||||||
size_t GetSize() const { return static_cast<size_t>(stack_top_ - stack_); }
|
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||||
size_t GetCapacity() const { return stack_capacity_; }
|
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Expand(size_t count) {
|
void Expand(size_t count) {
|
||||||
size_t new_capacity = stack_capacity_ * 2;
|
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
|
||||||
size_t size = GetSize();
|
size_t newCapacity = (stack_ == 0) ? initialCapacity_ : GetCapacity() * 2;
|
||||||
size_t new_size = GetSize() + sizeof(T) * count;
|
size_t newSize = GetSize() + sizeof(T) * count;
|
||||||
if (new_capacity < new_size)
|
if (newCapacity < newSize)
|
||||||
new_capacity = new_size;
|
newCapacity = newSize;
|
||||||
stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity);
|
|
||||||
stack_capacity_ = new_capacity;
|
Resize(newCapacity);
|
||||||
stack_top_ = stack_ + size;
|
}
|
||||||
stack_end_ = stack_ + stack_capacity_;
|
|
||||||
|
void Resize(size_t newCapacity) {
|
||||||
|
const size_t size = GetSize(); // Backup the current size
|
||||||
|
stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);
|
||||||
|
stackTop_ = stack_ + size;
|
||||||
|
stackEnd_ = stack_ + newCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prohibit copy constructor & assignment operator.
|
// Prohibit copy constructor & assignment operator.
|
||||||
@ -101,11 +118,11 @@ private:
|
|||||||
Stack& operator=(const Stack&);
|
Stack& operator=(const Stack&);
|
||||||
|
|
||||||
Allocator* allocator_;
|
Allocator* allocator_;
|
||||||
Allocator* own_allocator_;
|
Allocator* ownAllocator;
|
||||||
char *stack_;
|
char *stack_;
|
||||||
char *stack_top_;
|
char *stackTop_;
|
||||||
char *stack_end_;
|
char *stackEnd_;
|
||||||
size_t stack_capacity_;
|
size_t initialCapacity_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
Loading…
x
Reference in New Issue
Block a user