summaryrefslogtreecommitdiffstats
path: root/mfbt/EnumTypeTraits.h
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/EnumTypeTraits.h')
-rw-r--r--mfbt/EnumTypeTraits.h113
1 files changed, 113 insertions, 0 deletions
diff --git a/mfbt/EnumTypeTraits.h b/mfbt/EnumTypeTraits.h
new file mode 100644
index 0000000000..528e1db8a7
--- /dev/null
+++ b/mfbt/EnumTypeTraits.h
@@ -0,0 +1,113 @@
+/* -*- 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 <stddef.h>
+#include <type_traits>
+
+namespace mozilla {
+
+namespace detail {
+
+template <size_t EnumSize, bool EnumSigned, size_t StorageSize,
+ bool StorageSigned>
+struct EnumFitsWithinHelper;
+
+// Signed enum, signed storage.
+template <size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, true, StorageSize, true>
+ : public std::integral_constant<bool, (EnumSize <= StorageSize)> {};
+
+// Signed enum, unsigned storage.
+template <size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, true, StorageSize, false>
+ : public std::integral_constant<bool, false> {};
+
+// Unsigned enum, signed storage.
+template <size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, false, StorageSize, true>
+ : public std::integral_constant<bool, (EnumSize * 2 <= StorageSize)> {};
+
+// Unsigned enum, unsigned storage.
+template <size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, false, StorageSize, false>
+ : public std::integral_constant<bool, (EnumSize <= StorageSize)> {};
+
+} // 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 <typename T, typename Storage>
+struct EnumTypeFitsWithin
+ : public detail::EnumFitsWithinHelper<
+ sizeof(T),
+ std::is_signed<typename std::underlying_type<T>::type>::value,
+ sizeof(Storage), std::is_signed<Storage>::value> {
+ static_assert(std::is_enum<T>::value, "must provide an enum type");
+ static_assert(std::is_integral<Storage>::value,
+ "must provide an integral type");
+};
+
+/*
+ * Provides information about highest enum member value.
+ * Each specialization of struct MaxEnumValue should define
+ * "static constexpr unsigned int value".
+ *
+ * example:
+ *
+ * enum ExampleEnum
+ * {
+ * CAT = 0,
+ * DOG,
+ * HAMSTER
+ * };
+ *
+ * template <>
+ * struct MaxEnumValue<ExampleEnum>
+ * {
+ * static constexpr unsigned int value = static_cast<unsigned int>(HAMSTER);
+ * };
+ */
+template <typename T>
+struct MaxEnumValue; // no need to define the primary template
+
+/**
+ * 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 <typename T>
+inline constexpr auto UnderlyingValue(const T v) {
+ static_assert(std::is_enum_v<T>);
+ return static_cast<typename std::underlying_type<T>::type>(v);
+}
+
+} // namespace mozilla
+
+#endif /* mozilla_EnumTypeTraits_h */