| #pragma once |
| |
| #ifndef TCG_LIST_H |
| #define TCG_LIST_H |
| |
| |
| #include "alignment.h" |
| #include "macros.h" |
| |
| |
| #include <cstddef> // size_t |
| #include <new> // placement new |
| #include <vector> |
| |
| #include "assert.h" |
| |
| |
| |
| |
| #ifndef TCG_RVALUES_SUPPORT |
| #include <boost/config.hpp> |
| |
| #ifdef BOOST_NO_RVALUE_REFERENCES |
| #define TCG_RVALUES_SUPPORT 0 |
| #else |
| #define TCG_RVALUES_SUPPORT 1 |
| #endif |
| #endif |
| |
| #if (TCG_RVALUES_SUPPORT > 0) |
| |
| |
| #define TCG_FORWARD_TYPE(TheType) TheType##__ && |
| #define TCG_FORWARD_TEMPLATE(TheType) template <typename TheType##__> |
| #define TCG_FORWARD(TheType, Val) std::forward<TheType##__>(Val) |
| |
| #else |
| |
| |
| #define TCG_FORWARD_TYPE(TheType) const TheType & |
| #define TCG_FORWARD_TEMPLATE(TheType) |
| #define TCG_FORWARD(TheType, Val) Val |
| |
| #endif |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| namespace tcg |
| { |
| |
| static const size_t _neg = -1, |
| _invalid = -2; |
| |
| } |
| |
| |
| |
| |
| |
| namespace tcg |
| { |
| |
| |
| |
| |
| |
| template <typename T> |
| struct _list_node { |
| TCG_STATIC_ASSERT(sizeof(T) == sizeof(aligned_buffer<T>)); |
| |
| aligned_buffer<T> m_val; |
| size_t m_prev, m_next; |
| |
| TCG_DEBUG(T &m_t;) |
| |
| public: |
| _list_node() : m_prev(_neg), m_next(_invalid) TCG_DEBUG2(, m_t(value())) |
| { |
| } |
| _list_node(const T &val) : m_prev(_neg), m_next(_neg) TCG_DEBUG2(, m_t(value())) |
| { |
| constructValue(val); |
| } |
| ~_list_node() |
| { |
| if (isValid()) |
| destroyValue(); |
| } |
| |
| _list_node(const _list_node &other) |
| : m_prev(other.m_prev), m_next(other.m_next) TCG_DEBUG2(, m_t(value())) |
| { |
| if (other.isValid()) |
| constructValue(other.value()); |
| } |
| |
| _list_node &operator=(const _list_node &other) |
| { |
| if (isValid()) |
| if (other.isValid()) |
| value() = other.value(); |
| else |
| destroyValue(); |
| else |
| constructValue(other.value()); |
| |
| m_prev = other.m_prev, m_next = other.m_next; |
| return *this; |
| } |
| |
| const T &value() const { return reinterpret_cast<const T &>(m_val.m_buf); } |
| T &value() { return reinterpret_cast<T &>(m_val.m_buf); } |
| |
| bool isValid() const { return (m_next != _invalid); } |
| void invalidate() |
| { |
| assert(isValid()); |
| destroyValue(); |
| m_next = _invalid; |
| } |
| |
| #if (TCG_RVALUES_SUPPORT > 0) |
| |
| _list_node(T &&val) : m_prev(_neg), m_next(_neg) TCG_DEBUG2(, m_t(value())) |
| { |
| constructValue(std::move(val)); |
| } |
| |
| _list_node(_list_node &&other) |
| : m_prev(other.m_prev), m_next(other.m_next) TCG_DEBUG2(, m_t(value())) |
| { |
| if (other.isValid()) |
| constructValue(std::move(other.value())), other.invalidate(); |
| } |
| |
| _list_node &operator=(_list_node &&other) |
| { |
| if (isValid()) |
| if (other.isValid()) |
| value() = other.value(); |
| else |
| destroyValue(); |
| else |
| constructValue(std::move(other.value())); |
| |
| value() = std::move(other.value()); |
| m_prev = other.m_prev, m_next = other.m_next; |
| return *this; |
| } |
| |
| #endif |
| |
| public: |
| void constructValue(const T &val) { new (m_val.m_buf) T(val); } |
| void destroyValue() { value().~T(); } |
| |
| #if (TCG_RVALUES_SUPPORT > 0) |
| void constructValue(T &&val) |
| { |
| new (m_val.m_buf) T(std::move(val)); |
| } |
| #endif |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename T> |
| class list_base |
| { |
| public: |
| typedef T value_type; |
| typedef ::size_t size_t; |
| |
| static const size_t _neg = -1; |
| |
| protected: |
| typedef _list_node<T> list_node; |
| |
| std::vector<list_node> m_vector; |
| |
| size_t m_size; |
| size_t m_clearedHead; |
| |
| public: |
| struct const_iterator : public std::iterator<std::bidirectional_iterator_tag, const T> { |
| const list_base *m_list; |
| size_t m_idx; |
| |
| TCG_DEBUG(const list_node *m_node;) |
| |
| public: |
| typedef const T value_type; |
| typedef const T *pointer; |
| typedef const T &reference; |
| |
| public: |
| const_iterator() {} |
| const_iterator(const list_base *list, size_t idx) |
| : m_list(list), m_idx(idx) { TCG_DEBUG(m_node = (m_idx == _neg) ? 0 : &m_list->m_vector[m_idx]); } |
| |
| size_t index() const { return m_idx; } |
| |
| reference operator*() const { return (*m_list)[m_idx]; } |
| pointer operator->() const { return &(*m_list)[m_idx]; } |
| |
| const_iterator operator++(int) |
| { |
| const_iterator temp(*this); |
| operator++(); |
| return temp; |
| } |
| const_iterator &operator++() |
| { |
| m_idx = m_list->m_vector[m_idx].m_next; |
| TCG_DEBUG(m_node = (m_idx == _neg) ? 0 : &m_list->m_vector[m_idx]); |
| return *this; |
| } |
| |
| const_iterator operator--(int) |
| { |
| const_iterator temp(*this); |
| operator--(); |
| return temp; |
| } |
| const_iterator &operator--() |
| { |
| m_idx = m_list->m_vector[m_idx].m_prev; |
| TCG_DEBUG(m_node = (m_idx == _neg) ? 0 : &m_list->m_vector[m_idx]); |
| return *this; |
| } |
| |
| bool operator==(const const_iterator &it) const { return (m_idx == it.m_idx); } |
| bool operator!=(const const_iterator &it) const { return (m_idx != it.m_idx); } |
| }; |
| |
| struct iterator : public const_iterator { |
| public: |
| typedef T value_type; |
| typedef T *pointer; |
| typedef T &reference; |
| |
| public: |
| iterator() {} |
| iterator(list_base *list, size_t idx) : const_iterator(list, idx) {} |
| |
| reference operator*() const { return const_cast<reference>(const_iterator::operator*()); } |
| pointer operator->() const { return const_cast<pointer>(const_iterator::operator->()); } |
| |
| iterator operator++(int) |
| { |
| iterator temp(*this); |
| operator++(); |
| return temp; |
| } |
| iterator &operator++() |
| { |
| const_iterator::operator++(); |
| return *this; |
| } |
| |
| iterator operator--(int) |
| { |
| iterator temp(*this); |
| operator--(); |
| return temp; |
| } |
| iterator &operator--() |
| { |
| const_iterator::operator--(); |
| return *this; |
| } |
| }; |
| |
| friend struct iterator; |
| friend struct const_iterator; |
| |
| public: |
| list_base() : m_size(0), m_clearedHead(_neg) {} |
| |
| list_base(size_t count, const T &val) |
| : m_vector(count, list_node(val)), m_size(count), m_clearedHead(_neg) |
| { |
| assert(m_size >= 0); |
| for (size_t i = 0; i < m_size; ++i) |
| m_vector[i].m_prev = i - 1, m_vector[i].m_next = i + 1; |
| if (m_size > 0) |
| m_vector[m_size - 1].m_next = _neg; |
| } |
| |
| template <typename InIt> |
| list_base(InIt begin, InIt end) |
| : m_vector(begin, end), m_size(m_vector.size()), m_clearedHead(_neg) |
| { |
| assert(m_size >= 0); |
| for (size_t i = 0; i < m_size; ++i) |
| m_vector[i].m_prev = i - 1, m_vector[i].m_next = i + 1; |
| if (m_size > 0) |
| m_vector[m_size - 1].m_next = _neg; |
| } |
| |
| |
| |
| list_base(const list_base &other) |
| : m_vector(other.m_vector), m_size(other.m_size), m_clearedHead(other.m_clearedHead) {} |
| |
| list_base &operator=(const list_base &other) |
| { |
| |
| |
| |
| m_size = other.m_size; |
| m_clearedHead = other.m_clearedHead; |
| |
| |
| |
| |
| |
| m_vector.clear(); |
| |
| m_vector = other.m_vector; |
| return *this; |
| } |
| |
| #if (TCG_RVALUES_SUPPORT > 0) |
| |
| list_base(list_base &&other) |
| : m_vector(std::move(other.m_vector)), m_size(other.m_size), m_clearedHead(other.m_clearedHead) |
| { |
| } |
| |
| list_base &operator=(list_base &&other) |
| { |
| swap(*this, std::forward<list_base>(other)); |
| return *this; |
| } |
| |
| #endif |
| |
| T &operator[](size_t idx) |
| { |
| assert(idx < m_vector.size() && isValid(idx)); |
| return m_vector[idx].value(); |
| } |
| const T &operator[](size_t idx) const |
| { |
| assert(idx < m_vector.size() && isValid(idx)); |
| return m_vector[idx].value(); |
| } |
| |
| bool isValid(size_t idx) const { return m_vector[idx].isValid(); } |
| |
| size_t size() const { return m_size; } |
| size_t nodesCount() const { return m_vector.size(); } |
| |
| void reserve(size_t size) { m_vector.reserve(size); } |
| size_t capacity() const { return m_vector.capacity(); } |
| |
| void clear() |
| { |
| m_size = 0; |
| m_clearedHead = _neg; |
| m_vector.clear(); |
| } |
| |
| bool empty() const { return m_size == 0; } |
| |
| void _swap(list_base &a, list_base &b) |
| { |
| std::swap(a.m_size, b.m_size); |
| std::swap(a.m_clearedHead, b.m_clearedHead); |
| a.m_vector.swap(b.m_vector); |
| } |
| |
| #if (TCG_RVALUES_SUPPORT > 0) |
| |
| void _swap(list_base &a, list_base &&b) |
| { |
| a.m_size = b.m_size; |
| a.m_clearedHead = b.m_clearedHead; |
| a.m_vector.swap(b.m_vector); |
| } |
| |
| void _swap(list_base &&a, list_base &b) |
| { |
| swap(b, std::move(a)); |
| } |
| |
| #endif |
| |
| |
| |
| |
| template <typename ForIt> |
| list_base(ForIt begin, ForIt end, size_t nodesCount) |
| { |
| |
| m_vector.resize(nodesCount, list_node()); |
| |
| |
| size_t lastIdx = _neg; |
| |
| for (; begin != end; ++begin) { |
| size_t idx = (*begin).first; |
| |
| assert(idx >= 0); |
| |
| |
| if (idx >= m_vector.size()) { |
| |
| |
| size_t newSize = m_vector.size(); |
| |
| for (ForIt it = begin; it != end; ++it) |
| newSize = std::max(newSize, size_t((*it).first) + 1); |
| |
| m_vector.resize(newSize, list_node()); |
| } |
| |
| |
| list_node &node = m_vector[idx]; |
| new (&node) list_node((*begin).second); |
| |
| |
| node.m_prev = lastIdx; |
| if (lastIdx != _neg) |
| m_vector[lastIdx].m_next = idx; |
| |
| lastIdx = idx; |
| } |
| |
| |
| lastIdx = _neg; |
| |
| size_t n, nCount = m_vector.size(); |
| for (n = 0; n != nCount; ++n) { |
| list_node &node = m_vector[n]; |
| |
| if (!node.isValid()) |
| node.m_prev = lastIdx, lastIdx = n; |
| } |
| |
| m_clearedHead = lastIdx; |
| } |
| |
| |
| |
| protected: |
| TCG_FORWARD_TEMPLATE(T) |
| size_t buyNode(TCG_FORWARD_TYPE(T) val) |
| { |
| size_t nodeIdx; |
| list_node *node; |
| |
| ++m_size; |
| |
| if (m_clearedHead != _neg) { |
| assert(m_clearedHead < m_vector.size()); |
| |
| |
| nodeIdx = m_clearedHead; |
| node = &m_vector[nodeIdx]; |
| |
| m_clearedHead = node->m_prev; |
| } else { |
| m_vector.push_back(list_node()); |
| |
| nodeIdx = m_vector.size() - 1; |
| node = &m_vector[nodeIdx]; |
| } |
| |
| |
| node->constructValue(TCG_FORWARD(T, val)); |
| |
| return nodeIdx; |
| } |
| |
| |
| |
| void sellNode(size_t idx) |
| { |
| assert(isValid(idx)); |
| |
| list_node &node = m_vector[idx]; |
| |
| |
| if (node.m_prev != _neg) |
| m_vector[node.m_prev].m_next = node.m_next; |
| if (node.m_next != _neg) |
| m_vector[node.m_next].m_prev = node.m_prev; |
| |
| |
| node.invalidate(); |
| |
| |
| |
| |
| |
| node.m_prev = m_clearedHead; |
| m_clearedHead = idx; |
| |
| --m_size; |
| } |
| |
| |
| |
| void sellNodes(size_t begin, size_t end) |
| { |
| for (size_t i = begin; i != end; i = m_vector[i].m_next) |
| sellNode(i); |
| } |
| |
| |
| |
| void move(size_t afterDst, size_t &dstBegin, size_t &dstRBegin, |
| size_t srcBegin, size_t srcEnd, size_t srcRBegin) |
| { |
| if (srcBegin == _neg || srcBegin == afterDst) |
| return; |
| |
| |
| { |
| size_t beforeDst = (afterDst == _neg) ? dstRBegin : m_vector[afterDst].m_prev; |
| |
| m_vector[srcBegin].m_prev = beforeDst; |
| |
| if (beforeDst != _neg) |
| m_vector[beforeDst].m_next = srcBegin; |
| else |
| dstBegin = srcBegin; |
| } |
| |
| |
| { |
| size_t srcLast = (srcEnd == _neg) ? srcRBegin : m_vector[srcEnd].m_prev; |
| |
| m_vector[srcLast].m_next = afterDst; |
| |
| if (afterDst != _neg) |
| m_vector[afterDst].m_prev = srcLast; |
| else |
| dstRBegin = srcLast; |
| } |
| } |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename T> |
| class list : public list_base<T> |
| { |
| size_t m_begin, m_rbegin; |
| |
| protected: |
| typedef typename list_base<T>::list_node list_node; |
| using list_base<T>::m_vector; |
| |
| public: |
| struct iterator : public list_base<T>::iterator { |
| iterator() {} |
| iterator(list *l, size_t idx) : list_base<T>::iterator(l, idx) {} |
| |
| iterator &operator++() |
| { |
| list_base<T>::iterator::operator++(); |
| return *this; |
| } |
| iterator &operator--() |
| { |
| if (this->m_idx == _neg) |
| operator=(static_cast<list *>(this->m_list)->last()); |
| else |
| list_base<T>::iterator::operator--(); |
| |
| return *this; |
| } |
| |
| iterator operator++(int) |
| { |
| iterator temp(*this); |
| operator++(); |
| return temp; |
| } |
| iterator operator--(int) |
| { |
| iterator temp(*this); |
| operator--(); |
| return temp; |
| } |
| }; |
| |
| struct const_iterator : public list_base<T>::const_iterator { |
| const_iterator() {} |
| const_iterator(const list *l, size_t idx) : list_base<T>::const_iterator(l, idx) {} |
| |
| const_iterator &operator++() |
| { |
| list_base<T>::const_iterator::operator++(); |
| return *this; |
| } |
| const_iterator &operator--() |
| { |
| if (this->m_idx == _neg) |
| operator=(static_cast<const list *>(this->m_list)->last()); |
| else |
| list_base<T>::const_iterator::operator--(); |
| |
| return *this; |
| } |
| |
| const_iterator operator++(int) |
| { |
| const_iterator temp(*this); |
| operator++(); |
| return temp; |
| } |
| const_iterator operator--(int) |
| { |
| const_iterator temp(*this); |
| operator--(); |
| return temp; |
| } |
| }; |
| |
| public: |
| list() : m_begin(_neg), m_rbegin(_neg) {} |
| list(size_t count, const T &val) : list_base<T>(count, val), m_begin(0), m_rbegin(count - 1) {} |
| |
| template <typename InIt> |
| list(InIt begin, InIt end) : list_base<T>(begin, end), m_begin(list_base<T>::m_size ? 0 : _neg), m_rbegin(list_base<T>::m_size - 1) {} |
| |
| |
| template <typename BidIt> |
| list(BidIt begin, BidIt end, size_t nodesCount) : list_base<T>(begin, end, nodesCount) |
| { |
| if (begin != end) |
| m_begin = (*begin).first, m_rbegin = (*--end).first; |
| } |
| |
| |
| |
| list(const list &other) : list_base<T>(other), m_begin(other.m_begin), m_rbegin(other.m_rbegin) {} |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| list &operator=(const list &other) |
| { |
| m_begin = other.m_begin, m_rbegin = other.m_rbegin; |
| list_base<T>::operator=(other); |
| return *this; |
| } |
| |
| #if (TCG_RVALUES_SUPPORT > 0) |
| |
| list(list &&other) : list_base<T>(std::forward<list_base<T>>(other)), m_begin(other.m_begin), m_rbegin(other.m_rbegin) |
| { |
| } |
| |
| list &operator=(list &&other) |
| { |
| swap(*this, std::forward<list>(other)); |
| return *this; |
| } |
| |
| #endif |
| |
| |
| |
| TCG_FORWARD_TEMPLATE(T) |
| size_t insert(size_t idx, TCG_FORWARD_TYPE(T) val) |
| { |
| assert(idx == _neg || list_base<T>::isValid(idx)); |
| |
| size_t nodeIdx = list_base<T>::buyNode(TCG_FORWARD(T, val)); |
| list_node &node = m_vector[nodeIdx]; |
| |
| |
| if (idx != _neg) { |
| |
| list_node &next = m_vector[idx]; |
| |
| node.m_prev = next.m_prev; |
| next.m_prev = nodeIdx; |
| node.m_next = idx; |
| if (node.m_prev != _neg) |
| m_vector[node.m_prev].m_next = nodeIdx; |
| } else { |
| node.m_next = _neg; |
| node.m_prev = m_rbegin; |
| if (m_rbegin != _neg) |
| m_vector[m_rbegin].m_next = nodeIdx; |
| m_rbegin = nodeIdx; |
| } |
| |
| if (idx == m_begin) |
| m_begin = nodeIdx; |
| |
| return nodeIdx; |
| } |
| |
| template <typename Iter> |
| size_t insert(size_t idx, Iter begin, Iter end) |
| { |
| if (begin == end) |
| return idx; |
| |
| assert(idx == _neg || list_base<T>::isValid(idx)); |
| |
| size_t res = insert(idx, *begin); |
| |
| for (++begin; begin != end; ++begin) |
| insert(idx, *begin); |
| |
| return res; |
| } |
| |
| size_t erase(size_t idx) |
| { |
| assert(list_base<T>::isValid(idx)); |
| |
| if (idx == m_begin) |
| m_begin = m_vector[idx].m_next; |
| if (idx == m_rbegin) |
| m_rbegin = m_vector[idx].m_prev; |
| |
| size_t result = m_vector[idx].m_next; |
| list_base<T>::sellNode(idx); |
| |
| return result; |
| } |
| |
| size_t erase(size_t begin, size_t end) |
| { |
| assert(list_base<T>::isValid(begin)); |
| |
| if (begin == m_begin) |
| m_begin = end; |
| if (end == m_rbegin) |
| m_rbegin = m_vector[begin].m_prev; |
| |
| list_base<T>::sellNodes(begin, end); |
| |
| return end; |
| } |
| |
| void clear() |
| { |
| list_base<T>::clear(); |
| m_begin = m_rbegin = _neg; |
| } |
| |
| void swap(list &other) |
| { |
| _swap(*this, other); |
| std::swap(m_begin, other.m_begin); |
| std::swap(m_rbegin, other.m_rbegin); |
| } |
| |
| void swap(list &a, list &b) |
| { |
| a.swap(b); |
| } |
| |
| #if (TCG_RVALUES_SUPPORT > 0) |
| |
| void swap(list &&other) |
| { |
| this->_swap(*this, std::move(other)); |
| m_begin = other.m_begin; |
| m_rbegin = other.m_rbegin; |
| } |
| |
| void swap(list &a, list &&b) |
| { |
| a.swap(std::move(b)); |
| } |
| |
| void swap(list &&a, list &b) |
| { |
| b.swap(std::move(a)); |
| } |
| |
| #endif |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void move(size_t afterDst, size_t srcBegin, size_t srcEnd) |
| { |
| return move(afterDst, m_begin, m_rbegin, |
| srcBegin, srcEnd, m_rbegin); |
| } |
| |
| |
| |
| |
| void move(iterator afterDst, |
| iterator srcBegin, iterator srcEnd) |
| { |
| assert(afterDst.m_list == this && |
| srcBegin.m_list == this && |
| srcEnd.m_list == this); |
| |
| return move(afterDst.m_idx, srcBegin.m_idx, srcEnd.m_idx); |
| } |
| |
| |
| |
| iterator insert(iterator it, const T &val) { return iterator(this, insert(it.m_idx, val)); } |
| iterator erase(iterator it) { return iterator(this, erase(it.m_idx)); } |
| |
| template <typename Iter> |
| iterator insert(iterator it, Iter begin, Iter end) { return iterator(this, insert(it.m_idx, begin, end)); } |
| iterator erase(iterator begin, iterator end) { return iterator(this, erase(begin.m_idx, end.m_idx)); } |
| |
| size_t push_front(const T &val) { return insert(m_begin, val); } |
| size_t push_back(const T &val) { return insert(_neg, val); } |
| |
| void pop_front() { erase(m_begin); } |
| void pop_back() { erase(m_rbegin); } |
| |
| T &front() { return m_vector[m_begin].value(); } |
| const T &front() const { return m_vector[m_begin].value(); } |
| |
| T &back() { return m_vector[m_rbegin].value(); } |
| const T &back() const { return m_vector[m_rbegin].value(); } |
| |
| iterator begin() { return iterator(this, m_begin); } |
| const_iterator begin() const { return const_iterator(this, m_begin); } |
| |
| iterator last() { return iterator(this, m_rbegin); } |
| const_iterator last() const { return const_iterator(this, m_rbegin); } |
| |
| iterator end() { return iterator(this, _neg); } |
| const_iterator end() const { return const_iterator(this, _neg); } |
| |
| #if (TCG_RVALUES_SUPPORT > 0) |
| |
| iterator insert(iterator it, T &&val) |
| { |
| return iterator(this, insert<T>(it.m_idx, std::forward<T>(val))); |
| } |
| size_t push_front(T &&val) { return insert<T>(m_begin, std::forward<T>(val)); } |
| size_t push_back(T &&val) { return insert<T>(_neg, std::forward<T>(val)); } |
| |
| #endif |
| }; |
| |
| } |
| |
| #endif |