/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: LockGuard.hpp Date: 2021-6-10 Author: Reece ***/ #pragma once namespace Aurora::Threading { template class TryLockGuard { private: using Internal_t = std::remove_pointer_t; bool bLockSuccessful; public: TryLockGuard(T &lock) { if constexpr (std::is_pointer_v) { annoying_ = lock; } else { annoying_ = &lock; } if constexpr (AuIsBaseOfTemplate::value || AuIsBaseOfTemplate::value) { bLockSuccessful = annoying_->get()->TryLock(); } else { bLockSuccessful = annoying_->TryLock(); } } TryLockGuard(T &&lock) { if constexpr (std::is_pointer_v) { annoying_ = lock; } else { annoying_ = &lock; } if constexpr (AuIsBaseOfTemplate::value || AuIsBaseOfTemplate::value) { bLockSuccessful = annoying_->get()->TryLock(); } else { bLockSuccessful = annoying_->TryLock(); } } ~TryLockGuard() { if (!bLockSuccessful) { return; } if constexpr (AuIsBaseOfTemplate::value || AuIsBaseOfTemplate::value) { annoying_->get()->Unlock(); } else { annoying_->Unlock(); } } const bool Locked() const { return bLockSuccessful; } private: std::conditional_t, T, T*> annoying_; }; #define AU_TRY_LOCK_GUARD(variable) Aurora::Threading::TryLockGuard AU_CONCAT(__stack_lock, __COUNTER__) (variable); #define AU_TRY_LOCK_GUARD_RET_NAMED(variable, value, name) Aurora::Threading::TryLockGuard name (variable); if (!(name.Locked())) return value; #define AU_TRY_LOCK_GUARD_RET(variable, value, counter) AU_TRY_LOCK_GUARD_RET_NAMED(variable, value, AU_CONCAT(__stack_lock, counter)) #define AU_TRY_LOCK_GUARD_RET_VAL(variable, value) AU_TRY_LOCK_GUARD_RET_NAMED(variable, value, AU_WHAT(__COUNTER__)) #define AU_TRY_LOCK_GUARD_RET_DEF(variable) AU_TRY_LOCK_GUARD_RET_VAL(variable, {}) #define AU_TRY_LOCK_GUARD_RET(variable) AU_TRY_LOCK_GUARD_RET_VAL(variable, ) #define AU_TRY_LOCK_GUARD_NAMED(variable, name) AU_TRY_LOCK_GUARD_RET_NAMED(variable, , name) }2