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 <inttypes.h>
  10. #include <iterator>
  11. #include "dxxsconf.h"
  12. #include "partial_range.h"
  13. #include "ephemeral_range.h"
  14. #include <tuple>
  15. #include <type_traits>
  16.  
  17. /*
  18.  * This could have been done using a std::pair, but using a custom type
  19.  * allows for more descriptive member names.
  20.  */
  21. template <typename range_value_type, typename index_type>
  22. struct enumerated_value
  23. {
  24.         range_value_type value;
  25.         const index_type idx;
  26. };
  27.  
  28. namespace d_enumerate {
  29.  
  30. namespace detail {
  31.  
  32. template <typename result_type, typename index_type>
  33. struct adjust_iterator_dereference_type : std::false_type
  34. {
  35.         using value_type = enumerated_value<result_type, index_type>;
  36. };
  37.  
  38. template <typename... T, typename index_type>
  39. struct adjust_iterator_dereference_type<std::tuple<T...>, index_type> : std::true_type
  40. {
  41.         using value_type = std::tuple<index_type, T...>;
  42. };
  43.  
  44. }
  45.  
  46. }
  47.  
  48. template <typename range_iterator_type, typename index_type, typename iterator_dereference_type>
  49. class enumerated_iterator
  50. {
  51.         range_iterator_type m_iter;
  52.         index_type m_idx;
  53.         using adjust_iterator_dereference_type = d_enumerate::detail::adjust_iterator_dereference_type<typename std::remove_cv<iterator_dereference_type>::type, index_type>;
  54. public:
  55.         using iterator_category = std::forward_iterator_tag;
  56.         using value_type = typename adjust_iterator_dereference_type::value_type;
  57.         using difference_type = std::ptrdiff_t;
  58.         using pointer = value_type *;
  59.         using reference = value_type &;
  60.         enumerated_iterator(const range_iterator_type &iter, const index_type idx) :
  61.                 m_iter(iter), m_idx(idx)
  62.         {
  63.         }
  64.         value_type operator*() const
  65.         {
  66.                 if constexpr (adjust_iterator_dereference_type::value)
  67.                         return std::tuple_cat(std::tuple<index_type>(m_idx), *m_iter);
  68.                 else
  69.                         return {*m_iter, m_idx};
  70.         }
  71.         enumerated_iterator &operator++()
  72.         {
  73.                 ++ m_iter;
  74.                 ++ m_idx;
  75.                 return *this;
  76.         }
  77.         bool operator!=(const enumerated_iterator &i) const
  78.         {
  79.                 return m_iter != i.m_iter;
  80.         }
  81.         bool operator==(const enumerated_iterator &i) const
  82.         {
  83.                 return m_iter == i.m_iter;
  84.         }
  85. };
  86.  
  87. template <typename range_iterator_type, typename index_type>
  88. class enumerate : partial_range_t<range_iterator_type>
  89. {
  90.         using base_type = partial_range_t<range_iterator_type>;
  91.         using iterator_dereference_type = decltype(*std::declval<range_iterator_type>());
  92.         using enumerated_iterator_type = enumerated_iterator<
  93.                 range_iterator_type,
  94.                 index_type,
  95.                 iterator_dereference_type>;
  96.         const index_type m_idx;
  97. public:
  98.         using range_owns_iterated_storage = std::false_type;
  99.         enumerate(const range_iterator_type b, const range_iterator_type e, const index_type i) :
  100.                 base_type(b, e), m_idx(i)
  101.         {
  102.         }
  103.         template <typename range_type>
  104.                 enumerate(range_type &&t, const index_type i = 0) :
  105.                         base_type(t), m_idx(i)
  106.         {
  107.                 static_assert(!any_ephemeral_range<range_type &&>::value, "cannot enumerate storage of ephemeral ranges");
  108.                 static_assert(std::is_rvalue_reference<range_type &&>::value || std::is_lvalue_reference<iterator_dereference_type>::value, "lvalue range must produce lvalue reference enumerated_value");
  109.         }
  110.         enumerated_iterator_type begin() const
  111.         {
  112.                 return enumerated_iterator_type(this->base_type::begin(), m_idx);
  113.         }
  114.         enumerated_iterator_type end() const
  115.         {
  116.                 return enumerated_iterator_type(this->base_type::end(), 0 /* unused */);
  117.         }
  118. };
  119.  
  120. template <typename range_type, typename index_type = uint_fast32_t, typename range_iterator_type = decltype(std::begin(std::declval<range_type &>()))>
  121. enumerate(range_type &&r, const index_type start = index_type(/* value ignored */)) -> enumerate<range_iterator_type, index_type>;
  122.