Add FlagSet<E,N> for wrapping a bitset of enum values
MODIFY
CMakeLists.txt
CMakeLists.txt
@@ -41,6 +41,7 @@ add_library(lcf
src/ini.h
src/inireader.cpp
src/inireader.h
+ src/flag_set.h
src/lcf_options.h
src/lcf_saveopt.h
src/ldb_equipment.cpp

MODIFY
Makefile.am
Makefile.am
@@ -123,6 +123,7 @@ pkginclude_HEADERS = \
src/data.h \
src/encoder.h \
src/enum_tags.h \
+ src/flag_set.h \
src/ini.h \
src/inireader.h \
src/lcf_options.h \
@@ -217,6 +218,7 @@ check_PROGRAMS = test_runner
test_runner_SOURCES = \
tests/doctest.h \
tests/time_stamp.cpp \
+ tests/flag_set.cpp \
tests/test_main.cpp
test_runner_CPPFLAGS = \
-I$(srcdir)/src \

ADD
src/flag_set.h
+/*
+ * This file is part of liblcf. Copyright (c) 2019 liblcf authors.
+ * https://github.com/EasyRPG/liblcf - https://easyrpg.org
+ *
+ * liblcf is Free/Libre Open Source Software, released under the MIT License.
+ * For the full copyright and license information, please view the COPYING
+ * file that was distributed with this source code.
+ */
+
+#ifndef LCF_FLAG_SET_H
+#define LCF_FLAG_SET_H
+
+#include <bitset>
+
+template <typename E, size_t N=32>
+class FlagSet {
+ public:
+ using underlying = std::bitset<N>;
+ using reference = typename underlying::reference;
+
+ constexpr FlagSet() = default;
+ FlagSet(std::initializer_list<E> ilist);
+
+ constexpr bool operator[](E tag) const { return _bits[size_t(tag)]; }
+ reference operator[](E tag) { return _bits[size_t(tag)]; }
+
+ size_t count() const { return _bits.count(); }
+ size_t size() const { return _bits.size(); }
+
+ FlagSet& operator&=(const FlagSet& o) { _bits &= o._bits; return *this; }
+ FlagSet& operator|=(const FlagSet& o) { _bits |= o._bits; return *this; }
+ FlagSet& operator^=(const FlagSet& o) { _bits ^= o._bits; return *this; }
+
+ template <typename EE, size_t NN>
+ friend bool operator==(const FlagSet<EE,NN>& l, const FlagSet<EE,NN>& r);
+
+ friend struct std::hash<FlagSet<E,N>>;
+ private:
+ std::bitset<N> _bits = {};
+};
+
+template <typename E, size_t N>
+inline bool operator==(const FlagSet<E,N>& l, const FlagSet<E,N>& r) {
+ return l._bits == r._bits;
+}
+
+template <typename E, size_t N>
+inline bool operator!=(const FlagSet<E,N>& l, const FlagSet<E,N>& r) {
+ return !(l == r);
+}
+
+template <typename E, size_t N>
+inline FlagSet<E,N> operator&(const FlagSet<E,N>& l, const FlagSet<E,N>& r) {
+ auto copy = l;
+ copy &= r;
+ return copy;
+}
+
+template <typename E, size_t N>
+inline FlagSet<E,N> operator|(const FlagSet<E,N>& l, const FlagSet<E,N>& r) {
+ auto copy = l;
+ copy |= r;
+ return copy;
+}
+
+template <typename E, size_t N>
+inline FlagSet<E,N> operator^(const FlagSet<E,N>& l, const FlagSet<E,N>& r) {
+ auto copy = l;
+ copy ^= r;
+ return copy;
+}
+
+template <typename E, size_t N>
+inline FlagSet<E,N>::FlagSet(std::initializer_list<E> ilist) {
+ for (auto&& tag: ilist) {
+ _bits.set(tag);
+ }
+}
+
+namespace std {
+template <typename E, size_t N>
+ struct hash<FlagSet<E,N>> {
+ size_t operator()(const FlagSet<E,N>& fs) {
+ return hash<typename FlagSet<E,N>::underlying>()(fs._bits);
+ }
+ };
+}
+
+
+
+#endif

ADD
tests/flag_set.cpp
+/*
+ * This file is part of liblcf. Copyright (c) 2018 liblcf authors.
+ * https://github.com/EasyRPG/liblcf - https://easyrpg.org
+ *
+ * liblcf is Free/Libre Open Source Software, released under the MIT License.
+ * For the full copyright and license information, please view the COPYING
+ * file that was distributed with this source code.
+ */
+
+#include "flag_set.h"
+#include "doctest.h"
+
+enum Color {
+ Red,
+ Green,
+ Blue
+};
+
+template class FlagSet<Color>;
+
+using ColorSet = FlagSet<Color>;
+
+TEST_SUITE_BEGIN("flag_set");
+
+TEST_CASE("Default Construct") {
+ ColorSet cs;
+ REQUIRE(!cs[Red]);
+ REQUIRE(!cs[Green]);
+ REQUIRE(!cs[Blue]);
+ REQUIRE_EQ(cs.count(), 0);
+}
+
+TEST_CASE("List Construct") {
+ ColorSet cs = { Red, Blue };
+ REQUIRE(cs[Red]);
+ REQUIRE(!cs[Green]);
+ REQUIRE(cs[Blue]);
+ REQUIRE_EQ(cs.count(), 2);
+
+ cs[Green] = true;
+ REQUIRE(cs[Green]);
+ REQUIRE_EQ(cs.count(), 3);
+
+ cs[Red] = false;
+ REQUIRE(!cs[Red]);
+ REQUIRE_EQ(cs.count(), 2);
+}
+
+TEST_CASE("Logical Ops") {
+ ColorSet cs0 = {};
+ ColorSet csr = { Red };
+ ColorSet csg = { Green };
+ ColorSet csb = { Blue };
+
+ ColorSet csrg = { Red, Green };
+ ColorSet csrb = { Red, Blue };
+ ColorSet csgb = { Green, Blue };
+ ColorSet csrgb = { Red, Green, Blue };
+
+ REQUIRE(cs0 == (csr & csg));
+ REQUIRE(cs0 == (csb & csg));
+ REQUIRE(cs0 == (csr & csb));
+ REQUIRE(cs0 == (csrb & csg));
+ REQUIRE(cs0 == (csrgb & cs0));
+
+ REQUIRE(csrb == (csr | csb));
+ REQUIRE(csgb == (csb | csg));
+ REQUIRE(csrgb == (csr | csb | csg));
+
+ REQUIRE(csrb == (csr ^ csb));
+ REQUIRE(csb == (csr ^ csrb));
+}
+
+TEST_SUITE_END();

Add FlagSet<E,N> for wrapping a bitset of enum values