Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. #pragma once
  8.  
  9. #include <algorithm>
  10. #include <cstddef>
  11. #include <memory>
  12. #include <stdexcept>
  13. #include "dxxsconf.h"
  14. #include <array>
  15.  
  16. template <typename T = unsigned>
  17. class base_count_array_t
  18. {
  19. protected:
  20.         typedef T size_type;
  21.         void clear() { m_count = 0; }
  22.         size_type m_count = 0;
  23. public:
  24.         size_type size() const { return m_count; }
  25.         bool empty() const { return !m_count; }
  26. };
  27.  
  28. template <typename T, std::size_t S>
  29. class count_array_t : public base_count_array_t<>
  30. {
  31. public:
  32.         using array_type = std::array<T, S>;
  33.         typedef typename array_type::value_type value_type;
  34.         typedef typename array_type::iterator iterator;
  35.         typedef typename array_type::const_iterator const_iterator;
  36.         typedef typename array_type::const_reference const_reference;
  37.         static typename array_type::size_type max_size() { return S; }
  38.         ~count_array_t() { clear(); }
  39.         count_array_t &operator=(const count_array_t &rhs)
  40.         {
  41.                 if (this != &rhs)
  42.                 {
  43.                         iterator lb = begin();
  44.                         iterator le = end();
  45.                         const_iterator rb = rhs.begin();
  46.                         const_iterator re = rhs.end();
  47.                         for (; lb != le && rb != re; ++lb, ++rb)
  48.                                 *lb = *rb;
  49.                         shrink(lb);
  50.                         for (; rb != re; ++rb)
  51.                                 emplace_back(*rb);
  52.                 }
  53.                 return *this;
  54.         }
  55.         template <typename... Args>
  56.         void emplace_back(Args&&... args)
  57.         {
  58.                 if (m_count >= S)
  59.                         throw std::length_error("too many elements");
  60.                 T *uninitialized = static_cast<T *>(&arrayref()[m_count]);
  61.                 new(static_cast<void *>(uninitialized)) T(std::forward<Args>(args)...);
  62.                 ++ m_count;
  63.         }
  64.         void clear()
  65.         {
  66.                 shrink(begin());
  67.         }
  68.         // for std::back_insert_iterator
  69.         void push_back(const T& t)
  70.         {
  71.                 emplace_back(t);
  72.         }
  73.         void pop_back()
  74.         {
  75.                 shrink(end() - 1);
  76.         }
  77.         iterator begin() { return arrayref().begin(); }
  78.         iterator end() { return arrayref().begin() + m_count; }
  79.         iterator find(const T &t) { return std::find(begin(), end(), t); }
  80.         const_iterator find(const T &t) const { return std::find(begin(), end(), t); }
  81.         const_reference operator[](size_type i) const
  82.         {
  83.                 if (i >= m_count)
  84.                         throw std::out_of_range("not enough elements");
  85.                 return arrayref()[i];
  86.         }
  87.         const_reference back() const { return (*this)[m_count - 1]; }
  88.         bool contains(const T &t) const { return find(t) != end(); }
  89.         void erase(iterator i)
  90.         {
  91.                 shrink(i);
  92.         }
  93.         void erase(const T &t)
  94.         {
  95.                 shrink(std::remove(begin(), end(), t));
  96.         }
  97.         template <typename F>
  98.                 void erase_if(F f)
  99.                 {
  100.                         shrink(std::remove_if(begin(), end(), f));
  101.                 }
  102.         void replace(const T &o, const T &n)
  103.         {
  104.                 std::replace(begin(), end(), o, n);
  105.         }
  106.         const_iterator begin() const { return arrayref().begin(); }
  107.         const_iterator end() const { return arrayref().begin() + m_count; }
  108. private:
  109.         void destroy(iterator b, iterator e)
  110.         {
  111.                 for (; b != e; ++b)
  112.                         b->~T();
  113.         }
  114.         void shrink(iterator b)
  115.         {
  116.                 destroy(b, end());
  117.                 m_count = std::distance(begin(), b);
  118.         }
  119. private:
  120.         union U {
  121.                 array_type m_data;
  122.                 U() {}
  123.         } u;
  124.         array_type &arrayref() { return u.m_data; }
  125.         const array_type &arrayref() const { return u.m_data; }
  126. };
  127.