/*** 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 struct AuOperatorArrow { template static constexpr AuTrueType Test(decltype(&C::operator->)); template static constexpr AuFalseType Test(...); using type = decltype(Test(0)); }; template class LockGuard { 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: LockGuard(const T &lock) { ConstlessPtr_t pInterface {}; if constexpr (AuIsPointer_v) { pInterface = (ConstlessPtr_t)lock; } else { pInterface = (ConstlessPtr_t)&lock; } if constexpr (AuIsBaseOfTemplate::value || AuIsBaseOfTemplate::value) { pInterface->get()->Lock(); } else if constexpr (kBoolArrowOp) { (*pInterface)->Lock(); } else { pInterface->Lock(); } this->pAnnoying_ = pInterface; } ~LockGuard() { 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(); } } private: ConstlessPtr_t pAnnoying_ {}; }; #define AU_LOCK_GUARD(variable) Aurora::Threading::LockGuard AU_CONCAT(__stack_lock, __COUNTER__) (variable); }