diff options
Merge commit '6e19bb560d474736d45f5be011ff0830c7019991' as 'spasm'
1 files changed, 172 insertions, 0 deletions
| -rw-r--r-- | spasm/src/dstack.cpp | 172 |
diff --git a/spasm/src/dstack.cpp b/spasm/src/dstack.cpp new file mode 100644 index 0000000..93592ed --- /dev/null +++ b/spasm/src/dstack.cpp @@ -0,0 +1,172 @@ +#include "dstack.hpp" + +#include <algorithm> + +namespace SpasmImpl +{ +Dstack::Dstack() : bottom(NULL), tos(NULL), s_size(0) {} + +Dstack::Dstack(const Dstack& ds) : s_size(ds.s_size) +{ + copy_dstack(ds); +} + +Dstack& Dstack::operator=(const Dstack& ds) +{ + if (this != &ds) + { + if (bottom) + delete[] bottom; + s_size = ds.s_size; + copy_dstack(ds); + } + return *this; +} + +Dstack::~Dstack() +{ + if (bottom) + delete[] bottom; +} + +/** + * Makes the stack occupy new_size bytes + * \param new_size new size for the stack + */ +void Dstack::reserve(size_t new_size) +{ + size_t offset = tos - bottom; + byte* new_bottom = new byte[new_size]; + if (bottom) + { + std::copy(bottom, bottom + std::min(s_size, new_size), new_bottom); + delete[] bottom; + } + bottom = new_bottom; + tos = new_bottom + offset; + s_size = new_size; +} + +/*! +** Pushes x in the stack. +** If the stack is full its size is doubled. +** \param x data_t object to be pushed on the stack +*/ +void Dstack::push(data_t x) +{ + if (bottom + s_size < tos + sizeof(data_t)) + reserve((s_size ? s_size : sizeof(data_t)) * 2); + *((data_t*)tos) = x; + tos += sizeof(data_t); +} + +/*! +** Pushes the object of size x_size bytes pointed by x in the stack. +** If the stack is full its size is doubled (or more is x_size is greater +** than the size of the stack). +** \param x pointer to the element to be pushed on the stack +** \param x_size size of the element +*/ +void Dstack::push(byte* x, size_t x_size) +{ + if (bottom + s_size < tos + x_size) + reserve(s_size + ((s_size > x_size) ? s_size : x_size)); + std::copy(x, x + x_size, tos); + tos += x_size; +} + +/*! +** Pops an object of size x_size from the stack. +** The object is written to the place pointed by x. +** +** \param x pointer to the place for popping +** \param x_size size of the object to be popped +*/ +void Dstack::pop(void* x, size_t x_size) +{ + if (tos - x_size >= bottom) + { + std::copy(tos - x_size, tos, (byte*)x); + tos -= x_size; + } +} + +/*! +** \return a single data_t object, popping it from the stack. +*/ +data_t Dstack::pop() +{ + data_t x{}; + if (tos - sizeof(data_t) >= bottom) + { + tos -= sizeof(data_t); + x = *((data_t*)tos); + } + return x; +} + +/*! +** \return copy of the data_t object that is on top of the stack +*/ +data_t Dstack::top() const +{ + data_t x{}; + if (tos - sizeof(data_t) >= bottom) + { + x = *((data_t*)(tos - sizeof(data_t))); + } + return x; +} + +/*! +** \return the size of the stack in bytes +*/ +size_t Dstack::size() const +{ + return tos - bottom; +} + +/*! +** \return the space reserved for the stack in bytes +*/ +size_t Dstack::reserved() const +{ + return s_size; +} + +/*! +** Frees unused memory. Note that it is not always possible because memory +** management is done with new / delete +*/ + +void Dstack::strip_memory() +{ + reserve(size()); +} + +/*! +** \return true if the stack is empty +*/ +bool Dstack::empty() const +{ + return tos - bottom == 0; +} + +/*! +** Creates a copy of ds +** +** \param ds data stack to be copied +*/ +void Dstack::copy_dstack(const Dstack& ds) +{ + if (ds.bottom) + { + bottom = new byte[ds.s_size]; + tos = bottom + (ds.tos - ds.bottom); + std::copy(ds.bottom, ds.tos, bottom); + } + else + bottom = tos = NULL; +} + +} // namespace SpasmImpl |
