/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Type traits for enums. */ #ifndef mozilla_EnumTypeTraits_h #define mozilla_EnumTypeTraits_h #include #include namespace mozilla { namespace detail { template struct EnumFitsWithinHelper; // Signed enum, signed storage. template struct EnumFitsWithinHelper : public std::integral_constant {}; // Signed enum, unsigned storage. template struct EnumFitsWithinHelper : public std::integral_constant {}; // Unsigned enum, signed storage. template struct EnumFitsWithinHelper : public std::integral_constant {}; // Unsigned enum, unsigned storage. template struct EnumFitsWithinHelper : public std::integral_constant {}; } // namespace detail /* * Type trait that determines whether the enum type T can fit within the * integral type Storage without data loss. This trait should be used with * caution with an enum type whose underlying type has not been explicitly * specified: for such enums, the C++ implementation is free to choose a type * no smaller than int whose range encompasses all possible values of the enum. * So for an enum with only small non-negative values, the underlying type may * be either int or unsigned int, depending on the whims of the implementation. */ template struct EnumTypeFitsWithin : public detail::EnumFitsWithinHelper< sizeof(T), std::is_signed::type>::value, sizeof(Storage), std::is_signed::value> { static_assert(std::is_enum::value, "must provide an enum type"); static_assert(std::is_integral::value, "must provide an integral type"); }; /** * Get the underlying value of an enum, but typesafe. * * example: * * enum class Pet : int16_t { * Cat, * Dog, * Fish * }; * enum class Plant { * Flower, * Tree, * Vine * }; * UnderlyingValue(Pet::Fish) -> int16_t(2) * UnderlyingValue(Plant::Tree) -> int(1) */ template inline constexpr auto UnderlyingValue(const T v) { static_assert(std::is_enum_v); return static_cast::type>(v); } /* * Specialize either MaxContiguousEnumValue or MaxEnumValue to provide the * highest enum member value for an enum class. Note that specializing * MaxContiguousEnumValue will make MaxEnumValue just take its value from the * MaxContiguousEnumValue specialization. * * Specialize MinContiguousEnumValue and MaxContiguousEnumValue to provide both * lowest and highest enum member values for an enum class with contiguous * values. * * Each specialization of these structs should define "static constexpr" member * variable named "value". * * example: * * enum ExampleEnum * { * CAT = 0, * DOG, * HAMSTER * }; * * template <> * struct MaxEnumValue * { * static constexpr ExampleEnumvalue = HAMSTER; * }; */ template struct MinContiguousEnumValue { static constexpr T value = static_cast(0); }; template struct MaxContiguousEnumValue; template struct MaxEnumValue { static constexpr auto value = MaxContiguousEnumValue::value; }; // Provides the min and max values for a contiguous enum (requires at least // MaxContiguousEnumValue to be defined). template struct ContiguousEnumValues { static constexpr auto min = MinContiguousEnumValue::value; static constexpr auto max = MaxContiguousEnumValue::value; }; // Provides the total number of values for a contiguous enum (requires at least // MaxContiguousEnumValue to be defined). template struct ContiguousEnumSize { static constexpr size_t value = UnderlyingValue(ContiguousEnumValues::max) + 1 - UnderlyingValue(ContiguousEnumValues::min); }; } // namespace mozilla #endif /* mozilla_EnumTypeTraits_h */