OSDN Git Service

Merge pull request #2162 from Hourier/Define-ApplyMagicLite
[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 pointer = const EnumType *;
25         using reference = const EnumType &;
26         using iterator_category = std::input_iterator_tag;
27
28         /*!
29          * @brief 引数で与えた列挙値を指すイテレータオブジェクトを生成する
30          *
31          * @param val イテレータオブジェクトが指す列挙値
32          */
33         constexpr iterator(EnumType val) noexcept
34             : index(std::underlying_type_t<EnumType>(val))
35         {
36         }
37
38         /*!
39          * @brief イテレータが指している列挙値を取得する
40          *
41          * @return イテレータが指している列挙値
42          */
43         constexpr EnumType operator*() const noexcept
44         {
45             return static_cast<EnumType>(index);
46         }
47
48         /*!
49          * @brief イテレータをインクリメントする
50          *
51          * @return *this の参照
52          */
53         iterator &operator++() noexcept
54         {
55             ++index;
56             return *this;
57         }
58
59         /*!
60          * @brief 2つのイテレータが指している列挙値が等しいかどうか調べる
61          *
62          * @param other 比較対象となるイテレータ
63          * @return 2つのイテレータが指している列挙値が等しければ true、そうでなければ false
64          */
65         constexpr bool operator==(const iterator &other) const noexcept
66         {
67             return index == other.index;
68         }
69
70         /*!
71          * @brief 2つのイテレータが指している列挙値が等しくないかどうか調べる
72          *
73          * @param other 比較対象となるイテレータ
74          * @return 2つのイテレータが指している列挙値が等しくなければ true、そうでなければ false
75          */
76         constexpr bool operator!=(const iterator &other) const noexcept
77         {
78             return !this->operator==(other);
79         }
80
81     private:
82         //! 現在イテレータが指している列挙値の基底型における整数値
83         std::underlying_type_t<EnumType> index;
84     };
85
86     /*!
87      * @brief 引数で与えた範囲の EnumRange クラスのオブジェクトを生成する
88      * @details 生成する範囲はfirstからlastまで(lastを含む)。
89      * 範囲の最終値+1の列挙値が存在しない場合を考慮し、半開区間ではなく閉区間で範囲を指定する。
90      * 範囲のイテレーションは基底型の整数値をインクリメントする事によって行うので、
91      * first から last までの間の整数値が飛んでいる場合、その部分は具体的な定義の無い列挙値がイテレートされる。
92      * @param first 範囲の最初となる列挙値
93      * @param last 範囲の最後となる列挙値(lastも含む)
94      */
95     constexpr EnumRange(EnumType first, EnumType last) noexcept
96         : begin_val(first)
97         , end_val(static_cast<EnumType>(std::underlying_type_t<EnumType>(last) + 1))
98     {
99     }
100
101     /*!
102      * @brief 範囲の最初の列挙値を指すイテレータを取得する
103      *
104      * @return 範囲の最初の列挙値を指すイテレータ
105      */
106     constexpr iterator begin() const noexcept
107     {
108         return iterator(begin_val);
109     }
110
111     /*!
112      * @brief 範囲の最後の列挙値の次の値を指すイテレータを取得する
113      *
114      * @return 範囲の最後の列挙値の次の値を指すイテレータ
115      */
116     constexpr iterator end() const noexcept
117     {
118         return iterator(end_val);
119     }
120
121     /*!
122      * @brief 範囲に含まれる列挙値の種類数を取得する
123      *
124      * @return 範囲に含まれる列挙値の種類数
125      */
126     constexpr std::size_t size() const noexcept
127     {
128         return static_cast<std::size_t>(end_val) - static_cast<std::size_t>(begin_val);
129     }
130
131 private:
132     EnumType begin_val;
133     EnumType end_val;
134 };