aboutsummaryrefslogtreecommitdiff
path: root/pstl/test/support/utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'pstl/test/support/utils.h')
-rw-r--r--pstl/test/support/utils.h76
1 files changed, 76 insertions, 0 deletions
diff --git a/pstl/test/support/utils.h b/pstl/test/support/utils.h
index 541dc8c..090f937 100644
--- a/pstl/test/support/utils.h
+++ b/pstl/test/support/utils.h
@@ -231,6 +231,82 @@ fill_data(Iterator first, Iterator last, F f)
}
}
+struct MemoryChecker {
+ // static counters and state tags
+ static std::atomic<std::int64_t> alive_object_counter; // initialized outside
+ static constexpr std::int64_t alive_state = 0xAAAAAAAAAAAAAAAA;
+ static constexpr std::int32_t dead_state = 0; // only used as a set value to cancel alive_state
+
+ std::int32_t _value; // object value used for algorithms
+ std::int64_t _state; // state tag used for checks
+
+ // ctors, dtors, assign ops
+ explicit MemoryChecker(std::int32_t value = 0) : _value(value) {
+ // check for EXPECT_TRUE(state() != alive_state, ...) has not been done since we cannot guarantee that
+ // raw memory for object being constructed does not have a bit sequence being equal to alive_state
+
+ // set constructed state and increment counter for living object
+ inc_alive_objects();
+ _state = alive_state;
+ }
+ MemoryChecker(MemoryChecker&& other) : _value(other.value()) {
+ // check for EXPECT_TRUE(state() != alive_state, ...) has not been done since
+ // compiler can optimize out the move ctor call that results in false positive failure
+ EXPECT_TRUE(other.state() == alive_state, "wrong effect from MemoryChecker(MemoryChecker&&): attemp to construct an object from non-existing object");
+ // set constructed state and increment counter for living object
+ inc_alive_objects();
+ _state = alive_state;
+ }
+ MemoryChecker(const MemoryChecker& other) : _value(other.value()) {
+ // check for EXPECT_TRUE(state() != alive_state, ...) has not been done since
+ // compiler can optimize out the copy ctor call that results in false positive failure
+ EXPECT_TRUE(other.state() == alive_state, "wrong effect from MemoryChecker(const MemoryChecker&): attemp to construct an object from non-existing object");
+ // set constructed state and increment counter for living object
+ inc_alive_objects();
+ _state = alive_state;
+ }
+ MemoryChecker& operator=(MemoryChecker&& other) {
+ // check if we do not assign over uninitialized memory
+ EXPECT_TRUE(state() == alive_state, "wrong effect from MemoryChecker::operator=(MemoryChecker&& other): attemp to assign to non-existing object");
+ EXPECT_TRUE(other.state() == alive_state, "wrong effect from MemoryChecker::operator=(MemoryChecker&& other): attemp to assign from non-existing object");
+ // just assign new value, counter is the same, state is the same
+ _value = other.value();
+
+ return *this;
+ }
+ MemoryChecker& operator=(const MemoryChecker& other) {
+ // check if we do not assign over uninitialized memory
+ EXPECT_TRUE(state() == alive_state, "wrong effect from MemoryChecker::operator=(const MemoryChecker& other): attemp to assign to non-existing object");
+ EXPECT_TRUE(other.state() == alive_state, "wrong effect from MemoryChecker::operator=(const MemoryChecker& other): attemp to assign from non-existing object");
+ // just assign new value, counter is the same, state is the same
+ _value = other.value();
+
+ return *this;
+ }
+ ~MemoryChecker() {
+ // check if we do not double destruct the object
+ EXPECT_TRUE(state() == alive_state, "wrong effect from ~MemoryChecker(): attemp to destroy non-existing object");
+ // set destructed state and decrement counter for living object
+ static_cast<volatile std::int64_t&>(_state) = dead_state;
+ dec_alive_objects();
+ }
+
+ // getters
+ std::int32_t value() const { return _value; }
+ std::int64_t state() const { return _state; }
+ static std::int32_t alive_objects() { return alive_object_counter.load(); }
+private:
+ // setters
+ void inc_alive_objects() { alive_object_counter.fetch_add(1); }
+ void dec_alive_objects() { alive_object_counter.fetch_sub(1); }
+};
+
+std::atomic<std::int64_t> MemoryChecker::alive_object_counter{0};
+
+std::ostream& operator<<(std::ostream& os, const MemoryChecker& val) { return (os << val.value()); }
+bool operator==(const MemoryChecker& v1, const MemoryChecker& v2) { return v1.value() == v2.value(); }
+bool operator<(const MemoryChecker& v1, const MemoryChecker& v2) { return v1.value() < v2.value(); }
+
// Sequence<T> is a container of a sequence of T with lots of kinds of iterators.
// Prefixes on begin/end mean:
// c = "const"