12 namespace flag_group {
15 * @brief 型がFlagGroupクラスで使用するフラグを指すイテレータであることを表すコンセプト
17 * Iter の型が以下の要件を満たすことを表す
20 * - そのイテレータが指す要素の型が FlagType である
22 template <typename Iter, typename FlagType>
23 concept FlagIter = std::input_iterator<Iter> && std::same_as<std::iter_value_t<Iter>, FlagType>;
27 namespace flag_group::detail {
29 template <typename Func, size_t BITSET_SIZE>
30 void read_bitset(std::bitset<BITSET_SIZE> &bs, Func rd_byte_func, size_t count)
32 for (auto i = 0U; i < count; i++) {
33 const std::bitset<8> rd_byte_bs(rd_byte_func());
35 for (auto j = 0U; j < 8; j++) {
36 const size_t pos = i * 8 + j;
37 if (pos >= bs.size()) {
41 bs[pos] = rd_byte_bs[j];
46 template <typename Func, size_t BITSET_SIZE>
47 void write_bitset(const std::bitset<BITSET_SIZE> &bs, Func wr_byte_func, size_t count)
49 for (auto i = 0U; i < count; i++) {
50 std::bitset<8> wr_byte_bs;
52 for (auto j = 0U; j < 8; j++) {
53 const size_t pos = i * 8 + j;
54 if (pos >= bs.size()) {
58 wr_byte_bs[j] = bs[pos];
61 wr_byte_func(wr_byte_bs.to_ulong() & 0xff);
68 * @brief フラグ集合を扱う、FlagGroupクラス
70 * @tparam FlagType 扱うフラグ集合を定義したenum型 もしくは enum class型
71 * @tparam FlagTypeに列挙される値の最大値+1
73 template <typename FlagType, FlagType MAX>
77 static constexpr auto FLAG_TYPE_MAX = static_cast<size_t>(MAX);
80 using flag_type = FlagType;
83 * @brief フラグ集合に含まれるフラグの種類数を返す
85 * @return フラグ集合に含まれるフラグの種類数
87 [[nodiscard]] constexpr size_t size() const noexcept
93 * @brief FlagGroupクラスのデフォルトコンストラクタ
95 * すべてのフラグがOFFの状態のFlagGroupクラスのインスタンスを生成する
97 FlagGroup() = default;
100 * @brief FlagGroupクラスのコンストラクタ
102 * initializer_listで指定したフラグがON、それ以外はOFFの状態の
103 * FlagGroupクラスのインスタンスを生成する
105 * @param il ONの状態で生成するフラグを指定した initializer_list
107 FlagGroup(std::initializer_list<FlagType> il)
108 : FlagGroup(il.begin(), il.end())
113 * @brief FlagGroupクラスのコンストラクタ
115 * EnumRangeクラスで指定した範囲のフラグがON、それ以外はOFFの状態の
116 * FlagGroupクラスのインスタンスを生成する
118 * @param range 範囲を示すEnumRangeクラスのオブジェクト
120 FlagGroup(const EnumRange<FlagType> &range)
121 : FlagGroup(range.begin(), range.end())
126 * @brief FlagGroupクラスのコンストラクタ
128 * 入力イテレータで指定した範囲のリストに含まれるフラグがON、
129 * それ以外のフラグがOFFの状態のFlagGroupクラスのインスタンスを生成する
131 * @tparam InputIter 入力イテレータの型
132 * @param first 範囲の開始位置を示す入力イテレータ
133 * @param last 範囲の終了位置を示す入力イテレータ
135 template <flag_group::FlagIter<FlagType> InputIter>
136 FlagGroup(InputIter first, InputIter last)
138 for (; first != last; ++first) {
144 * @brief フラグ集合に含まれるフラグをすべてOFFにする
148 FlagGroup<FlagType, MAX> &clear() noexcept
155 * @brief 指定したフラグを指定した値にセットする
157 * @param flag 値をセットするフラグを指定する
158 * @param val セットする値。trueならフラグをON、falseならフラグをOFFにする。
159 * 引数を省略した場合はフラグをONにする。
162 FlagGroup<FlagType, MAX> &set(FlagType flag, bool val = true)
164 bs_.set(static_cast<size_t>(flag), val);
169 * @brief 入力イテレータで指定した範囲のリストに含まれるフラグをONにする
171 * @tparam InputIter 入力イテレータの型
172 * @param first 範囲の開始位置を示す入力イテレータ
173 * @param last 範囲の終了位置を示す入力イテレータ
176 template <flag_group::FlagIter<FlagType> InputIter>
177 FlagGroup<FlagType, MAX> &set(InputIter first, InputIter last)
179 return set(FlagGroup(first, last));
183 * @brief 指定したFlagGroupのインスンタンスのONになっているフラグをONにする
185 * @param rhs ONにするフラグがONになっているFlagGroupのインスタンス
188 FlagGroup<FlagType, MAX> &set(const FlagGroup<FlagType, MAX> &rhs)
195 * @brief 指定したフラグをOFFにする
197 * @param flag OFFにするフラグを指定する
200 FlagGroup<FlagType, MAX> &reset(FlagType flag)
202 bs_.reset(static_cast<size_t>(flag));
207 * @brief 入力イテレータで指定した範囲のリストに含まれるフラグをOFFにする
209 * @tparam InputIter 入力イテレータの型
210 * @param first 範囲の開始位置を示す入力イテレータ
211 * @param last 範囲の終了位置を示す入力イテレータ
214 template <flag_group::FlagIter<FlagType> InputIter>
215 FlagGroup<FlagType, MAX> &reset(InputIter first, InputIter last)
217 return reset(FlagGroup(first, last));
221 * @brief 指定したFlagGroupのインスンタンスのONになっているフラグをOFFにする
223 * @param rhs OFFにするフラグがONになっているFlagGroupのインスタンス
226 FlagGroup<FlagType, MAX> &reset(const FlagGroup<FlagType, MAX> &rhs)
233 * @brief 指定したフラグがONかOFFか調べる
235 * @param f 調べるフラグを指定する
236 * @return 指定したフラグがONならtrue、OFFならfalse
238 [[nodiscard]] bool has(FlagType f) const
241 // どのフラグにも該当しないFlagTypeの型としてMAXを指定する事があるため、MAXが指定された時はfalseを返すようにする
244 return bs_.test(static_cast<size_t>(f));
248 * @brief 指定したフラグがOFFかONか調べる
250 * @param f 調べるフラグを指定する
251 * @return 指定したフラグがOFFならtrue、ONならfalse
253 [[nodiscard]] bool has_not(FlagType f) const
259 * @brief フラグ集合のいずれかのフラグがONかどうかを調べる
261 * @return フラグ集合のいずれかのフラグがONならtrue
262 * フラグ集合のすべてのフラグがOFFならfalse
264 [[nodiscard]] bool any() const noexcept
270 * @brief フラグ集合のすべてのフラグがOFFかどうかを調べる
272 * @return フラグ集合のすべてのフラグがOFFならtrue
273 * フラグ集合のいずれかのフラグがONならfalse
275 [[nodiscard]] bool none() const noexcept
281 * @brief 入力イテレータで指定した範囲のリストに含まれるフラグがすべてONかどうかを調べる
283 * @tparam InputIter 入力イテレータの型
284 * @param first 範囲の開始位置を示す入力イテレータ
285 * @param last 範囲の終了位置を示す入力イテレータ
286 * @return すべてのフラグがONであればtrue、そうでなければfalse
288 template <flag_group::FlagIter<FlagType> InputIter>
289 [[nodiscard]] bool has_all_of(InputIter first, InputIter last) const
291 return has_all_of(FlagGroup(first, last));
295 * @brief 引数で指定したFlagGroupのインスンタンスのONになっているフラグがすべてONかどうかを調べる
297 * @param rhs FlagGroupのインスタンス
298 * @return すべてのフラグがONであればtrue、そうでなければfalse
300 [[nodiscard]] bool has_all_of(const FlagGroup<FlagType, MAX> &rhs) const
302 return (bs_ & rhs.bs_) == rhs.bs_;
306 * @brief 入力イテレータで指定した範囲のリストに含まれるフラグのいずれかがONかどうかを調べる
308 * @tparam InputIter 入力イテレータの型
309 * @param first 範囲の開始位置を示す入力イテレータ
310 * @param last 範囲の終了位置を示す入力イテレータ
311 * @return いずれかのフラグがONであればtrue、そうでなければfalse
313 template <flag_group::FlagIter<FlagType> InputIter>
314 [[nodiscard]] bool has_any_of(InputIter first, InputIter last) const
316 return has_any_of(FlagGroup(first, last));
320 * @brief 引数で指定したFlagGroupのインスンタンスのONになっているフラグのいずれかがONかどうかを調べる
322 * @param rhs FlagGroupのインスタンス
323 * @return いずれかのフラグがONであればtrue、そうでなければfalse
325 [[nodiscard]] bool has_any_of(const FlagGroup<FlagType, MAX> &rhs) const
327 return (bs_ & rhs.bs_).any();
331 * @brief 入力イテレータで指定した範囲のリストに含まれるフラグがすべてOFFかどうかを調べる
333 * @tparam InputIter 入力イテレータの型
334 * @param first 範囲の開始位置を示す入力イテレータ
335 * @param last 範囲の終了位置を示す入力イテレータ
336 * @return すべてのフラグがOFFであればtrue、そうでなければfalse
338 template <flag_group::FlagIter<FlagType> InputIter>
339 [[nodiscard]] bool has_none_of(InputIter first, InputIter last) const
341 return !has_any_of(first, last);
345 * @brief 引数で指定したFlagGroupのインスンタンスのONになっているフラグがすべてOFFかどうかを調べる
347 * @param rhs FlagGroupのインスタンス
348 * @return すべてのフラグがOFFであればtrue、そうでなければfalse
350 [[nodiscard]] bool has_none_of(const FlagGroup<FlagType, MAX> &rhs) const
352 return !has_any_of(rhs);
356 * @brief フラグ集合のONになっているフラグの数を返す
358 * @return ONになっているフラグの数
360 [[nodiscard]] size_t count() const noexcept
366 * @brief フラグ集合のONになっているフラグのうち最初のフラグを返す
368 * @return フラグ集合のONになっているフラグのうち最初のフラグ。但し一つもONになっているフラグがなければ std::nullopt
370 [[nodiscard]] std::optional<FlagType> first() const noexcept
372 for (size_t i = 0; i < bs_.size(); i++) {
374 return static_cast<FlagType>(i);
382 * @brief フラグ集合の状態を0と1で表した文字列を返す
384 * フラグ集合の上位番号から順に、フラグがONなら1、OFFなら0で表した文字列を返す。
385 * 例: 5つのフラグ集合で、0:ON、1:OFF、2:OFF、3:ON、4:OFFの場合、"01001"
387 * @return フラグ集合の状態を表した文字列
389 [[nodiscard]] std::string str() const
391 return bs_.to_string();
395 * @brief フラグ集合の状態を表したビット列を unsigned long 型にして返す
397 * @return フラグ集合の状態を表したビット列
399 [[nodiscard]] unsigned long to_ulong() const
401 return bs_.to_ulong();
405 * @brief フラグ集合の状態を表したビット列を unsigned long long 型にして返す
407 * @return フラグ集合の状態を表したビット列
409 [[nodiscard]] unsigned long long to_ullong() const
411 return bs_.to_ullong();
415 * @brief フラグ集合 *this と rhs が等値かどうかを調べる
417 * @param rhs 比較するフラグ集合
418 * @return すべてのフラグの状態が等しければtrue、そうでなければfalse
420 [[nodiscard]] bool operator==(const FlagGroup<FlagType, MAX> &rhs) const noexcept
422 return bs_ == rhs.bs_;
426 * @brief フラグ集合 *this と rhs が非等値かどうかを調べる
428 * @param rhs 比較するフラグ集合
429 * @return いずれかのフラグの状態が等しくなければtrue、そうでなければfalse
431 [[nodiscard]] bool operator!=(const FlagGroup<FlagType, MAX> &rhs) const noexcept
433 return bs_ != rhs.bs_;
437 * @brief フラグ集合 *this と rhs の論理積(AND)の複合演算を行う
439 * *this に対して、*this と rhs で共通してONのフラグをONのままにし、それ以外のフラグをOFFにする
441 * @param rhs 複合演算を行うフラグ集合
444 FlagGroup<FlagType, MAX> &operator&=(const FlagGroup<FlagType, MAX> &rhs) noexcept
451 * @brief フラグ集合 *this と rhs の論理和(OR)の複合演算を行う
453 * *this に対して、*this と rhs でどちらか一方でもONのフラグをONにし、それ以外のフラグをOFFにする
455 * @param rhs 複合演算を行うフラグ集合
458 FlagGroup<FlagType, MAX> &operator|=(const FlagGroup<FlagType, MAX> &rhs) noexcept
465 * @brief フラグ集合のONになっているフラグを出力イテレータに書き込む
467 * @tparam OutputIter フラグを書き込む出力イテレータの型
468 * @param flag_group 対象のフラグ集合
469 * @param start フラグを書き込む出力イテレータ
471 template <typename OutputIter>
472 static void get_flags(const FlagGroup<FlagType, MAX> &flag_group, OutputIter start)
474 for (size_t i = 0; i < flag_group.size(); i++) {
475 if (flag_group.bs_.test(i)) {
476 *start++ = static_cast<FlagType>(i);
482 * @brief セーブファイルからフラグ集合を読み出す
484 * @param fg 読み出したフラグ集合を格納するFlagGroupインスタンスの参照
485 * @param rd_byte_func セーブファイルから1バイトデータを読み出す関数(rd_byte)へのポインタ
487 template <typename Func>
488 friend void rd_FlagGroup(FlagGroup<FlagType, MAX> &fg, Func rd_byte_func)
490 auto tmp_l = rd_byte_func();
491 auto tmp_h = rd_byte_func();
492 const auto fg_size = static_cast<uint16_t>((tmp_h << 8) | tmp_l);
494 flag_group::detail::read_bitset(fg.bs_, rd_byte_func, fg_size);
498 * @brief セーブファイルにフラグ集合を書き込む
500 * @param fg 書き込むフラグ集合を保持したFlagGroupインスタンスの参照
501 * @param wr_byte_func セーブファイルに1バイトデータを書き込む関数(wr_byte)へのポインタ
503 template <typename Func>
504 friend void wr_FlagGroup(const FlagGroup<FlagType, MAX> &fg, Func wr_byte_func)
506 const auto fg_size = static_cast<uint16_t>((fg.bs_.size() + 7) / 8);
507 wr_byte_func(fg_size & 0xff);
508 wr_byte_func((fg_size >> 8) & 0xff);
510 flag_group::detail::write_bitset(fg.bs_, wr_byte_func, fg_size);
514 * @brief セーブファイルから固定バイト長でフラグ集合を読み出す
516 * @param fg 読み出したフラグ集合を格納するFlagGroupインスタンスの参照
517 * @param rd_byte_func セーブファイルから1バイトデータを読み出す関数(rd_byte)へのポインタ
518 * @param count 読み出すバイト数
520 template <typename Func>
521 friend void rd_FlagGroup_bytes(FlagGroup<FlagType, MAX> &fg, Func rd_byte_func, size_t count)
523 flag_group::detail::read_bitset(fg.bs_, rd_byte_func, count);
527 * @brief セーブファイルに固定バイト長でフラグ集合を書き込む
529 * @param fg 書き込むフラグ集合を保持したFlagGroupインスタンスの参照
530 * @param wr_byte_func セーブファイルに1バイトデータを書き込む関数(wr_byte)へのポインタ
531 * @param count 書き込むバイト数
533 template <typename Func>
534 friend void wr_FlagGroup_bytes(const FlagGroup<FlagType, MAX> &fg, Func wr_byte_func, size_t count)
536 flag_group::detail::write_bitset(fg.bs_, wr_byte_func, count);
540 * @brief 文字列からフラグへのマップを指定した検索キーで検索し、
541 * 見つかった場合はフラグ集合に該当するフラグをセットする
543 * @tparam Map std::map<string_view, FlagType> もしくは std::unordered_map<string_view, FlagType>
544 * @param fg フラグをセットするフラグ集合
545 * @param dict 文字列からフラグへのマップ
546 * @param what マップの検索キー
547 * @return 検索キーでフラグが見つかり、フラグをセットした場合 true
550 template <typename Map>
551 static bool grab_one_flag(FlagGroup<FlagType, MAX> &fg, const Map &dict, std::string_view what)
553 auto it = dict.find(what);
554 if (it == dict.end()) {
564 * @brief 指定したフラグ位置へのアクセスを提供するプロキシクラス
568 reference(std::bitset<FLAG_TYPE_MAX> &flags, size_t pos)
574 reference &operator=(const reference &rhs)
576 bs_[pos_] = static_cast<bool>(rhs);
580 reference &operator=(bool val)
586 [[nodiscard]] operator bool() const
592 std::bitset<FLAG_TYPE_MAX> &bs_;
598 * @brief 指定したフラグへのアクセスを提供するプロキシオブジェクトを取得する
600 * @param f プロキシオブジェクトを取得するフラグ
601 * @return 指定したフラグへのアクセスを提供するプロキシオブジェクト
603 [[nodiscard]] reference operator[](FlagType f)
605 return reference(bs_, static_cast<size_t>(f));
609 /** フラグ集合を保持するstd::bitsetのインスタンス */
610 std::bitset<FLAG_TYPE_MAX> bs_;
614 * @brief enum clsas 型に対してFlagGroupクラスを使用するエイリアステンプレート
616 * FlagGroupクラスのテンプレート引数に、使用する型として FlagType、列挙値の最大値として FlagType::MAX を渡す。
618 * @tparam FlagType FlagGroupクラスを使用する enum class 型
620 template <typename FlagType>
621 using EnumClassFlagGroup = FlagGroup<FlagType, FlagType::MAX>;
624 * @brief フラグ集合 lhs と rhs に対して論理積(AND)を取ったフラグ集合を生成する
626 * lhs と rhs で共通してONのフラグがON、それ以外のフラグがOFFのフラグ集合を生成する
628 * @tparam FlagType 扱うフラグ集合を定義したenum class型
631 * @return lhs と rhs の論理積を取ったフラグ集合
633 template <typename FlagType, FlagType MAX>
634 [[nodiscard]] FlagGroup<FlagType, MAX> operator&(const FlagGroup<FlagType, MAX> &lhs, const FlagGroup<FlagType, MAX> &rhs) noexcept
636 return FlagGroup<FlagType, MAX>(lhs) &= rhs;
640 * @brief フラグ集合 lhs と rhs に対して論理和(OR)を取ったフラグ集合を生成する
642 * lhs と rhs でどちらか一方でもONのフラグがON、それ以外のフラグがOFFのフラグ集合を生成する
644 * @tparam FlagType 扱うフラグ集合を定義したenum class型
647 * @return lhs と rhs の論理積を取ったフラグ集合
649 template <typename FlagType, FlagType MAX>
650 [[nodiscard]] FlagGroup<FlagType, MAX> operator|(const FlagGroup<FlagType, MAX> &lhs, const FlagGroup<FlagType, MAX> &rhs) noexcept
652 return FlagGroup<FlagType, MAX>(lhs) |= rhs;