xref: /oneTBB/test/common/state_trackable.h (revision b15aabb3)
1 /*
2     Copyright (c) 2005-2021 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 #ifndef __TBB_test_common_state_trackable_H
18 #define __TBB_test_common_state_trackable_H
19 
20 #include "common/test.h"
21 #include <map>
22 #include <atomic>
23 
24 // Declarations for a class that can track operations applied to its objects.
25 
26 struct StateTrackableBase {
27     enum StateValue {
28         ZeroInitialized     = 0,
29         DefaultInitialized  = 0xDEFAUL,
30         DirectInitialized   = 0xD1111,
31         CopyInitialized     = 0xC0314,
32         MoveInitialized     = 0xAAAAA,
33         CopyAssigned        = 0x11AED,
34         MoveAssigned        = 0x22AED,
35         MovedFrom           = 0xFFFFF,
36         Destroyed           = 0xDEADF00,
37         Unspecified         = 0xEEEEE
38     };
39 
40     class State {
41     public:
StateStateTrackableBase42         State() noexcept : state(Unspecified) {}
43 
StateStateTrackableBase44         State( const State& s ) : state(Unspecified) {
45             assign_new_state(s.state);
46         }
47 
StateStateTrackableBase48         State( StateValue s ) noexcept : state(Unspecified) {
49             assign_new_state(s);
50         }
51 
52         State& operator=( const State& st ) noexcept {
53             assign_new_state(st.state);
54             return *this;
55         }
56 
57         State& operator=( StateValue s ) noexcept {
58             assign_new_state(s);
59             return *this;
60         }
61 
StateValueStateTrackableBase62         operator StateValue() const noexcept { return state; }
63     private:
64         void assign_new_state( StateValue s ) noexcept;
65         StateValue state;
66     }; // class State
67 }; // struct StateTrackableBase
68 
69 struct StateTrackableCounters {
resetStateTrackableCounters70     static void reset() {
71         counters[StateTrackableBase::ZeroInitialized] = counters[StateTrackableBase::DefaultInitialized] =
72         counters[StateTrackableBase::DirectInitialized] = counters[StateTrackableBase::CopyInitialized] =
73         counters[StateTrackableBase::MoveInitialized] = counters[StateTrackableBase::CopyAssigned] =
74         counters[StateTrackableBase::MoveAssigned] = counters[StateTrackableBase::MovedFrom] =
75         counters[StateTrackableBase::Destroyed] = counters[StateTrackableBase::Unspecified] = 0;
76     }
77 
initializeStateTrackableCounters78     static bool initialize() {
79         reset();
80         return true;
81     }
82 
83     using counters_type = std::map<StateTrackableBase::StateValue, std::atomic<std::size_t>>;
84     static counters_type counters;
85 }; // struct StateTrackableCounters
86 
87 StateTrackableCounters::counters_type StateTrackableCounters::counters;
88 static const bool state_initialized = StateTrackableCounters::initialize();
89 
assign_new_state(StateValue s)90 void StateTrackableBase::State::assign_new_state( StateValue s ) noexcept {
91     CHECK_FAST_MESSAGE(state_initialized, "State trackable counters are not initialized");
92     CHECK_FAST_MESSAGE((s == StateTrackableBase::Unspecified ||
93                      StateTrackableCounters::counters.find(s) != StateTrackableCounters::counters.end()),
94                      "Current state value is unknown");
95     CHECK_FAST_MESSAGE((state == StateTrackableBase::Unspecified ||
96                      StateTrackableCounters::counters.find(state) != StateTrackableCounters::counters.end()),
97                      "New state value is unknown");
98     state = s;
99     ++StateTrackableCounters::counters[state];
100 }
101 
102 template <bool AllowZeroInitialized = false>
103 struct StateTrackable : StateTrackableBase {
104     static constexpr bool allow_zero_initialized = AllowZeroInitialized;
105 
is_validStateTrackable106     bool is_valid() const {
107         return state == DefaultInitialized || state == DirectInitialized || state == CopyInitialized ||
108                state == MoveInitialized || state == CopyAssigned || state == MoveAssigned || state == MovedFrom ||
109                (allow_zero_initialized && state == ZeroInitialized);
110     }
111 
StateTrackableStateTrackable112     StateTrackable( intptr_t ) noexcept : state(DirectInitialized) {}
StateTrackableStateTrackable113     StateTrackable() noexcept : state(DefaultInitialized) {}
114 
StateTrackableStateTrackable115     StateTrackable( const StateTrackable& src ) noexcept : state(CopyInitialized) {
116         CHECK_FAST_MESSAGE(src.is_valid(), "Bad source for copy ctor");
117     }
118 
StateTrackableStateTrackable119     StateTrackable( StateTrackable&& src ) noexcept : state(MoveInitialized) {
120         CHECK_FAST_MESSAGE(src.is_valid(), "Bad source for move ctor");
121         src.state = MovedFrom;
122     }
123 
124     StateTrackable& operator=( const StateTrackable& src ) noexcept {
125         CHECK_FAST_MESSAGE(is_valid(), "Copy assignment to invalid instance");
126         CHECK_FAST_MESSAGE(src.is_valid(), "Bad source for copy assignment");
127         state = CopyAssigned;
128         return *this;
129     }
130 
131     StateTrackable& operator=( StateTrackable&& src ) noexcept {
132         CHECK_FAST_MESSAGE(is_valid(), "Move assignment to invalid instance");
133         CHECK_FAST_MESSAGE(src.is_valid(), "Bad source for move assignment");
134         state = MoveAssigned;
135         src.state = MovedFrom;
136         return *this;
137     }
138 
~StateTrackableStateTrackable139     ~StateTrackable() noexcept {
140         CHECK_FAST_MESSAGE(is_valid(), "Calling destructor on invalid instance. (May be twice)");
141         state = Destroyed;
142     }
143 
144     State state;
145 }; // struct StateTrackable
146 
147 template <StateTrackableBase::StateValue desired_state, bool allow_zero_initialized>
is_state(const StateTrackable<allow_zero_initialized> & f)148 bool is_state( const StateTrackable<allow_zero_initialized>& f ) {
149     return f.state == desired_state;
150 }
151 
152 template <StateTrackableBase::StateValue desired_state>
153 struct is_not_state_predicate {
154     template <bool allow_zero_initialized>
operatoris_not_state_predicate155     bool operator()( const StateTrackable<allow_zero_initialized>& f ) {
156         return !is_state<desired_state>(f);
157     }
158 
159     // To operate with the associative containers
160     template <typename T, typename U>
operatoris_not_state_predicate161     bool operator()( const std::pair<T, U>& p ) {
162         return !is_state<desired_state>(p.second);
163     }
164 };
165 
166 template <StateTrackableBase::StateValue desired_state>
167 struct is_state_predicate {
168     template <bool allow_zero_initialized>
operatoris_state_predicate169     bool operator()( const StateTrackable<allow_zero_initialized>& f ) {
170         return is_state<desired_state>(f);
171     }
172 
173     template <typename T, typename U>
operatoris_state_predicate174     bool operator()( const std::pair<T, U>& p ) {
175         return is_state<desired_state>(p.second);
176     }
177 };
178 
179 #endif // __TBB_test_common_state_trackable_H
180