| #define TROMPELOEIL_PARAMS(num) TROMPELOEIL_CONCAT(TROMPELOEIL_PARAMS, num) | #define TROMPELOEIL_PARAMS(num) TROMPELOEIL_CONCAT(TROMPELOEIL_PARAMS, num) | ||||
| #if defined(__cxx_rtti) || defined(__GXX_RTTI) || defined(_CPPRTTI) | |||||
| # define TROMPELOEIL_TYPE_ID_NAME(x) typeid(x).name() | |||||
| #else | |||||
| # define TROMPELOEIL_TYPE_ID_NAME(x) "object" | |||||
| #endif | |||||
| #if (TROMPELOEIL_CPLUSPLUS == 201103L) | #if (TROMPELOEIL_CPLUSPLUS == 201103L) | ||||
| class specialized; | class specialized; | ||||
| namespace { | |||||
| inline | |||||
| const std::shared_ptr<std::recursive_mutex>& | |||||
| get_mutex_obj() | |||||
| { | |||||
| static auto obj = std::make_shared<std::recursive_mutex>(); | |||||
| return obj; | |||||
| } | |||||
| auto mutex_holder = get_mutex_obj(); | |||||
| } | |||||
| template <typename T> | |||||
| using aligned_storage_for = | |||||
| typename std::aligned_storage<sizeof(T), alignof(T)>::type; | |||||
| template <typename T = void> | template <typename T = void> | ||||
| std::unique_lock<std::recursive_mutex> get_lock() | std::unique_lock<std::recursive_mutex> get_lock() | ||||
| { | { | ||||
| return std::unique_lock<std::recursive_mutex>{ *get_mutex_obj() }; | |||||
| // Ugly hack for lifetime of mutex. The statically allocated | |||||
| // recursive_mutex is intentionally leaked, to ensure that the | |||||
| // mutex is available and valid even if the last use is from | |||||
| // the destructor of a global object in a translation unit | |||||
| // without #include <trompeloeil.hpp> | |||||
| static aligned_storage_for<std::recursive_mutex> buffer; | |||||
| static auto mutex = new (&buffer) std::recursive_mutex; | |||||
| return std::unique_lock<std::recursive_mutex>{*mutex}; | |||||
| } | } | ||||
| template <size_t N, typename T> | template <size_t N, typename T> | ||||
| , exp_loc(loc) | , exp_loc(loc) | ||||
| , seq(*i.second) | , seq(*i.second) | ||||
| { | { | ||||
| auto lock = get_lock(); | |||||
| seq.add_last(this); | seq.add_last(this); | ||||
| } | } | ||||
| } | } | ||||
| std::ostringstream os; | std::ostringstream os; | ||||
| os << "Unexpected destruction of " | os << "Unexpected destruction of " | ||||
| << typeid(T).name() << "@" << this << '\n'; | |||||
| << TROMPELOEIL_TYPE_ID_NAME(T) << "@" << this << '\n'; | |||||
| send_report<specialized>(severity::nonfatal, | send_report<specialized>(severity::nonfatal, | ||||
| location{}, | location{}, | ||||
| os.str()); | os.str()); |