EnumTypeTraits.h (4694B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* Type traits for enums. */ 7 8 #ifndef mozilla_EnumTypeTraits_h 9 #define mozilla_EnumTypeTraits_h 10 11 #include <cstddef> 12 #include <type_traits> 13 14 namespace mozilla { 15 16 namespace detail { 17 18 template <size_t EnumSize, bool EnumSigned, size_t StorageSize, 19 bool StorageSigned> 20 struct EnumFitsWithinHelper; 21 22 // Signed enum, signed storage. 23 template <size_t EnumSize, size_t StorageSize> 24 struct EnumFitsWithinHelper<EnumSize, true, StorageSize, true> 25 : public std::integral_constant<bool, (EnumSize <= StorageSize)> {}; 26 27 // Signed enum, unsigned storage. 28 template <size_t EnumSize, size_t StorageSize> 29 struct EnumFitsWithinHelper<EnumSize, true, StorageSize, false> 30 : public std::integral_constant<bool, false> {}; 31 32 // Unsigned enum, signed storage. 33 template <size_t EnumSize, size_t StorageSize> 34 struct EnumFitsWithinHelper<EnumSize, false, StorageSize, true> 35 : public std::integral_constant<bool, (EnumSize * 2 <= StorageSize)> {}; 36 37 // Unsigned enum, unsigned storage. 38 template <size_t EnumSize, size_t StorageSize> 39 struct EnumFitsWithinHelper<EnumSize, false, StorageSize, false> 40 : public std::integral_constant<bool, (EnumSize <= StorageSize)> {}; 41 42 } // namespace detail 43 44 /* 45 * Type trait that determines whether the enum type T can fit within the 46 * integral type Storage without data loss. This trait should be used with 47 * caution with an enum type whose underlying type has not been explicitly 48 * specified: for such enums, the C++ implementation is free to choose a type 49 * no smaller than int whose range encompasses all possible values of the enum. 50 * So for an enum with only small non-negative values, the underlying type may 51 * be either int or unsigned int, depending on the whims of the implementation. 52 */ 53 template <typename T, typename Storage> 54 struct EnumTypeFitsWithin 55 : public detail::EnumFitsWithinHelper< 56 sizeof(T), 57 std::is_signed<typename std::underlying_type<T>::type>::value, 58 sizeof(Storage), std::is_signed<Storage>::value> { 59 static_assert(std::is_enum<T>::value, "must provide an enum type"); 60 static_assert(std::is_integral<Storage>::value, 61 "must provide an integral type"); 62 }; 63 64 /** 65 * Get the underlying value of an enum, but typesafe. 66 * TODO: Replace with std::to_underlying when available. 67 * 68 * example: 69 * 70 * enum class Pet : int16_t { 71 * Cat, 72 * Dog, 73 * Fish 74 * }; 75 * enum class Plant { 76 * Flower, 77 * Tree, 78 * Vine 79 * }; 80 * UnderlyingValue(Pet::Fish) -> int16_t(2) 81 * UnderlyingValue(Plant::Tree) -> int(1) 82 */ 83 template <typename T> 84 inline constexpr auto UnderlyingValue(const T v) { 85 static_assert(std::is_enum_v<T>); 86 return static_cast<typename std::underlying_type<T>::type>(v); 87 } 88 89 /* 90 * Specialize either MaxContiguousEnumValue or MaxEnumValue to provide the 91 * highest enum member value for an enum class. Note that specializing 92 * MaxContiguousEnumValue will make MaxEnumValue just take its value from the 93 * MaxContiguousEnumValue specialization. 94 * 95 * Specialize MinContiguousEnumValue and MaxContiguousEnumValue to provide both 96 * lowest and highest enum member values for an enum class with contiguous 97 * values. 98 * 99 * Each specialization of these structs should define "static constexpr" member 100 * variable named "value". 101 * 102 * example: 103 * 104 * enum ExampleEnum 105 * { 106 * CAT = 0, 107 * DOG, 108 * HAMSTER 109 * }; 110 * 111 * template <> 112 * struct MaxEnumValue<ExampleEnum> 113 * { 114 * static constexpr ExampleEnumvalue = HAMSTER; 115 * }; 116 */ 117 118 template <typename T> 119 struct MinContiguousEnumValue : std::integral_constant<T, T(0)> {}; 120 121 template <typename T> 122 struct MaxContiguousEnumValue; 123 124 template <typename T> 125 struct MaxEnumValue : MaxContiguousEnumValue<T> {}; 126 127 // Provides the min and max values for a contiguous enum (requires at least 128 // MaxContiguousEnumValue to be defined). 129 template <typename T> 130 struct ContiguousEnumValues { 131 static constexpr auto min = MinContiguousEnumValue<T>::value; 132 static constexpr auto max = MaxContiguousEnumValue<T>::value; 133 }; 134 135 // Provides the total number of values for a contiguous enum (requires at least 136 // MaxContiguousEnumValue to be defined). 137 template <typename T> 138 struct ContiguousEnumSize { 139 static constexpr size_t value = 140 UnderlyingValue(ContiguousEnumValues<T>::max) + 1 - 141 UnderlyingValue(ContiguousEnumValues<T>::min); 142 }; 143 144 } // namespace mozilla 145 146 #endif /* mozilla_EnumTypeTraits_h */