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: 42 State() noexcept : state(Unspecified) {} 43 44 State( const State& s ) : state(Unspecified) { 45 assign_new_state(s.state); 46 } 47 48 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 62 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 { 70 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 78 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 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 106 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 112 StateTrackable( intptr_t ) noexcept : state(DirectInitialized) {} 113 StateTrackable() noexcept : state(DefaultInitialized) {} 114 115 StateTrackable( const StateTrackable& src ) noexcept : state(CopyInitialized) { 116 CHECK_FAST_MESSAGE(src.is_valid(), "Bad source for copy ctor"); 117 } 118 119 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 139 ~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> 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> 155 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> 161 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> 169 bool operator()( const StateTrackable<allow_zero_initialized>& f ) { 170 return is_state<desired_state>(f); 171 } 172 173 template <typename T, typename U> 174 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