cmUVHandlePtr.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #pragma once
  4. #include "cmConfigure.h" // IWYU pragma: keep
  5. #include <algorithm>
  6. #include <cstddef>
  7. #include <memory>
  8. #include <type_traits>
  9. #include "cm_uv.h"
  10. #define CM_PERFECT_FWD_CTOR(Class, FwdTo) \
  11. template <typename... Args> \
  12. Class(Args&&... args) \
  13. : FwdTo(std::forward<Args>(args)...) \
  14. { \
  15. }
  16. namespace cm {
  17. /***
  18. * RAII class to simplify and insure the safe usage of uv_*_t types. This
  19. * includes making sure resources are properly freed and contains casting
  20. * operators which allow for passing into relevant uv_* functions.
  21. *
  22. *@tparam T actual uv_*_t type represented.
  23. */
  24. template <typename T>
  25. class uv_handle_ptr_base_
  26. {
  27. protected:
  28. template <typename _T>
  29. friend class uv_handle_ptr_base_;
  30. /**
  31. * This must be a pointer type since the handle can outlive this class.
  32. * When uv_close is eventually called on the handle, the memory the
  33. * handle inhabits must be valid until the close callback is called
  34. * which can be later on in the loop.
  35. */
  36. std::shared_ptr<T> handle;
  37. /**
  38. * Allocate memory for the type and optionally set it's 'data' pointer.
  39. * Protected since this should only be called for an appropriate 'init'
  40. * call.
  41. *
  42. * @param data data pointer to set
  43. */
  44. void allocate(void* data = nullptr);
  45. public:
  46. CM_DISABLE_COPY(uv_handle_ptr_base_)
  47. uv_handle_ptr_base_(uv_handle_ptr_base_&&) noexcept;
  48. uv_handle_ptr_base_& operator=(uv_handle_ptr_base_&&) noexcept;
  49. /**
  50. * This move constructor allows us to move out of a more specialized
  51. * uv type into a less specialized one. The only constraint is that
  52. * the right hand side is castable to T.
  53. *
  54. * This allows you to return uv_handle_ptr or uv_stream_ptr from a function
  55. * that initializes something like uv_pipe_ptr or uv_tcp_ptr and interact
  56. * and clean up after it without caring about the exact type.
  57. */
  58. template <typename S, typename = typename std::enable_if<
  59. std::is_rvalue_reference<S&&>::value>::type>
  60. uv_handle_ptr_base_(S&& rhs)
  61. {
  62. // This will force a compiler error if rhs doesn't have a casting
  63. // operator to get T*
  64. this->handle = std::shared_ptr<T>(rhs.handle, rhs);
  65. rhs.handle.reset();
  66. }
  67. // Dtor and ctor need to be inline defined like this for default ctors and
  68. // dtors to work.
  69. uv_handle_ptr_base_() {}
  70. uv_handle_ptr_base_(std::nullptr_t) {}
  71. ~uv_handle_ptr_base_() { reset(); }
  72. /**
  73. * Properly close the handle if needed and sets the inner handle to nullptr
  74. */
  75. void reset();
  76. /**
  77. * Allow less verbose calling of uv_handle_* functions
  78. * @return reinterpreted handle
  79. */
  80. operator uv_handle_t*();
  81. T* get() const;
  82. T* operator->() const noexcept;
  83. };
  84. template <typename T>
  85. inline uv_handle_ptr_base_<T>::uv_handle_ptr_base_(
  86. uv_handle_ptr_base_<T>&&) noexcept = default;
  87. template <typename T>
  88. inline uv_handle_ptr_base_<T>& uv_handle_ptr_base_<T>::operator=(
  89. uv_handle_ptr_base_<T>&&) noexcept = default;
  90. /**
  91. * While uv_handle_ptr_base_ only exposes uv_handle_t*, this exposes uv_T_t*
  92. * too. It is broken out like this so we can reuse most of the code for the
  93. * uv_handle_ptr class.
  94. */
  95. template <typename T>
  96. class uv_handle_ptr_ : public uv_handle_ptr_base_<T>
  97. {
  98. template <typename _T>
  99. friend class uv_handle_ptr_;
  100. public:
  101. CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<T>);
  102. /***
  103. * Allow less verbose calling of uv_<T> functions
  104. * @return reinterpreted handle
  105. */
  106. operator T*() const;
  107. };
  108. /***
  109. * This specialization is required to avoid duplicate 'operator uv_handle_t*()'
  110. * declarations
  111. */
  112. template <>
  113. class uv_handle_ptr_<uv_handle_t> : public uv_handle_ptr_base_<uv_handle_t>
  114. {
  115. public:
  116. CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<uv_handle_t>);
  117. };
  118. class uv_async_ptr : public uv_handle_ptr_<uv_async_t>
  119. {
  120. public:
  121. CM_PERFECT_FWD_CTOR(uv_async_ptr, uv_handle_ptr_<uv_async_t>);
  122. int init(uv_loop_t& loop, uv_async_cb async_cb, void* data = nullptr);
  123. void send();
  124. };
  125. struct uv_signal_ptr : public uv_handle_ptr_<uv_signal_t>
  126. {
  127. CM_PERFECT_FWD_CTOR(uv_signal_ptr, uv_handle_ptr_<uv_signal_t>);
  128. int init(uv_loop_t& loop, void* data = nullptr);
  129. int start(uv_signal_cb cb, int signum);
  130. void stop();
  131. };
  132. struct uv_pipe_ptr : public uv_handle_ptr_<uv_pipe_t>
  133. {
  134. CM_PERFECT_FWD_CTOR(uv_pipe_ptr, uv_handle_ptr_<uv_pipe_t>);
  135. operator uv_stream_t*() const;
  136. int init(uv_loop_t& loop, int ipc, void* data = nullptr);
  137. };
  138. struct uv_tty_ptr : public uv_handle_ptr_<uv_tty_t>
  139. {
  140. CM_PERFECT_FWD_CTOR(uv_tty_ptr, uv_handle_ptr_<uv_tty_t>);
  141. operator uv_stream_t*() const;
  142. int init(uv_loop_t& loop, int fd, int readable, void* data = nullptr);
  143. };
  144. typedef uv_handle_ptr_<uv_stream_t> uv_stream_ptr;
  145. typedef uv_handle_ptr_<uv_handle_t> uv_handle_ptr;
  146. #ifndef cmUVHandlePtr_cxx
  147. extern template class uv_handle_ptr_base_<uv_handle_t>;
  148. #define UV_HANDLE_PTR_INSTANTIATE_EXTERN(NAME) \
  149. extern template class uv_handle_ptr_base_<uv_##NAME##_t>; \
  150. extern template class uv_handle_ptr_<uv_##NAME##_t>;
  151. UV_HANDLE_PTR_INSTANTIATE_EXTERN(async)
  152. UV_HANDLE_PTR_INSTANTIATE_EXTERN(signal)
  153. UV_HANDLE_PTR_INSTANTIATE_EXTERN(pipe)
  154. UV_HANDLE_PTR_INSTANTIATE_EXTERN(stream)
  155. UV_HANDLE_PTR_INSTANTIATE_EXTERN(tty)
  156. #undef UV_HANDLE_PTR_INSTANTIATE_EXTERN
  157. #endif
  158. }