255 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <app/counter.h>
 | |
| 
 | |
| #include <app/print.h> // for print
 | |
| 
 | |
| #include <cstdlib>       // for abort
 | |
| #include <ostream>       // for ostream
 | |
| #include <stdexcept>     // for runtime_error
 | |
| #include <unordered_set> // for unordered_set
 | |
| #include <utility>       // for swap, pair
 | |
| 
 | |
| static inline constexpr bool counter_enable_unordered_set = true;
 | |
| 
 | |
| auto singleton_constructed_objects() -> std::unordered_set<counter::obj const*>& {
 | |
|     static std::unordered_set<counter::obj const*> static_data{};
 | |
|     return static_data;
 | |
| }
 | |
| 
 | |
| counter::obj::obj()
 | |
|     : m_data(0)
 | |
|     , m_counts(nullptr) {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (!singleton_constructed_objects().emplace(this).second) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     ++static_default_ctor;
 | |
| }
 | |
| 
 | |
| counter::obj::obj(const size_t& data, counter& counts)
 | |
|     : m_data(data)
 | |
|     , m_counts(&counts) {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (!singleton_constructed_objects().emplace(this).second) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     ++m_counts->m_data.m_ctor;
 | |
| }
 | |
| 
 | |
| counter::obj::obj(const counter::obj& o)
 | |
|     : m_data(o.m_data)
 | |
|     , m_counts(o.m_counts) {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (1 != singleton_constructed_objects().count(&o)) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|         if (!singleton_constructed_objects().emplace(this).second) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_copy_ctor;
 | |
|     }
 | |
| }
 | |
| 
 | |
| counter::obj::obj(counter::obj&& o) noexcept
 | |
|     : m_data(o.m_data)
 | |
|     , m_counts(o.m_counts) {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (1 != singleton_constructed_objects().count(&o)) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|         if (!singleton_constructed_objects().emplace(this).second) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_move_ctor;
 | |
|     }
 | |
| }
 | |
| 
 | |
| counter::obj::~obj() {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (1 != singleton_constructed_objects().erase(this)) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_dtor;
 | |
|     } else {
 | |
|         ++static_dtor;
 | |
|     }
 | |
| }
 | |
| 
 | |
| auto counter::obj::operator==(obj const& o) const -> bool {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&o)) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_equals;
 | |
|     }
 | |
|     return m_data == o.m_data;
 | |
| }
 | |
| 
 | |
| auto counter::obj::operator<(obj const& o) const -> bool {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&o)) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_less;
 | |
|     }
 | |
|     return m_data < o.m_data;
 | |
| }
 | |
| 
 | |
| // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)
 | |
| auto counter::obj::operator=(obj const& o) -> counter::obj& {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&o)) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     m_counts = o.m_counts;
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_assign;
 | |
|     }
 | |
|     m_data = o.m_data;
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| auto counter::obj::operator=(obj&& o) noexcept -> counter::obj& {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&o)) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     if (nullptr != o.m_counts) {
 | |
|         m_counts = o.m_counts;
 | |
|     }
 | |
|     m_data = o.m_data;
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_move_assign;
 | |
|     }
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| auto counter::obj::get() const -> size_t const& {
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_const_get;
 | |
|     }
 | |
|     return m_data;
 | |
| }
 | |
| 
 | |
| auto counter::obj::get() -> size_t& {
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_get;
 | |
|     }
 | |
|     return m_data;
 | |
| }
 | |
| 
 | |
| void counter::obj::swap(obj& other) {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&other)) {
 | |
|             test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
|     using std::swap;
 | |
|     swap(m_data, other.m_data);
 | |
|     swap(m_counts, other.m_counts);
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_swaps;
 | |
|     }
 | |
| }
 | |
| 
 | |
| auto counter::obj::get_for_hash() const -> size_t {
 | |
|     if (nullptr != m_counts) {
 | |
|         ++m_counts->m_data.m_hash;
 | |
|     }
 | |
|     return m_data;
 | |
| }
 | |
| 
 | |
| counter::counter() {
 | |
|     counter::static_default_ctor = 0;
 | |
|     counter::static_dtor = 0;
 | |
| }
 | |
| 
 | |
| void counter::check_all_done() const {
 | |
|     if constexpr (counter_enable_unordered_set) {
 | |
|         // check that all are destructed
 | |
|         if (!singleton_constructed_objects().empty()) {
 | |
|             test::print("ERROR at ~counter(): got {} objects still alive!", singleton_constructed_objects().size());
 | |
|             std::abort();
 | |
|         }
 | |
| 
 | |
|         if (m_data.m_dtor + static_dtor !=
 | |
|             m_data.m_ctor + static_default_ctor + m_data.m_copy_ctor + m_data.m_default_ctor + m_data.m_move_ctor) {
 | |
|             test::print("ERROR at ~counter(): number of counts does not match!\n");
 | |
|             test::print(
 | |
|                 "{} dtor + {} staticDtor != {} ctor + {} staticDefaultCtor + {} copyCtor + {} defaultCtor + {} moveCtor\n",
 | |
|                 m_data.m_dtor,
 | |
|                 static_dtor,
 | |
|                 m_data.m_ctor,
 | |
|                 static_default_ctor,
 | |
|                 m_data.m_copy_ctor,
 | |
|                 m_data.m_default_ctor,
 | |
|                 m_data.m_move_ctor);
 | |
|             std::abort();
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| counter::~counter() {
 | |
|     check_all_done();
 | |
| }
 | |
| 
 | |
| auto counter::total() const -> size_t {
 | |
|     return m_data.m_ctor + static_default_ctor + m_data.m_copy_ctor + (m_data.m_dtor + static_dtor) + m_data.m_equals +
 | |
|            m_data.m_less + m_data.m_assign + m_data.m_swaps + m_data.m_get + m_data.m_const_get + m_data.m_hash +
 | |
|            m_data.m_move_ctor + m_data.m_move_assign;
 | |
| }
 | |
| 
 | |
| void counter::operator()(std::string_view title) {
 | |
|     m_records += fmt::format("{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}|{:9}| {}\n",
 | |
|                              m_data.m_ctor,
 | |
|                              static_default_ctor,
 | |
|                              m_data.m_copy_ctor,
 | |
|                              m_data.m_dtor + static_dtor,
 | |
|                              m_data.m_assign,
 | |
|                              m_data.m_swaps,
 | |
|                              m_data.m_get,
 | |
|                              m_data.m_const_get,
 | |
|                              m_data.m_hash,
 | |
|                              m_data.m_equals,
 | |
|                              m_data.m_less,
 | |
|                              m_data.m_move_ctor,
 | |
|                              m_data.m_move_assign,
 | |
|                              total(),
 | |
|                              title);
 | |
| }
 | |
| 
 | |
| auto operator<<(std::ostream& os, counter const& c) -> std::ostream& {
 | |
|     return os << c.m_records;
 | |
| }
 | |
| 
 | |
| auto operator new(size_t /*unused*/, counter::obj* /*unused*/) -> void* {
 | |
|     throw std::runtime_error("operator new overload is taken! Cast to void* to ensure the void pointer overload is taken.");
 | |
| }
 | |
| size_t counter::static_default_ctor = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | |
| size_t counter::static_dtor = 0;         // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 |