Use kAudioObjectPropertyElementMaster on macOS for compatibility
[openal-soft.git] / common / comptr.h
blob0567d1e172ba2ab602680ea75be71ff5c36415ae
1 #ifndef COMMON_COMPTR_H
2 #define COMMON_COMPTR_H
4 #include <cstddef>
5 #include <memory>
6 #include <type_traits>
7 #include <utility>
8 #include <variant>
10 #define WIN32_LEAN_AND_MEAN
11 #include <windows.h>
12 #include <objbase.h>
14 struct ComWrapper {
15 HRESULT mStatus{};
17 ComWrapper(void *reserved, DWORD coinit)
18 : mStatus{CoInitializeEx(reserved, coinit)}
19 { }
20 ComWrapper(DWORD coinit=COINIT_APARTMENTTHREADED)
21 : mStatus{CoInitializeEx(nullptr, coinit)}
22 { }
23 ComWrapper(ComWrapper&& rhs) { mStatus = std::exchange(rhs.mStatus, E_FAIL); }
24 ComWrapper(const ComWrapper&) = delete;
25 ~ComWrapper() { if(SUCCEEDED(mStatus)) CoUninitialize(); }
27 ComWrapper& operator=(ComWrapper&& rhs)
29 if(SUCCEEDED(mStatus))
30 CoUninitialize();
31 mStatus = std::exchange(rhs.mStatus, E_FAIL);
32 return *this;
34 ComWrapper& operator=(const ComWrapper&) = delete;
36 [[nodiscard]]
37 HRESULT status() const noexcept { return mStatus; }
38 explicit operator bool() const noexcept { return SUCCEEDED(status()); }
40 void uninit()
42 if(SUCCEEDED(mStatus))
43 CoUninitialize();
44 mStatus = E_FAIL;
49 template<typename T> /* NOLINTNEXTLINE(clazy-rule-of-three) False positive */
50 struct ComPtr {
51 using element_type = T;
53 static constexpr bool RefIsNoexcept{noexcept(std::declval<T&>().AddRef())
54 && noexcept(std::declval<T&>().Release())};
56 ComPtr() noexcept = default;
57 ComPtr(const ComPtr &rhs) noexcept(RefIsNoexcept) : mPtr{rhs.mPtr}
58 { if(mPtr) mPtr->AddRef(); }
59 ComPtr(ComPtr&& rhs) noexcept : mPtr{rhs.mPtr} { rhs.mPtr = nullptr; }
60 ComPtr(std::nullptr_t) noexcept { }
61 explicit ComPtr(T *ptr) noexcept : mPtr{ptr} { }
62 ~ComPtr() { if(mPtr) mPtr->Release(); }
64 /* NOLINTNEXTLINE(bugprone-unhandled-self-assignment) Yes it is. */
65 ComPtr& operator=(const ComPtr &rhs) noexcept(RefIsNoexcept)
67 if constexpr(RefIsNoexcept)
69 if(rhs.mPtr) rhs.mPtr->AddRef();
70 if(mPtr) mPtr->Release();
71 mPtr = rhs.mPtr;
72 return *this;
74 else
76 ComPtr tmp{rhs};
77 if(mPtr) mPtr->Release();
78 mPtr = tmp.release();
79 return *this;
82 ComPtr& operator=(ComPtr&& rhs) noexcept(RefIsNoexcept)
84 if(&rhs != this)
86 if(mPtr) mPtr->Release();
87 mPtr = std::exchange(rhs.mPtr, nullptr);
89 return *this;
92 void reset(T *ptr=nullptr) noexcept(RefIsNoexcept)
94 if(mPtr) mPtr->Release();
95 mPtr = ptr;
98 explicit operator bool() const noexcept { return mPtr != nullptr; }
100 T& operator*() const noexcept { return *mPtr; }
101 T* operator->() const noexcept { return mPtr; }
102 T* get() const noexcept { return mPtr; }
104 T* release() noexcept { return std::exchange(mPtr, nullptr); }
106 void swap(ComPtr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
107 void swap(ComPtr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
109 private:
110 T *mPtr{nullptr};
113 #endif