Commit 4a2ddf80 authored by Milo Yip's avatar Milo Yip

Add Stack::ShrinkToFit() and some refactoring.

Lazy allocation. (so Document not for parsing don't need to allocate
stack).
Remove redundant stackCapacity member variable.
parent 4600680a
...@@ -33,67 +33,84 @@ namespace internal { ...@@ -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: ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment