/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: LockGuardTry.hpp Date: 2021-12-25 Author: Reece ***/ #pragma once namespace Aurora::Threading { template class TryLockGuard { using Constless_t = T; using ConstlessPtr_t = AuConditional_t, Constless_t, Constless_t *>; using Internal_t = AuRemovePointer_t; static const bool kBoolArrowOp = AuOperatorArrow>::type::value; public: TryLockGuard(const T &lock) { ConstlessPtr_t pInterface {}; if constexpr (AuIsPointer_v) { pInterface = (ConstlessPtr_t)lock; } else { pInterface = (ConstlessPtr_t)&lock; } // TODO: In AuROXTL: [+] AuIsSharedPtr_v if constexpr (AuIsBaseOfTemplate::value || AuIsBaseOfTemplate::value) { if (pInterface->get()->TryLock()) { this->pAnnoying_ = pInterface; } } else if constexpr (kBoolArrowOp) { if ((*this->pAnnoying_)->TryLock()) { this->pAnnoying_ = pInterface; } } else { if (pInterface->TryLock()) { this->pAnnoying_ = pInterface; } } } ~TryLockGuard() { if (!this->pAnnoying_) { return; } if constexpr (AuIsBaseOfTemplate::value || AuIsBaseOfTemplate::value) { this->pAnnoying_->get()->Unlock(); } else if constexpr (kBoolArrowOp) { (*this->pAnnoying_)->Unlock(); } else { this->pAnnoying_->Unlock(); } } const bool Locked() const { return pAnnoying_ != 0; } private: ConstlessPtr_t pAnnoying_ {}; }; // Named try-lock guard. Use when you wish to poll ::Locked(), otherwise use the auto-return macros // There is no point in using anonymous lock handles w/o checking the lock state or auto-returning // Where variable = an iwaitable-like interface reference, pointer, or shared pointer; value = reference to a boolean // name = name of handle variable #define AU_TRY_LOCK_GUARD_NAMED(variable, name) Aurora::Threading::TryLockGuard name(variable); /// @hideinitializer #define AU_TRY_LOCK_GUARD_RET_NAMED(variable, value, name) AU_TRY_LOCK_GUARD_NAMED(variable, name) if (!(name.Locked())) return value; /// @hideinitializer #define AU_TRY_LOCK_GUARD_RET_COUNTERVAL(variable, value, counter) AU_TRY_LOCK_GUARD_RET_NAMED(variable, value, AU_CONCAT(__stack_lock, counter)) // where variable = an iwaitable-like interface reference, pointer, or shared pointer; value = reference to a boolean // value = failure return object #define AU_TRY_LOCK_GUARD_RET_VAL(variable, value) AU_TRY_LOCK_GUARD_RET_COUNTERVAL(variable, value, AU_WHAT(__COUNTER__)) // where variable = an iwaitable-like interface reference, pointer, or shared pointer #define AU_TRY_LOCK_GUARD_RET_DEF(variable) AU_TRY_LOCK_GUARD_RET_VAL(variable, {}) // where variable = an iwaitable-like interface reference, pointer #define AU_TRY_LOCK_GUARD_RET(variable) AU_TRY_LOCK_GUARD_RET_VAL(variable, ) }