blob: f37df04edd849ea6e019addc777f5536d358040b [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_UPDATER_ENUM_TRAITS_H_
#define CHROME_UPDATER_ENUM_TRAITS_H_
#include <concepts>
#include <optional>
#include <ostream>
#include <type_traits>
#include "base/types/cxx23_to_underlying.h"
namespace updater {
// Provides a way to safely convert numeric types to enumerated values. To use
// this facility, the enum definition must be annotated with traits to specify
// the range of the enum values. Due to how specialization of class templates
// works in C++14, the `EnumTraits` specialization of the primary template must
// be defined inside the `updater` namespace, where the primary template is
// defined. Traits for enum types defined inside other scopes, such as nested
// classes or other namespaces, may not work.
//
// enum class MyEnum {
// kVal1 = -1,
// kVal2 = 0,
// kVal3 = 1,
// };
//
// template <>
// struct EnumTraits<MyEnum> {
// static constexpr MyEnum first_elem = MyEnum::kVal1;
// static constexpr MyEnum last_elem = MyEnum::kVal3;
// };
//
// MyEnum val = *CheckedCastToEnum<MyEnum>(-1);
template <typename T>
requires(std::is_enum_v<T>)
struct EnumTraits {};
// Returns an optional value of an enum type T if the conversion from an
// integer value `v` is safe, meaning that `v` is within the bounds of the enum.
// The enum type must be annotated with traits to specify the lower and upper
// bounds of the enum values.
template <typename T>
requires(std::is_enum_v<T>)
constexpr std::optional<T> CheckedCastToEnum(std::underlying_type_t<T> v) {
return (base::to_underlying(EnumTraits<T>::first_elem) <= v &&
v <= base::to_underlying(EnumTraits<T>::last_elem))
? std::make_optional(static_cast<T>(v))
: std::nullopt;
}
} // namespace updater
#endif // CHROME_UPDATER_ENUM_TRAITS_H_