1 /* 2 * Copyright (c) 2021 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_VERIFICATION_UTIL_SATURATED_ENUM_H_ 17 #define PANDA_VERIFICATION_UTIL_SATURATED_ENUM_H_ 18 19 #include "macros.h" 20 21 #include <utility> 22 23 namespace panda::verifier { 24 25 /* 26 possible options: 27 1. initial value UNDEFINED and any op will lead to fatal error, add constructors etc for proper initialization 28 pros: more safety and robustness to programmer errors, cons: more code, more complexity, etc 29 2. initial value is least significant one. 30 pros: simplicity, cons: less robust, does not help to detect logic errors in program 31 */ 32 33 template <typename Enum, Enum...> 34 class SaturatedEnum; 35 36 template <typename Enum, Enum E> 37 class SaturatedEnum<Enum, E> { 38 public: 39 SaturatedEnum &operator=(Enum e) 40 { 41 value_ = e; 42 return *this; 43 } 44 45 SaturatedEnum &operator|=(Enum e) 46 { 47 Set(e); 48 return *this; 49 } 50 51 bool operator[](Enum e) const 52 { 53 return Check(e, false); 54 } 55 Enum()56 operator Enum() const 57 { 58 return value_; 59 } 60 61 template <typename Handler> EnumerateValues(Handler && handler)62 void EnumerateValues(Handler &&handler) const 63 { 64 Enumerate(std::move(handler), false); 65 } 66 67 protected: 68 #ifndef NDEBUG Check(Enum e,bool prev_set)69 bool Check(Enum e, bool prev_set) const 70 #else 71 bool Check([[maybe_unused]] Enum e, bool prev_set) const 72 #endif 73 { 74 // to catch missed enum members 75 ASSERT(e == E); 76 return prev_set || value_ == E; 77 } 78 Set(Enum e)79 void Set(Enum e) 80 { 81 ASSERT(e == E); 82 value_ = e; 83 } 84 85 template <typename Handler> Enumerate(Handler && handler,bool prev_set)86 void Enumerate(Handler &&handler, bool prev_set) const 87 { 88 prev_set |= value_ == E; 89 if (prev_set) { 90 handler(E); 91 } 92 } 93 94 Enum value_ {E}; 95 }; 96 97 template <typename Enum, Enum E, Enum... Rest> 98 class SaturatedEnum<Enum, E, Rest...> : public SaturatedEnum<Enum, Rest...> { 99 using Base = SaturatedEnum<Enum, Rest...>; 100 101 public: 102 SaturatedEnum &operator=(Enum e) 103 { 104 Base::operator=(e); 105 return *this; 106 } 107 108 SaturatedEnum &operator|=(Enum e) 109 { 110 Set(e); 111 return *this; 112 } 113 114 bool operator[](Enum e) const 115 { 116 return Check(e, false); 117 } 118 Enum()119 operator Enum() const 120 { 121 return Base::value_; 122 } 123 124 template <typename Handler> EnumerateValues(Handler && handler)125 void EnumerateValues(Handler &&handler) const 126 { 127 Enumerate(std::move(handler), false); 128 } 129 130 protected: Check(Enum e,bool prev_set)131 bool Check(Enum e, bool prev_set) const 132 { 133 prev_set |= Base::value_ == E; 134 if (e == E) { 135 return prev_set; 136 } 137 return Base::Check(e, prev_set); 138 } 139 Set(Enum e)140 void Set(Enum e) 141 { 142 if (Base::value_ == E) { 143 return; 144 } 145 if (e == E) { 146 Base::operator=(e); 147 return; 148 } 149 Base::Set(e); 150 } 151 152 template <typename Handler> Enumerate(Handler && handler,bool prev_set)153 void Enumerate(Handler &&handler, bool prev_set) const 154 { 155 prev_set |= Base::value_ == E; 156 if (prev_set && !handler(E)) { 157 return; 158 } 159 Base::template Enumerate<Handler>(std::move(handler), prev_set); 160 } 161 }; 162 163 } // namespace panda::verifier 164 165 #endif // PANDA_VERIFICATION_UTIL_SATURATED_ENUM_H_ 166