• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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