Path: blob/master/dep/rapidyaml/include/c4/yml/detail/stack.hpp
4270 views
#ifndef _C4_YML_DETAIL_STACK_HPP_1#define _C4_YML_DETAIL_STACK_HPP_23#ifndef _C4_YML_COMMON_HPP_4#include "../common.hpp"5#endif67#ifdef RYML_DBG8# include <type_traits>9#endif1011#include <string.h>1213namespace c4 {14namespace yml {15namespace detail {1617/** A lightweight contiguous stack with SSO. This avoids a dependency on std. */18template<class T, size_t N=16>19class stack20{21static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");22static_assert(std::is_trivially_destructible<T>::value, "T must be trivially destructible");2324enum : size_t { sso_size = N };2526public:2728T m_buf[N];29T * m_stack;30size_t m_size;31size_t m_capacity;32Callbacks m_callbacks;3334public:3536constexpr static bool is_contiguous() { return true; }3738stack(Callbacks const& cb)39: m_buf()40, m_stack(m_buf)41, m_size(0)42, m_capacity(N)43, m_callbacks(cb) {}44stack() : stack(get_callbacks()) {}45~stack()46{47_free();48}4950stack(stack const& that) noexcept : stack(that.m_callbacks)51{52resize(that.m_size);53_cp(&that);54}5556stack(stack &&that) noexcept : stack(that.m_callbacks)57{58_mv(&that);59}6061stack& operator= (stack const& that) noexcept62{63_cb(that.m_callbacks);64resize(that.m_size);65_cp(&that);66return *this;67}6869stack& operator= (stack &&that) noexcept70{71_cb(that.m_callbacks);72_mv(&that);73return *this;74}7576public:7778size_t size() const { return m_size; }79size_t empty() const { return m_size == 0; }80size_t capacity() const { return m_capacity; }8182void clear()83{84m_size = 0;85}8687void resize(size_t sz)88{89reserve(sz);90m_size = sz;91}9293void reserve(size_t sz);9495void push(T const& C4_RESTRICT n)96{97RYML_ASSERT((const char*)&n + sizeof(T) < (const char*)m_stack || &n > m_stack + m_capacity);98if(m_size == m_capacity)99{100size_t cap = m_capacity == 0 ? N : 2 * m_capacity;101reserve(cap);102}103m_stack[m_size] = n;104++m_size;105}106107void push_top()108{109RYML_ASSERT(m_size > 0);110if(m_size == m_capacity)111{112size_t cap = m_capacity == 0 ? N : 2 * m_capacity;113reserve(cap);114}115m_stack[m_size] = m_stack[m_size - 1];116++m_size;117}118119T const& C4_RESTRICT pop()120{121RYML_ASSERT(m_size > 0);122--m_size;123return m_stack[m_size];124}125126C4_ALWAYS_INLINE T const& C4_RESTRICT top() const { RYML_ASSERT(m_size > 0); return m_stack[m_size - 1]; }127C4_ALWAYS_INLINE T & C4_RESTRICT top() { RYML_ASSERT(m_size > 0); return m_stack[m_size - 1]; }128129C4_ALWAYS_INLINE T const& C4_RESTRICT bottom() const { RYML_ASSERT(m_size > 0); return m_stack[0]; }130C4_ALWAYS_INLINE T & C4_RESTRICT bottom() { RYML_ASSERT(m_size > 0); return m_stack[0]; }131132C4_ALWAYS_INLINE T const& C4_RESTRICT top(size_t i) const { RYML_ASSERT(i < m_size); return m_stack[m_size - 1 - i]; }133C4_ALWAYS_INLINE T & C4_RESTRICT top(size_t i) { RYML_ASSERT(i < m_size); return m_stack[m_size - 1 - i]; }134135C4_ALWAYS_INLINE T const& C4_RESTRICT bottom(size_t i) const { RYML_ASSERT(i < m_size); return m_stack[i]; }136C4_ALWAYS_INLINE T & C4_RESTRICT bottom(size_t i) { RYML_ASSERT(i < m_size); return m_stack[i]; }137138C4_ALWAYS_INLINE T const& C4_RESTRICT operator[](size_t i) const { RYML_ASSERT(i < m_size); return m_stack[i]; }139C4_ALWAYS_INLINE T & C4_RESTRICT operator[](size_t i) { RYML_ASSERT(i < m_size); return m_stack[i]; }140141public:142143using iterator = T *;144using const_iterator = T const *;145146iterator begin() { return m_stack; }147iterator end () { return m_stack + m_size; }148149const_iterator begin() const { return (const_iterator)m_stack; }150const_iterator end () const { return (const_iterator)m_stack + m_size; }151152public:153void _free();154void _cp(stack const* C4_RESTRICT that);155void _mv(stack * that);156void _cb(Callbacks const& cb);157};158159160//-----------------------------------------------------------------------------161//-----------------------------------------------------------------------------162//-----------------------------------------------------------------------------163164template<class T, size_t N>165void stack<T, N>::reserve(size_t sz)166{167if(sz <= m_size)168return;169if(sz <= N)170{171m_stack = m_buf;172m_capacity = N;173return;174}175T *buf = (T*) m_callbacks.m_allocate(sz * sizeof(T), m_stack, m_callbacks.m_user_data);176memcpy(buf, m_stack, m_size * sizeof(T));177if(m_stack != m_buf)178{179m_callbacks.m_free(m_stack, m_capacity * sizeof(T), m_callbacks.m_user_data);180}181m_stack = buf;182m_capacity = sz;183}184185186//-----------------------------------------------------------------------------187188template<class T, size_t N>189void stack<T, N>::_free()190{191RYML_ASSERT(m_stack != nullptr); // this structure cannot be memset() to zero192if(m_stack != m_buf)193{194m_callbacks.m_free(m_stack, m_capacity * sizeof(T), m_callbacks.m_user_data);195m_stack = m_buf;196m_size = N;197m_capacity = N;198}199else200{201RYML_ASSERT(m_capacity == N);202}203}204205206//-----------------------------------------------------------------------------207208template<class T, size_t N>209void stack<T, N>::_cp(stack const* C4_RESTRICT that)210{211if(that->m_stack != that->m_buf)212{213RYML_ASSERT(that->m_capacity > N);214RYML_ASSERT(that->m_size <= that->m_capacity);215}216else217{218RYML_ASSERT(that->m_capacity <= N);219RYML_ASSERT(that->m_size <= that->m_capacity);220}221memcpy(m_stack, that->m_stack, that->m_size * sizeof(T));222m_size = that->m_size;223m_capacity = that->m_size < N ? N : that->m_size;224m_callbacks = that->m_callbacks;225}226227228//-----------------------------------------------------------------------------229230template<class T, size_t N>231void stack<T, N>::_mv(stack * that)232{233if(that->m_stack != that->m_buf)234{235RYML_ASSERT(that->m_capacity > N);236RYML_ASSERT(that->m_size <= that->m_capacity);237m_stack = that->m_stack;238}239else240{241RYML_ASSERT(that->m_capacity <= N);242RYML_ASSERT(that->m_size <= that->m_capacity);243memcpy(m_buf, that->m_buf, that->m_size * sizeof(T));244m_stack = m_buf;245}246m_size = that->m_size;247m_capacity = that->m_capacity;248m_callbacks = that->m_callbacks;249// make sure no deallocation happens on destruction250RYML_ASSERT(that->m_stack != m_buf);251that->m_stack = that->m_buf;252that->m_capacity = N;253that->m_size = 0;254}255256257//-----------------------------------------------------------------------------258259template<class T, size_t N>260void stack<T, N>::_cb(Callbacks const& cb)261{262if(cb != m_callbacks)263{264_free();265m_callbacks = cb;266}267}268269} // namespace detail270} // namespace yml271} // namespace c4272273#endif /* _C4_YML_DETAIL_STACK_HPP_ */274275276