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 | |