1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_VERIFIER_UTIL_SATURATED_ENUM_H__ 17 #define PANDA_VERIFIER_UTIL_SATURATED_ENUM_H__ 18 19 #include "macros.h" 20 21 #include <utility> 22 23 namespace panda::verifier { 24 25 /* 26 TODO: default value? 27 possible options: 28 1. initial value UNDEFINED and any op will lead to fatal error, add constructors etc for proper initialization 29 pros: more safety and robustness to programmer errors, cons: more code, more complexity, etc 30 2. initial value is least significant one. 31 pros: simplicity, cons: less robust, does not help to detect logic errors in program 32 */ 33 34 template <typename Enum, Enum...> 35 class SaturatedEnum; 36 37 template <typename Enum, Enum E> 38 class SaturatedEnum<Enum, E> { 39 public: 40 SaturatedEnum &operator=(Enum e) 41 { 42 value_ = e; 43 return *this; 44 } 45 46 SaturatedEnum &operator|=(Enum e) 47 { 48 Set(e); 49 return *this; 50 } 51 52 bool operator[](Enum e) const 53 { 54 return Check(e, false); 55 } 56 Enum()57 operator Enum() const 58 { 59 return value_; 60 } 61 62 template <typename Handler> EnumerateValues(Handler && handler)63 void EnumerateValues(Handler &&handler) const 64 { 65 Enumerate(std::move(handler), false); 66 } 67 68 protected: 69 #ifndef NDEBUG Check(Enum e,bool prev_set)70 bool Check(Enum e, bool prev_set) const 71 #else 72 bool Check([[maybe_unused]] Enum e, bool prev_set) const 73 #endif 74 { 75 // to catch missed enum members 76 ASSERT(e == E); 77 return prev_set || value_ == E; 78 } 79 Set(Enum e)80 void Set(Enum e) 81 { 82 ASSERT(e == E); 83 value_ = e; 84 } 85 86 template <typename Handler> Enumerate(Handler && handler,bool prev_set)87 void Enumerate(Handler &&handler, bool prev_set) const 88 { 89 prev_set = prev_set || (value_ == E); 90 if (prev_set) { 91 handler(E); 92 } 93 } 94 95 Enum value_ {E}; 96 }; 97 98 template <typename Enum, Enum E, Enum... Rest> 99 class SaturatedEnum<Enum, E, Rest...> : public SaturatedEnum<Enum, Rest...> { 100 using Base = SaturatedEnum<Enum, Rest...>; 101 102 public: 103 SaturatedEnum &operator=(Enum e) 104 { 105 Base::operator=(e); 106 return *this; 107 } 108 109 SaturatedEnum &operator|=(Enum e) 110 { 111 Set(e); 112 return *this; 113 } 114 115 bool operator[](Enum e) const 116 { 117 return Check(e, false); 118 } 119 Enum()120 operator Enum() const 121 { 122 return Base::value_; 123 } 124 125 template <typename Handler> EnumerateValues(Handler && handler)126 void EnumerateValues(Handler &&handler) const 127 { 128 Enumerate(std::move(handler), false); 129 } 130 131 protected: Check(Enum e,bool prev_set)132 bool Check(Enum e, bool prev_set) const 133 { 134 prev_set = prev_set || (Base::value_ == E); 135 if (e == E) { 136 return prev_set; 137 } 138 return Base::Check(e, prev_set); 139 } 140 Set(Enum e)141 void Set(Enum e) 142 { 143 if (Base::value_ == E) { 144 return; 145 } 146 if (e == E) { 147 Base::operator=(e); 148 return; 149 } 150 Base::Set(e); 151 } 152 153 template <typename Handler> Enumerate(Handler && handler,bool prev_set)154 void Enumerate(Handler &&handler, bool prev_set) const 155 { 156 prev_set = prev_set || (Base::value_ == E); 157 if (prev_set && !handler(E)) { 158 return; 159 } 160 Base::template Enumerate<Handler>(std::move(handler), prev_set); 161 } 162 }; 163 164 } // namespace panda::verifier 165 166 #endif //! PANDA_VERIFIER_UTIL_SATURATED_ENUM_H__ 167