comptr.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #ifndef COMMON_COMPTR_H
  2. #define COMMON_COMPTR_H
  3. #ifdef _WIN32
  4. #include <cstddef>
  5. #include <utility>
  6. #define WIN32_LEAN_AND_MEAN
  7. #include <windows.h>
  8. #include <objbase.h>
  9. struct ComWrapper {
  10. HRESULT mStatus{};
  11. ComWrapper(void *reserved, DWORD coinit)
  12. : mStatus{CoInitializeEx(reserved, coinit)}
  13. { }
  14. explicit ComWrapper(DWORD coinit=COINIT_APARTMENTTHREADED)
  15. : mStatus{CoInitializeEx(nullptr, coinit)}
  16. { }
  17. ComWrapper(ComWrapper&& rhs) { mStatus = std::exchange(rhs.mStatus, E_FAIL); }
  18. ComWrapper(const ComWrapper&) = delete;
  19. ~ComWrapper() { if(SUCCEEDED(mStatus)) CoUninitialize(); }
  20. ComWrapper& operator=(ComWrapper&& rhs)
  21. {
  22. if(SUCCEEDED(mStatus))
  23. CoUninitialize();
  24. mStatus = std::exchange(rhs.mStatus, E_FAIL);
  25. return *this;
  26. }
  27. ComWrapper& operator=(const ComWrapper&) = delete;
  28. [[nodiscard]]
  29. HRESULT status() const noexcept { return mStatus; }
  30. explicit operator bool() const noexcept { return SUCCEEDED(status()); }
  31. void uninit()
  32. {
  33. if(SUCCEEDED(mStatus))
  34. CoUninitialize();
  35. mStatus = E_FAIL;
  36. }
  37. };
  38. template<typename T> /* NOLINTNEXTLINE(clazy-rule-of-three) False positive */
  39. struct ComPtr {
  40. using element_type = T;
  41. static constexpr bool RefIsNoexcept{noexcept(std::declval<T&>().AddRef())
  42. && noexcept(std::declval<T&>().Release())};
  43. ComPtr() noexcept = default;
  44. ComPtr(const ComPtr &rhs) noexcept(RefIsNoexcept) : mPtr{rhs.mPtr}
  45. { if(mPtr) mPtr->AddRef(); }
  46. ComPtr(ComPtr&& rhs) noexcept : mPtr{rhs.mPtr} { rhs.mPtr = nullptr; }
  47. ComPtr(std::nullptr_t) noexcept { } /* NOLINT(google-explicit-constructor) */
  48. explicit ComPtr(T *ptr) noexcept : mPtr{ptr} { }
  49. ~ComPtr() { if(mPtr) mPtr->Release(); }
  50. /* NOLINTNEXTLINE(bugprone-unhandled-self-assignment) Yes it is. */
  51. ComPtr& operator=(const ComPtr &rhs) noexcept(RefIsNoexcept)
  52. {
  53. if constexpr(RefIsNoexcept)
  54. {
  55. if(rhs.mPtr) rhs.mPtr->AddRef();
  56. if(mPtr) mPtr->Release();
  57. mPtr = rhs.mPtr;
  58. return *this;
  59. }
  60. else
  61. {
  62. ComPtr tmp{rhs};
  63. if(mPtr) mPtr->Release();
  64. mPtr = tmp.release();
  65. return *this;
  66. }
  67. }
  68. ComPtr& operator=(ComPtr&& rhs) noexcept(RefIsNoexcept)
  69. {
  70. if(&rhs != this)
  71. {
  72. if(mPtr) mPtr->Release();
  73. mPtr = std::exchange(rhs.mPtr, nullptr);
  74. }
  75. return *this;
  76. }
  77. void reset(T *ptr=nullptr) noexcept(RefIsNoexcept)
  78. {
  79. if(mPtr) mPtr->Release();
  80. mPtr = ptr;
  81. }
  82. explicit operator bool() const noexcept { return mPtr != nullptr; }
  83. T& operator*() const noexcept { return *mPtr; }
  84. T* operator->() const noexcept { return mPtr; }
  85. T* get() const noexcept { return mPtr; }
  86. T* release() noexcept { return std::exchange(mPtr, nullptr); }
  87. void swap(ComPtr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
  88. void swap(ComPtr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
  89. private:
  90. T *mPtr{nullptr};
  91. };
  92. #endif /* _WIN32 */
  93. #endif