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