diff --git a/src/BUILD.gn b/src/BUILD.gn index 6c91770e98..c39e38b315 100644 --- a/src/BUILD.gn +++ b/src/BUILD.gn @@ -573,6 +573,7 @@ libtint_source_set("libtint_core_all_src") { "transform/var_for_dynamic_index.h", "transform/vertex_pulling.cc", "transform/vertex_pulling.h", + "utils/enum_set.h", "utils/get_or_create.h", "utils/hash.h", "utils/math.h", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9066b187d1..7c6ed45ef2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -335,6 +335,7 @@ set(TINT_LIB_SRCS sem/vector_type.h sem/void_type.cc sem/void_type.h + utils/enum_set.h utils/get_or_create.h utils/hash.h utils/math.h @@ -620,6 +621,7 @@ if(${TINT_BUILD_TESTS}) sem/type_manager_test.cc sem/u32_type_test.cc sem/vector_type_test.cc + utils/enum_set_test.cc utils/get_or_create_test.cc utils/hash_test.cc utils/io/command_test.cc diff --git a/src/utils/enum_set.h b/src/utils/enum_set.h new file mode 100644 index 0000000000..396e911b7d --- /dev/null +++ b/src/utils/enum_set.h @@ -0,0 +1,79 @@ +// Copyright 2021 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_UTILS_ENUM_SET_H_ +#define SRC_UTILS_ENUM_SET_H_ + +#include +#include + +namespace tint { +namespace utils { + +/// EnumSet is a set of enum values. +/// @note As the EnumSet is backed by a single uint64_t value, it can only hold +/// enum values in the range [0 .. 63]. +template +struct EnumSet { + public: + /// Enum is the enum type this EnumSet wraps + using Enum = ENUM; + + /// Constructor. Initializes the EnumSet with zero. + constexpr EnumSet() = default; + + /// Constructor. Initializes the EnumSet with the given values. + /// @param values the enumerator values to construct the set with + template + explicit constexpr EnumSet(VALUES... values) : set(Union(values...)) {} + + /// Adds e to this set + /// @param e the enum value + /// @return this set so calls can be chained + inline EnumSet& Add(Enum e) { + set |= Bit(e); + return *this; + } + + /// Removes e from this set + /// @param e the enum value + /// @return this set so calls can be chained + inline EnumSet& Remove(Enum e) { + set &= ~Bit(e); + return *this; + } + + /// @param e the enum value + /// @return true if the set contains `e` + inline bool Contains(Enum e) { return (set & Bit(e)) != 0; } + + private: + static constexpr uint64_t Bit(Enum value) { + return static_cast(1) << static_cast(value); + } + + static constexpr uint64_t Union() { return 0; } + + template + static constexpr uint64_t Union(FIRST first, VALUES... values) { + return Bit(first) | Union(values...); + } + + uint64_t set = 0; +}; + +} // namespace utils +} // namespace tint + +#endif // SRC_UTILS_ENUM_SET_H_ diff --git a/src/utils/enum_set_test.cc b/src/utils/enum_set_test.cc new file mode 100644 index 0000000000..d53b834966 --- /dev/null +++ b/src/utils/enum_set_test.cc @@ -0,0 +1,64 @@ +// Copyright 2021 The Tint Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/utils/enum_set.h" + +#include "gtest/gtest.h" + +namespace tint { +namespace utils { +namespace { + +enum class E { A, B, C }; + +TEST(EnumSetTest, ConstructEmpty) { + EnumSet set; + EXPECT_FALSE(set.Contains(E::A)); + EXPECT_FALSE(set.Contains(E::B)); + EXPECT_FALSE(set.Contains(E::C)); +} + +TEST(EnumSetTest, ConstructWithSingle) { + EnumSet set(E::B); + EXPECT_FALSE(set.Contains(E::A)); + EXPECT_TRUE(set.Contains(E::B)); + EXPECT_FALSE(set.Contains(E::C)); +} + +TEST(EnumSetTest, ConstructWithMultiple) { + EnumSet set(E::A, E::C); + EXPECT_TRUE(set.Contains(E::A)); + EXPECT_FALSE(set.Contains(E::B)); + EXPECT_TRUE(set.Contains(E::C)); +} + +TEST(EnumSetTest, Add) { + EnumSet set; + set.Add(E::B); + EXPECT_FALSE(set.Contains(E::A)); + EXPECT_TRUE(set.Contains(E::B)); + EXPECT_FALSE(set.Contains(E::C)); +} + +TEST(EnumSetTest, Remove) { + EnumSet set(E::A, E::B); + set.Remove(E::B); + EXPECT_TRUE(set.Contains(E::A)); + EXPECT_FALSE(set.Contains(E::B)); + EXPECT_FALSE(set.Contains(E::C)); +} + +} // namespace +} // namespace utils +} // namespace tint diff --git a/test/BUILD.gn b/test/BUILD.gn index 12a5fa5582..ef868a66e4 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -287,6 +287,7 @@ tint_unittests_source_set("tint_unittests_core_src") { "../src/transform/transform_test.cc", "../src/transform/var_for_dynamic_index_test.cc", "../src/transform/vertex_pulling_test.cc", + "../src/utils/enum_set_test.cc", "../src/utils/get_or_create_test.cc", "../src/utils/hash_test.cc", "../src/utils/io/command_test.cc",