| // Copyright 2017-2020 The Verible 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 VERIBLE_COMMON_UTIL_ENUM_FLAGS_H_ |
| #define VERIBLE_COMMON_UTIL_ENUM_FLAGS_H_ |
| |
| #include <initializer_list> |
| #include <map> |
| #include <sstream> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_join.h" |
| #include "absl/strings/string_view.h" |
| #include "common/strings/compare.h" |
| #include "common/util/logging.h" |
| |
| namespace verible { |
| |
| /** |
| This library provides some boilerplate functions for handling enums as flags. |
| The main benefit of this is having to only specify the relationship between |
| values and their string names once in an initializer_list. |
| This operates smoothly with the absl flags library. |
| |
| Usage: |
| (in your .h file) |
| namespace your_namespace { |
| |
| enum class MyEnumType { |
| kValue1, |
| kValue2, |
| kValue3, |
| ... |
| }; |
| |
| namespace internal { |
| // data that is private to the implementation and tests |
| extern const std::initializer_list< |
| std::pair<const absl::string_view, MyEnumType>> |
| kMyEnumTypeStringMap; |
| } // namespace internal |
| |
| std::ostream& operator<<(std::ostream&, MyEnumType); |
| |
| // For use with the absl flags library, declare the following: |
| |
| bool AbslParseFlag(absl::string_view, MyEnumType*, std::string*); |
| |
| std::string AbslUnparseFlag(const MyEnumType&); |
| |
| } // namespace your_namespace |
| |
| |
| (in your .cc file, which includes your .h file) |
| |
| namespace your_namespace { |
| namespace internal { |
| // This mapping defines how this enum is displayed and parsed. |
| // By providing this mapping, the other necessary flag functions can be |
| // generated for you. |
| const std::initializer_list< |
| std::pair<const absl::string_view, MyEnumType>> |
| kMyEnumTypeStringMap = { |
| {"value1", MyEnumType::kValue1}, |
| {"value2", MyEnumType::kValue2}, |
| {"value3", MyEnumType::kValue3}, |
| // etc. |
| }; |
| } // namespace internal |
| |
| // Conventional stream printer (declared in header providing enum). |
| std::ostream& operator<<(std::ostream& stream, MyEnumType p) { |
| static const auto* flag_map = |
| MakeEnumToStringMap(internal::kMyEnumTypeStringMap); |
| return stream << flag_map->find(p)->second; |
| } |
| |
| bool AbslParseFlag(absl::string_view text, MyEnumType* mode, |
| std::string* error) { |
| static const auto* flag_map = |
| MakeStringToEnumMap(internal::kMyEnumTypeStringMap); |
| return EnumMapParseFlag(*flag_map, text, mode, error); |
| } |
| |
| std::string AbslUnparseFlag(const MyEnumType& mode) { |
| std::ostringstream stream; |
| stream << mode; |
| return stream.str(); |
| } |
| |
| } // namespace your_namespace |
| **/ |
| |
| // Functor that extracts the first element of a pair and appends it to a string. |
| // Suitable for use with absl::StrJoin()'s formatter arguments. |
| struct FirstElementFormatter { |
| template <class P> |
| void operator()(std::string* out, const P& p) const { |
| out->append(std::string(p.first)); |
| } |
| }; |
| |
| // Looks up an enum value given its string name, and sets it by reference. |
| // Suitable for use with AbslParseFlag(). |
| template <typename M> |
| bool EnumMapParseFlag(const M& flag_map, absl::string_view text, |
| typename M::mapped_type* flag, std::string* error) { |
| const auto p = flag_map.find(text); |
| if (p != flag_map.end()) { |
| *flag = p->second; |
| return true; |
| } else { |
| *error = absl::StrCat( |
| "unknown value for enumeration '", text, "'. Valid options are: ", |
| absl::StrJoin(flag_map, ",", FirstElementFormatter())); |
| return false; |
| } |
| } |
| |
| // For enums to be comparable for uniqueness/mapping sake, |
| // force interpret them as integers. |
| struct EnumCompare { |
| template <class E> |
| bool operator()(E left, E right) const { |
| return static_cast<int>(left) < static_cast<int>(right); |
| } |
| }; |
| |
| // Constructs a map<S, V> from a sequence of pair<S, V>'s. |
| // V is an enum type, S is only string_view |
| template <class V> |
| const std::map<absl::string_view, V, verible::StringViewCompare>* |
| MakeStringToEnumMap( |
| std::initializer_list<std::pair<const absl::string_view, V>> elements) { |
| return new std::map<absl::string_view, V, verible::StringViewCompare>( |
| elements); |
| } |
| |
| // Constructs a (reverse) map<V, S> from a sequence of pair<S, V>'s. |
| // V is an enum type, S is only string_view |
| // Fatal error if any keys are duplicate. |
| template <class V> |
| const std::map<V, absl::string_view, EnumCompare>* MakeEnumToStringMap( |
| std::initializer_list<std::pair<const absl::string_view, V>> elements) { |
| auto* result = new std::map<V, absl::string_view, EnumCompare>; |
| for (const auto& p : elements) { |
| const auto it = result->emplace(p.second, p.first); |
| CHECK(it.second) << "Duplicate element forbidden at key: " << p.second; |
| } |
| return result; |
| } |
| |
| } // namespace verible |
| |
| #endif // VERIBLE_COMMON_UTIL_ENUM_FLAGS_H_ |