aboutsummaryrefslogtreecommitdiffstats
path: root/common/comptr.h
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-11-28 12:51:46 +0100
committerSven Gothel <[email protected]>2023-11-28 12:51:46 +0100
commit1aaf4f070011490bcece50394b9b32dfa593fd9e (patch)
tree17d68284e401a35eea3d3a574d986d446a60763a /common/comptr.h
parent6e7cee4fa9a8af03f28ca26cd89f8357390dfc90 (diff)
parent571b546f35eead77ce109f8d4dd6c3de3199d573 (diff)
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'common/comptr.h')
-rw-r--r--common/comptr.h129
1 files changed, 105 insertions, 24 deletions
diff --git a/common/comptr.h b/common/comptr.h
index cdc6dec0..9f8fd294 100644
--- a/common/comptr.h
+++ b/common/comptr.h
@@ -2,49 +2,84 @@
#define COMMON_COMPTR_H
#include <cstddef>
+#include <memory>
+#include <type_traits>
#include <utility>
+#include <variant>
-#include "opthelpers.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <objbase.h>
+
+struct ComWrapper {
+ HRESULT mStatus{};
+
+ ComWrapper(void *reserved, DWORD coinit)
+ : mStatus{CoInitializeEx(reserved, coinit)}
+ { }
+ ComWrapper(DWORD coinit=COINIT_APARTMENTTHREADED)
+ : mStatus{CoInitializeEx(nullptr, coinit)}
+ { }
+ ComWrapper(ComWrapper&& rhs) { mStatus = std::exchange(rhs.mStatus, E_FAIL); }
+ ComWrapper(const ComWrapper&) = delete;
+ ~ComWrapper() { if(SUCCEEDED(mStatus)) CoUninitialize(); }
+
+ ComWrapper& operator=(ComWrapper&& rhs)
+ {
+ if(SUCCEEDED(mStatus))
+ CoUninitialize();
+ mStatus = std::exchange(rhs.mStatus, E_FAIL);
+ return *this;
+ }
+ ComWrapper& operator=(const ComWrapper&) = delete;
+
+ HRESULT status() const noexcept { return mStatus; }
+ explicit operator bool() const noexcept { return SUCCEEDED(status()); }
+
+ void uninit()
+ {
+ if(SUCCEEDED(mStatus))
+ CoUninitialize();
+ mStatus = E_FAIL;
+ }
+};
template<typename T>
-class ComPtr {
- T *mPtr{nullptr};
+struct ComPtr {
+ using element_type = T;
+
+ static constexpr bool RefIsNoexcept{noexcept(std::declval<T&>().AddRef())
+ && noexcept(std::declval<T&>().Release())};
-public:
ComPtr() noexcept = default;
- ComPtr(const ComPtr &rhs) : mPtr{rhs.mPtr} { if(mPtr) mPtr->AddRef(); }
+ ComPtr(const ComPtr &rhs) noexcept(RefIsNoexcept) : mPtr{rhs.mPtr}
+ { if(mPtr) mPtr->AddRef(); }
ComPtr(ComPtr&& rhs) noexcept : mPtr{rhs.mPtr} { rhs.mPtr = nullptr; }
ComPtr(std::nullptr_t) noexcept { }
explicit ComPtr(T *ptr) noexcept : mPtr{ptr} { }
~ComPtr() { if(mPtr) mPtr->Release(); }
- ComPtr& operator=(const ComPtr &rhs)
+ ComPtr& operator=(const ComPtr &rhs) noexcept(RefIsNoexcept)
{
- if(!rhs.mPtr)
+ if constexpr(RefIsNoexcept)
{
- if(mPtr)
- mPtr->Release();
- mPtr = nullptr;
+ if(rhs.mPtr) rhs.mPtr->AddRef();
+ if(mPtr) mPtr->Release();
+ mPtr = rhs.mPtr;
+ return *this;
}
else
{
- rhs.mPtr->AddRef();
- try {
- if(mPtr)
- mPtr->Release();
- mPtr = rhs.mPtr;
- }
- catch(...) {
- rhs.mPtr->Release();
- throw;
- }
+ ComPtr tmp{rhs};
+ if(mPtr) mPtr->Release();
+ mPtr = tmp.release();
+ return *this;
}
- return *this;
}
- ComPtr& operator=(ComPtr&& rhs)
+ ComPtr& operator=(ComPtr&& rhs) noexcept(RefIsNoexcept)
{
- if(&rhs != this) LIKELY
+ if(&rhs != this)
{
if(mPtr) mPtr->Release();
mPtr = std::exchange(rhs.mPtr, nullptr);
@@ -52,17 +87,63 @@ public:
return *this;
}
+ void reset(T *ptr=nullptr) noexcept(RefIsNoexcept)
+ {
+ if(mPtr) mPtr->Release();
+ mPtr = ptr;
+ }
+
explicit operator bool() const noexcept { return mPtr != nullptr; }
T& operator*() const noexcept { return *mPtr; }
T* operator->() const noexcept { return mPtr; }
T* get() const noexcept { return mPtr; }
- T** getPtr() noexcept { return &mPtr; }
T* release() noexcept { return std::exchange(mPtr, nullptr); }
void swap(ComPtr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
void swap(ComPtr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
+
+private:
+ T *mPtr{nullptr};
+};
+
+
+namespace al {
+
+template<typename SP, typename PT, typename ...Args>
+class out_ptr_t {
+ static_assert(!std::is_same_v<PT,void*>);
+
+ SP &mRes;
+ std::variant<PT,void*> mPtr{};
+
+public:
+ out_ptr_t(SP &res) : mRes{res} { }
+ ~out_ptr_t()
+ {
+ auto set_res = [this](auto &ptr)
+ { mRes.reset(static_cast<PT>(ptr)); };
+ std::visit(set_res, mPtr);
+ }
+ out_ptr_t(const out_ptr_t&) = delete;
+
+ out_ptr_t& operator=(const out_ptr_t&) = delete;
+
+ operator PT*() noexcept
+ { return &std::get<PT>(mPtr); }
+
+ operator void**() noexcept
+ { return &mPtr.template emplace<void*>(); }
};
+template<typename T=void, typename SP, typename ...Args>
+auto out_ptr(SP &res)
+{
+ using ptype = typename SP::element_type*;
+ return out_ptr_t<SP,ptype>{res};
+}
+
+} // namespace al
+
#endif