blob: e235539e1e8f019f231d91ca43a87fc004dfe3bc [file] [log] [blame]
// 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_