OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / util / enum-range.h
1 #pragma once
2
3 #include <iterator>
4 #include <type_traits>
5
6 /*!
7  * @brief enum もしくは enum class の列挙値の範囲を扱うクラス
8  *
9  * @tparam EnumType 対象となる列挙型(enum もしくは enum class)
10  */
11 template <typename EnumType>
12 class EnumRange {
13     static_assert(std::is_enum_v<EnumType>);
14
15 public:
16     /*!
17      * @brief 列挙値の範囲のイテレータクラス
18      */
19     class iterator {
20     public:
21         // std::iterator_traits に対応するための定義
22         using difference_type = int;
23         using value_type = EnumType;
24         using iterator_concept = std::input_iterator_tag;
25
26         /*!
27          * @brief 引数で与えた列挙値を指すイテレータオブジェクトを生成する
28          *
29          * @param val イテレータオブジェクトが指す列挙値
30          */
31         constexpr iterator(EnumType val) noexcept
32             : index(std::underlying_type_t<EnumType>(val))
33         {
34         }
35
36         /*!
37          * @brief イテレータが指している列挙値を取得する
38          *
39          * @return イテレータが指している列挙値
40          */
41         constexpr EnumType operator*() const noexcept
42         {
43             return static_cast<EnumType>(index);
44         }
45
46         /*!
47          * @brief イテレータを前置インクリメントする
48          *
49          * @return *this の参照
50          */
51         constexpr iterator &operator++() noexcept
52         {
53             ++index;
54             return *this;
55         }
56
57         /*!
58          * @brief イテレータを後置インクリメントする
59          *
60          * @return *this の参照
61          */
62         constexpr iterator operator++(int) noexcept
63         {
64             auto old = *this;
65             ++*this;
66             return old;
67         }
68
69         /*!
70          * @brief 2つのイテレータが指している列挙値が等しいかどうか調べる
71          *
72          * @param other 比較対象となるイテレータ
73          * @return 2つのイテレータが指している列挙値が等しければ true、そうでなければ false
74          */
75         constexpr bool operator==(const iterator &other) const noexcept
76         {
77             return index == other.index;
78         }
79
80     private:
81         //! 現在イテレータが指している列挙値の基底型における整数値
82         std::underlying_type_t<EnumType> index;
83     };
84
85     /*!
86      * @brief 引数で与えた範囲の EnumRange クラスのオブジェクトを生成する
87      * @details 生成する範囲はfirstからlastまで(lastを含む)。
88      * 範囲の最終値+1の列挙値が存在しない場合を考慮し、半開区間ではなく閉区間で範囲を指定する。
89      * 範囲のイテレーションは基底型の整数値をインクリメントする事によって行うので、
90      * first から last までの間の整数値が飛んでいる場合、その部分は具体的な定義の無い列挙値がイテレートされる。
91      * @param first 範囲の最初となる列挙値
92      * @param last 範囲の最後となる列挙値(lastも含む)
93      */
94     constexpr EnumRange(EnumType first, EnumType last) noexcept
95         : begin_val(first)
96         , end_val(static_cast<EnumType>(std::underlying_type_t<EnumType>(last) + 1))
97     {
98     }
99
100     /*!
101      * @brief 範囲の最初の列挙値を指すイテレータを取得する
102      *
103      * @return 範囲の最初の列挙値を指すイテレータ
104      */
105     constexpr iterator begin() const noexcept
106     {
107         return iterator(begin_val);
108     }
109
110     /*!
111      * @brief 範囲の最後の列挙値の次の値を指すイテレータを取得する
112      *
113      * @return 範囲の最後の列挙値の次の値を指すイテレータ
114      */
115     constexpr iterator end() const noexcept
116     {
117         return iterator(end_val);
118     }
119
120     /*!
121      * @brief 範囲に含まれる列挙値の種類数を取得する
122      *
123      * @return 範囲に含まれる列挙値の種類数
124      */
125     constexpr std::size_t size() const noexcept
126     {
127         return static_cast<std::size_t>(end_val) - static_cast<std::size_t>(begin_val);
128     }
129
130 private:
131     EnumType begin_val;
132     EnumType end_val;
133 };