xref: /aosp_15_r20/external/cronet/base/allocator/partition_allocator/src/partition_alloc/flags.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This header provides a type-safe way of storing OR-combinations of enum
6 // values.
7 //
8 // The traditional C++ approach for storing OR-combinations of enum values is to
9 // use an int or unsigned int variable. The inconvenience with this approach is
10 // that there's no type checking at all; any enum value can be OR'd with any
11 // other enum value and passed on to a function that takes an int or unsigned
12 // int.
13 
14 #ifndef PARTITION_ALLOC_FLAGS_H_
15 #define PARTITION_ALLOC_FLAGS_H_
16 
17 #include <type_traits>
18 
19 namespace partition_alloc::internal {
20 // Returns `T` if and only if `EnumType` is a scoped enum.
21 template <typename EnumType, typename T = EnumType>
22 using IfEnum = std::enable_if_t<
23     std::is_enum_v<EnumType> &&
24         !std::is_convertible_v<EnumType, std::underlying_type_t<EnumType>>,
25     T>;
26 
27 // We assume `EnumType` defines `kMaxValue` which has the largest value and all
28 // powers of two are represented in `EnumType`.
29 template <typename EnumType>
30 constexpr inline EnumType kAllFlags = static_cast<IfEnum<EnumType>>(
31     (static_cast<std::underlying_type_t<EnumType>>(EnumType::kMaxValue) << 1) -
32     1);
33 
34 template <typename EnumType>
AreValidFlags(EnumType flags)35 constexpr inline IfEnum<EnumType, bool> AreValidFlags(EnumType flags) {
36   const auto raw_flags = static_cast<std::underlying_type_t<EnumType>>(flags);
37   const auto raw_all_flags =
38       static_cast<std::underlying_type_t<EnumType>>(kAllFlags<EnumType>);
39   return (raw_flags & ~raw_all_flags) == 0;
40 }
41 
42 // Checks `subset` is a subset of `superset` or not.
43 template <typename EnumType>
ContainsFlags(EnumType superset,EnumType subset)44 constexpr inline IfEnum<EnumType, bool> ContainsFlags(EnumType superset,
45                                                       EnumType subset) {
46   return (superset & subset) == subset;
47 }
48 
49 // Removes flags `target` from `from`.
50 template <typename EnumType>
RemoveFlags(EnumType from,EnumType target)51 constexpr inline IfEnum<EnumType> RemoveFlags(EnumType from, EnumType target) {
52   return from & ~target;
53 }
54 
55 // A macro to define binary arithmetic over `EnumType`.
56 // Use inside `namespace partition_alloc::internal`.
57 #define PA_DEFINE_OPERATORS_FOR_FLAGS(EnumType)                              \
58   [[maybe_unused]] [[nodiscard]] inline constexpr EnumType operator&(        \
59       const EnumType& lhs, const EnumType& rhs) {                            \
60     return static_cast<EnumType>(                                            \
61         static_cast<std::underlying_type_t<EnumType>>(lhs) &                 \
62         static_cast<std::underlying_type_t<EnumType>>(rhs));                 \
63   }                                                                          \
64   [[maybe_unused]] inline constexpr EnumType& operator&=(                    \
65       EnumType& lhs, const EnumType& rhs) {                                  \
66     lhs = lhs & rhs;                                                         \
67     return lhs;                                                              \
68   }                                                                          \
69   [[maybe_unused]] [[nodiscard]] inline constexpr EnumType operator|(        \
70       const EnumType& lhs, const EnumType& rhs) {                            \
71     return static_cast<EnumType>(                                            \
72         static_cast<std::underlying_type_t<EnumType>>(lhs) |                 \
73         static_cast<std::underlying_type_t<EnumType>>(rhs));                 \
74   }                                                                          \
75   [[maybe_unused]] inline constexpr EnumType& operator|=(                    \
76       EnumType& lhs, const EnumType& rhs) {                                  \
77     lhs = lhs | rhs;                                                         \
78     return lhs;                                                              \
79   }                                                                          \
80   [[maybe_unused]] [[nodiscard]] inline constexpr EnumType operator^(        \
81       const EnumType& lhs, const EnumType& rhs) {                            \
82     return static_cast<EnumType>(                                            \
83         static_cast<std::underlying_type_t<EnumType>>(lhs) ^                 \
84         static_cast<std::underlying_type_t<EnumType>>(rhs));                 \
85   }                                                                          \
86   [[maybe_unused]] inline constexpr EnumType& operator^=(                    \
87       EnumType& lhs, const EnumType& rhs) {                                  \
88     lhs = lhs ^ rhs;                                                         \
89     return lhs;                                                              \
90   }                                                                          \
91   [[maybe_unused]] [[nodiscard]] inline constexpr EnumType operator~(        \
92       const EnumType& val) {                                                 \
93     return static_cast<EnumType>(                                            \
94         static_cast<std::underlying_type_t<EnumType>>(kAllFlags<EnumType>) & \
95         ~static_cast<std::underlying_type_t<EnumType>>(val));                \
96   }                                                                          \
97   static_assert(true) /* semicolon here */
98 
99 }  // namespace partition_alloc::internal
100 
101 #endif  // PARTITION_ALLOC_FLAGS_H_
102