basedOpinionated utility library | 
          
| git clone git://git.dimitrijedobrota.com/based.git | 
| Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING | 
list.hpp (5680B)
    0 #pragma once
          
              2 #include <cassert>
              3 #include <vector>
          
              5 #include "based/concepts/is/same.hpp"
              6 #include "based/types/types.hpp"
          
              8 namespace based
              9 {
          
             11 template<typename T, typename N>
             12 // T semiregular
             13 // N integral
             14 class list_pool
             15 {
             16 public:
             17   using value_type = T;
             18   using list_type = N;
          
             20 private:
             21   struct node_t
             22   {
             23     value_type value {};
             24     list_type next;
             25   };
          
             27   std::vector<node_t> m_pool;
             28   list_type m_free_list;
          
             30   [[nodiscard]] const node_t& node(list_type x) const
             31   {
             32     assert(x != list_type(0));
             33     return m_pool[(x - list_type(1)).value];
             34   }
          
             36   [[nodiscard]] node_t& node(list_type x)
             37   {
             38     assert(x != list_type(0));
             39     return m_pool[(x - list_type(1)).value];
             40   }
          
             42   [[nodiscard]] list_type new_node()
             43   {
             44     m_pool.push_back(node_t());
             45     return list_type {static_cast<list_type::basic_type>(m_pool.size())};
             46   }
          
             48 public:
             49   list_pool()
             50       : m_free_list(node_empty())
             51   {
             52   }
          
             54   struct iterator
             55   {
             56     using iterator_category = std::forward_iterator_tag;
             57     using difference_type = list_pool::list_type;
             58     using value_type = list_pool::value_type;
             59     using reference = value_type&;
             60     using pointer = value_type*;
          
             62     iterator() = default;
          
             64     explicit iterator(list_pool& pool)
             65         : iterator(pool, pool.node_empty())
             66     {
             67     }
          
             69     iterator(list_pool& pool, list_pool::list_type node)
             70         : m_pool(&pool)
             71         , m_node(node)
             72     {
             73     }
          
             75     reference operator*() const { return m_pool->value(m_node); }
             76     pointer operator->() const { return &**this; }
          
             78     iterator& operator++()
             79     {
             80       m_node = m_pool->next(m_node);
             81       return *this;
             82     }
          
             84     iterator operator++(int)
             85     {
             86       iterator tmp(*this);
             87       ++*this;
             88       return tmp;
             89     }
          
             91     friend bool operator==(const iterator& x, const iterator& y)
             92     {
             93       assert(x.m_pool == y.m_pool);
             94       return x.m_node == y.m_node;
             95     }
          
             97     friend bool operator!=(const iterator& x, const iterator& y)
             98     {
             99       return !(x == y);
            100     }
          
            102   private:
            103     list_pool* m_pool;
            104     list_pool::list_type m_node;
            105   };
          
            107   struct const_iterator
            108   {
            109     using iterator_category = std::forward_iterator_tag;
            110     using difference_type = list_pool::list_type;
            111     using value_type = list_pool::value_type;
            112     using reference = const value_type&;
            113     using pointer = const value_type*;
          
            115     const_iterator() = default;
          
            117     explicit const_iterator(const list_pool& pool)
            118         : const_iterator(pool, pool.node_empty())
            119     {
            120     }
          
            122     const_iterator(const list_pool& pool, list_pool::list_type node)
            123         : m_pool(&pool)
            124         , m_node(node)
            125     {
            126     }
          
            128     reference operator*() const { return m_pool->value(m_node); }
            129     pointer operator->() const { return &**this; }
          
            131     const_iterator& operator++()
            132     {
            133       m_node = m_pool->next(m_node);
            134       return *this;
            135     }
          
            137     const_iterator operator++(int)
            138     {
            139       const_iterator tmp(*this);
            140       ++*this;
            141       return tmp;
            142     }
          
            144     friend bool operator==(const const_iterator& x, const const_iterator& y)
            145     {
            146       assert(x.m_pool == y.m_pool);
            147       return x.m_node == y.m_node;
            148     }
          
            150     friend bool operator!=(const const_iterator& x, const const_iterator& y)
            151     {
            152       return !(x == y);
            153     }
          
            155   private:
            156     const list_pool* m_pool;
            157     list_pool::list_type m_node;
            158   };
          
            160   [[nodiscard]] bool is_empty(list_type x) const { return x == node_empty(); }
            161   [[nodiscard]] list_type node_empty() const { return list_type(0); }
          
            163   [[nodiscard]] const value_type& value(list_type x) const
            164   {
            165     return node(x).value;
            166   }
            167   [[nodiscard]] value_type& value(list_type x) { return node(x).value; }
          
            169   [[nodiscard]] const list_type& next(list_type x) const
            170   {
            171     return node(x).next;
            172   }
            173   [[nodiscard]] list_type& next(list_type x) { return node(x).next; }
          
            175   list_type free(list_type x)
            176   {
            177     const list_type ret = next(x);
            178     next(x) = m_free_list;
            179     m_free_list = x;
            180     return ret;
            181   }
          
            183   list_type free(
            184       list_type front,  // NOLINT(*swappable*)
            185       list_type back
            186   )
            187   {
            188     if (is_empty(front)) {
            189       return node_empty();
            190     }
          
            192     const list_type ret = next(back);
            193     next(back) = m_free_list;
            194     m_free_list = front;
            195     return ret;
            196   }
          
            198   [[nodiscard]] list_type allocate(const value_type& val, list_type tail)
            199   {
            200     list_type new_list = m_free_list;
          
            202     if (is_empty(new_list)) {
            203       new_list = new_node();
            204     } else {
            205       m_free_list = next(m_free_list);
            206     }
          
            208     value(new_list) = val;
            209     next(new_list) = tail;
            210     return new_list;
            211   }
          
            213   using queue_t = std::pair<list_type, list_type>;
          
            215   [[nodiscard]] bool is_empty(const queue_t& queue) const
            216   {
            217     return is_empty(queue.first);
            218   }
            219   [[nodiscard]] queue_t queue_empty() { return {node_empty(), node_empty()}; }
          
            221   [[nodiscard]] queue_t push_front(const queue_t& queue, const value_type& val)
            222   {
            223     auto new_node = allocate(val, queue.first);
            224     if (is_empty(queue)) {
            225       return {new_node, new_node};
            226     }
            227     return {new_node, queue.second};
            228   }
          
            230   [[nodiscard]] queue_t push_back(const queue_t& queue, const value_type& val)
            231   {
            232     auto new_node = allocate(val, node_empty());
            233     if (is_empty(queue)) {
            234       return {new_node, new_node};
            235     }
            236     next(queue.second) = new_node;
            237     return {queue.first, new_node};
            238   }
          
            240   [[nodiscard]] queue_t pop_front(const queue_t& queue)
            241   {
            242     if (is_empty(queue)) {
            243       return queue;
            244     }
            245     queue_t ret = {next(queue.first), queue.second};
            246     free(queue.first);
            247     return ret;
            248   }
          
            250   void free(const queue_t& queue) { free(queue.first, queue.second); }
            251 };
          
            253 template<typename T, typename N>
            254 void free_list(list_pool<T, N>& pool, typename list_pool<T, N>::list_type x)
            255 {
            256   while (!pool.is_empty(x)) {
            257     x = pool.free(x);
            258   }
            259 }
          
            261 }  // namespace based