| 25 | namespace internal { |
| 26 | |
| 27 | class Stack { |
| 28 | public: |
| 29 | Stack(size_t cap = defaultCapcity()) : cap_(cap) { Reserve(cap); } |
| 30 | Stack(const Stack&) = delete; |
| 31 | Stack(Stack&& rhs) : buf_(rhs.buf_), top_(rhs.top_), cap_(rhs.cap_) { |
| 32 | rhs.setZero(); |
| 33 | } |
| 34 | ~Stack() { std::free(buf_); } |
| 35 | Stack& operator=(const Stack&) = delete; |
| 36 | Stack& operator=(Stack&& rhs) { |
| 37 | std::free(buf_); |
| 38 | buf_ = rhs.buf_; |
| 39 | top_ = rhs.top_; |
| 40 | cap_ = rhs.cap_; |
| 41 | rhs.setZero(); |
| 42 | return *this; |
| 43 | } |
| 44 | |
| 45 | sonic_force_inline size_t Size() const { return top_ - buf_; } |
| 46 | sonic_force_inline size_t Capacity() const { return cap_; } |
| 47 | sonic_force_inline bool Empty() const { return Size() == 0; } |
| 48 | |
| 49 | /** |
| 50 | * @brief Increase the capacity of buffer if new_cap is greater than the |
| 51 | * current capacity(). Otherwise, do nothing. |
| 52 | */ |
| 53 | sonic_force_inline void Reserve(size_t new_cap) { |
| 54 | if (new_cap < Capacity()) { |
| 55 | return; |
| 56 | } |
| 57 | size_t align_cap = SONIC_ALIGN(new_cap); |
| 58 | char* tmp = static_cast<char*>(std::realloc(buf_, align_cap)); |
| 59 | top_ = tmp + Size(); |
| 60 | buf_ = tmp; |
| 61 | sonic_assert(buf_ != NULL); |
| 62 | cap_ = buf_ ? new_cap : 0; |
| 63 | } |
| 64 | |
| 65 | /** |
| 66 | * @brief Erases all contexts in the buffer. |
| 67 | */ |
| 68 | sonic_force_inline void Clear() { top_ = buf_; } |
| 69 | |
| 70 | /** |
| 71 | * @brief Push a value into buffer |
| 72 | * @param v the pushed value, as char, int... |
| 73 | */ |
| 74 | template <typename T> |
| 75 | sonic_force_inline void Push(T v) { |
| 76 | Grow(sizeof(T)); |
| 77 | *reinterpret_cast<T*>(top_) = v; |
| 78 | top_ += sizeof(T); |
| 79 | } |
| 80 | |
| 81 | /** |
| 82 | * @brief Push a string into buffer. |
| 83 | * @param s the begining of string |
| 84 | * @param n the string size |