| 1 | /* |
| 2 | Copyright (c) 2005-2019 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 | // Declarations for a class that can track operations applied to its objects. |
| 18 | // This header is an optional part of the test harness. |
| 19 | |
| 20 | #ifndef tbb_test_harness_state_trackable_H |
| 21 | #define tbb_test_harness_state_trackable_H |
| 22 | |
| 23 | #include <cstddef> |
| 24 | #include <map> |
| 25 | #include <tbb/atomic.h> |
| 26 | |
| 27 | #include "harness_assert.h" |
| 28 | |
| 29 | namespace Harness{ |
| 30 | struct StateTrackableBase { |
| 31 | enum StateValue { |
| 32 | ZeroInitialized = 0, |
| 33 | DefaultInitialized = 0xDEFAUL, |
| 34 | DirectInitialized = 0xD1111, |
| 35 | CopyInitialized = 0xC0314, |
| 36 | MoveInitialized = 0xAAAAA, |
| 37 | Assigned = 0x11AED, |
| 38 | MoveAssigned = 0x22AED, |
| 39 | MovedFrom = 0xFFFFF, |
| 40 | Destroyed = 0xDEADF00, |
| 41 | Unspecified = 0xEEEEE |
| 42 | }; |
| 43 | |
| 44 | class State { |
| 45 | public: |
| 46 | State() __TBB_NOEXCEPT(true) : state(Unspecified) { |
| 47 | assignNewState(Unspecified); |
| 48 | } |
| 49 | State(const State& s) : state(Unspecified) { |
| 50 | assignNewState(s.state); |
| 51 | } |
| 52 | State(StateValue s) __TBB_NOEXCEPT(true) : state(Unspecified) { |
| 53 | assignNewState(s); |
| 54 | }; |
| 55 | State& operator=(StateValue s) __TBB_NOEXCEPT(true) { |
| 56 | assignNewState(s); |
| 57 | return *this; |
| 58 | } |
| 59 | operator StateValue() const __TBB_NOEXCEPT(true) { return state; } |
| 60 | private: |
| 61 | void assignNewState(StateValue s) __TBB_NOEXCEPT(true); |
| 62 | StateValue state; |
| 63 | }; |
| 64 | }; |
| 65 | |
| 66 | struct StateTrackableCounters { |
| 67 | static void reset() { |
| 68 | counters[StateTrackableBase::ZeroInitialized] = counters[StateTrackableBase::DefaultInitialized] = |
| 69 | counters[StateTrackableBase::DirectInitialized] = counters[StateTrackableBase::CopyInitialized] = |
| 70 | counters[StateTrackableBase::MoveInitialized] = counters[StateTrackableBase::Assigned] = |
| 71 | counters[StateTrackableBase::MoveAssigned] = counters[StateTrackableBase::MovedFrom] = |
| 72 | counters[StateTrackableBase::Destroyed] = counters[StateTrackableBase::Unspecified] = 0; |
| 73 | } |
| 74 | |
| 75 | static bool initialize() { |
| 76 | reset(); |
| 77 | return true; |
| 78 | } |
| 79 | |
| 80 | typedef std::map<StateTrackableBase::StateValue, tbb::atomic<std::size_t> > counters_t; |
| 81 | static counters_t counters; |
| 82 | }; |
| 83 | |
| 84 | StateTrackableCounters::counters_t StateTrackableCounters::counters; |
| 85 | static const bool stateTrackableBaseStateInitialized = StateTrackableCounters::initialize(); |
| 86 | |
| 87 | void StateTrackableBase::State::assignNewState(StateValue s) __TBB_NOEXCEPT(true) { |
| 88 | ASSERT(stateTrackableBaseStateInitialized, "State trackable counters are not initialized" ); |
| 89 | ASSERT(s == StateTrackableBase::Unspecified || |
| 90 | StateTrackableCounters::counters.find(s) != StateTrackableCounters::counters.end(), "The current state value is unknown" ); |
| 91 | ASSERT(state == StateTrackableBase::Unspecified || |
| 92 | StateTrackableCounters::counters.find(state) != StateTrackableCounters::counters.end(), "The new state value is unknown" ); |
| 93 | state = s; |
| 94 | ++StateTrackableCounters::counters[state]; |
| 95 | } |
| 96 | |
| 97 | template<bool allow_zero_initialized_state = false> |
| 98 | struct StateTrackable: StateTrackableBase { |
| 99 | static const bool is_zero_initialized_state_allowed = allow_zero_initialized_state; |
| 100 | State state; |
| 101 | |
| 102 | bool is_valid() const { |
| 103 | return state == DefaultInitialized || state == DirectInitialized || state == CopyInitialized |
| 104 | || state == MoveInitialized || state == Assigned || state == MoveAssigned || state == MovedFrom |
| 105 | || (allow_zero_initialized_state && state == ZeroInitialized) |
| 106 | ; |
| 107 | } |
| 108 | |
| 109 | StateTrackable (intptr_t) __TBB_NOEXCEPT(true) : state (DirectInitialized){} |
| 110 | StateTrackable () __TBB_NOEXCEPT(true) : state (DefaultInitialized){} |
| 111 | StateTrackable (const StateTrackable & src) __TBB_NOEXCEPT(true) { |
| 112 | ASSERT( src.is_valid(), "bad source for copy" ); |
| 113 | state = CopyInitialized; |
| 114 | } |
| 115 | #if __TBB_CPP11_RVALUE_REF_PRESENT |
| 116 | StateTrackable (StateTrackable && src) __TBB_NOEXCEPT(true) { |
| 117 | ASSERT( src.is_valid(), "bad source for move?" ); |
| 118 | state = MoveInitialized; |
| 119 | src.state = MovedFrom; |
| 120 | } |
| 121 | StateTrackable & operator=(StateTrackable && src) __TBB_NOEXCEPT(true) { |
| 122 | ASSERT( src.is_valid(), "bad source for assignment" ); |
| 123 | ASSERT( is_valid(), "assigning to invalid instance?" ); |
| 124 | |
| 125 | src.state = MovedFrom; |
| 126 | state = MoveAssigned; |
| 127 | return *this; |
| 128 | } |
| 129 | #endif |
| 130 | StateTrackable & operator=(const StateTrackable & src) __TBB_NOEXCEPT(true) { |
| 131 | ASSERT( src.is_valid(), "bad source for assignment?" ); |
| 132 | ASSERT( is_valid(), "assigning to invalid instance?" ); |
| 133 | |
| 134 | state = Assigned; |
| 135 | return *this; |
| 136 | } |
| 137 | ~StateTrackable () __TBB_NOEXCEPT(true) { |
| 138 | ASSERT( is_valid(), "Calling destructor on invalid instance? (twice destructor call?)" ); |
| 139 | state = Destroyed; |
| 140 | } |
| 141 | }; |
| 142 | } // Harness |
| 143 | #endif // tbb_test_harness_state_trackable_H |
| 144 | |