uvcc
libuv C++ bindings
request-base.hpp
1 
2 #ifndef UVCC_REQUEST_BASE__HPP
3 #define UVCC_REQUEST_BASE__HPP
4 
5 #include "uvcc/debug.hpp"
6 #include "uvcc/utility.hpp"
7 
8 #include <cstddef> // size_t offsetof
9 #include <cstdint> // uintptr_t
10 #include <cstring> // memset()
11 #include <uv.h>
12 
13 #include <functional> // function
14 #include <type_traits> // is_standard_layout
15 #include <utility> // forward() swap()
16 
17 
18 namespace uv
19 {
20 
21 
22 /*! \ingroup doxy_group__request
23  \brief The base class for the libuv requests.
24  \details Derived classes conceptually are just interfaces to the data stored
25  in the base class, so there are no any virtual member functions.
26  \sa libuv API documentation: [`uv_req_t` — Base request](http://docs.libuv.org/en/v1.x/request.html#uv-req-t-base-request). */
27 class request
28 {
29 public: /*types*/
30  using uv_t = ::uv_req_t;
31  using on_destroy_t = std::function< void(void *_data) >;
32  /*!< \brief The function type of the callback called when the request object is about to be destroyed. */
33 
34 protected: /*types*/
35  //! \cond internals
36  //! \addtogroup doxy_group__internals
37  //! \{
38 
39  struct properties {};
40  constexpr static const std::size_t MAX_PROPERTY_SIZE = 24 + sizeof(::sockaddr_storage);
41  constexpr static const std::size_t MAX_PROPERTY_ALIGN = 8;
42 
43  template< class _Request_ > class instance
44  {
45  struct uv_t
46  {
47  template< typename _T_, typename = std::size_t > struct substitute { using type = void; };
48  template< typename _T_ > struct substitute< _T_, decltype(sizeof(typename _T_::uv_t)) > { using type = typename _T_::uv_t; };
49  using type = typename substitute< _Request_ >::type;
50  };
51  struct on_request_t
52  {
53  template< typename _T_, typename = std::size_t > struct substitute { using type = std::function< void() >; };
54  template< typename _T_ > struct substitute< _T_, decltype(sizeof(typename _T_::on_request_t)) > { using type = typename _T_::on_request_t; };
55  using type = typename substitute< _Request_ >::type;
56  };
57 
58  public: /*data*/
59  mutable int uv_error = 0;
60  ref_count refs;
61  type_storage< on_destroy_t > destroy_cb_storage;
62  type_storage< typename on_request_t::type > request_cb_storage; // XXX : ensure this field is of immutable layout size
63  aligned_storage< MAX_PROPERTY_SIZE, MAX_PROPERTY_ALIGN > property_storage;
64  //* all the fields placed before should have immutable layout size across the request class hierarchy *//
65  alignas(::uv_any_req) typename uv_t::type uv_req_struct;
66 
67  private: /*constructors*/
68  instance()
69  {
70  std::memset(&uv_req_struct, 0, sizeof(uv_req_struct));
71  property_storage.reset< typename _Request_::properties >();
72  }
73  template< typename... _Args_ > instance(_Args_&&... _args)
74  {
75  std::memset(&uv_req_struct, 0, sizeof(uv_req_struct));
76  property_storage.reset< typename _Request_::properties >(std::forward< _Args_ >(_args)...);
77  }
78 
79  public: /*constructors*/
80  ~instance() = default;
81 
82  instance(const instance&) = delete;
83  instance& operator =(const instance&) = delete;
84 
85  instance(instance&&) = delete;
86  instance& operator =(instance&&) = delete;
87 
88  private: /*functions*/
89  void destroy_instance()
90  {
91  auto &destroy_cb = destroy_cb_storage.value();
92  if (destroy_cb) destroy_cb(uv_req_struct.data);
93 
94  delete this;
95  }
96 
97  public: /*interface*/
98  static void* create() { return &(new instance)->uv_req_struct; }
99  template< typename... _Args_ > static void* create(_Args_&&... _args)
100  {
101  return &(new instance(std::forward< _Args_ >(_args)...))->uv_req_struct;
102  }
103 
104  constexpr static instance* from(void *_uv_req) noexcept
105  {
106  static_assert(std::is_standard_layout< instance >::value, "not a standard layout type");
107  return reinterpret_cast< instance* >(static_cast< char* >(_uv_req) - offsetof(instance, uv_req_struct));
108  }
109 
110  typename _Request_::properties& properties() noexcept
111  { return property_storage.get< typename _Request_::properties >(); }
112 
113  void ref() { refs.inc(); }
114  void unref() { if (refs.dec() == 0) destroy_instance(); }
115  };
116  //! \cond
117  template< class _Request_ > friend typename _Request_::instance* debug::instance(_Request_&) noexcept;
118  //! \endcond
119 
120  //! \}
121  //! \endcond
122 
123 protected: /*data*/
124  //! \cond
125  void *uv_req;
126  //! \endcond
127 
128 protected: /*constructors*/
129  //! \cond
130  request() noexcept : uv_req(nullptr) {}
131 
132  explicit request(uv_t *_uv_req)
133  {
134  if (_uv_req) instance< request >::from(_uv_req)->ref();
135  uv_req = _uv_req;
136  }
137  //! \endcond
138 
139 public: /*constructors*/
140  ~request() { if (uv_req) instance< request >::from(uv_req)->unref(); }
141 
142  request(const request &_that) : request(static_cast< uv_t* >(_that.uv_req)) {}
143  request& operator =(const request &_that)
144  {
145  if (this != &_that)
146  {
147  if (_that.uv_req) instance< request >::from(_that.uv_req)->ref();
148  auto t = uv_req;
149  uv_req = _that.uv_req;
150  if (t) instance< request >::from(t)->unref();
151  }
152  return *this;
153  }
154 
155  request(request &&_that) noexcept : uv_req(_that.uv_req) { _that.uv_req = nullptr; }
156  request& operator =(request &&_that) noexcept
157  {
158  if (this != &_that)
159  {
160  auto t = uv_req;
161  uv_req = _that.uv_req;
162  _that.uv_req = nullptr;
163  if (t) instance< request >::from(t)->unref();
164  }
165  return *this;
166  }
167 
168 protected: /*functions*/
169  //! \cond
170  int uv_status(int _value) const noexcept
171  {
172  instance< request >::from(uv_req)->uv_error = _value;
173  return _value;
174  }
175  //! \endcond
176 
177 public: /*interface*/
178  void swap(request &_that) noexcept { std::swap(uv_req, _that.uv_req); }
179  std::uintptr_t id() const noexcept { return reinterpret_cast< std::uintptr_t >(instance< request >::from(uv_req)); }
180 
181  /*! \brief The current number of existing references to the same object as this request variable refers to. */
182  long nrefs() const noexcept { return instance< request >::from(uv_req)->refs.get_value(); }
183 
184  /*! \brief The status value returned by the last executed libuv API function on this request. */
185  int uv_status() const noexcept { return instance< request >::from(uv_req)->uv_error; }
186 
187  on_destroy_t& on_destroy() const noexcept { return instance< request >::from(uv_req)->destroy_cb_storage.value(); }
188 
189  /*! \brief The tag indicating a libuv type of the request.
190  \sa libuv API documentation: [`uv_req_t.type`](http://docs.libuv.org/en/v1.x/request.html#c.uv_req_t.type). */
191  ::uv_req_type type() const noexcept { return static_cast< uv_t* >(uv_req)->type; }
192  /*! \brief A string containing the name of the request type. */
193  const char* type_name() const noexcept
194  {
195  const char *ret;
196 
197  switch (type())
198  {
199 #define XX(X, x) case UV_##X: ret = #x; break;
200  UV_REQ_TYPE_MAP(XX)
201 #undef XX
202  default: ret = "<unknown>"; break;
203  }
204 
205  return ret;
206  }
207 
208  /*! \brief The pointer to the user-defined arbitrary data. libuv and uvcc does not use this field. */
209  void* const& data() const noexcept { return static_cast< uv_t* >(uv_req)->data; }
210  void* & data() noexcept { return static_cast< uv_t* >(uv_req)->data; }
211 
212  /*! \brief Cancel a pending request.
213  \sa libuv API documentation: [`uv_cancel()`](http://docs.libuv.org/en/v1.x/request.html#c.uv_cancel).*/
214  int cancel() noexcept { return ::uv_cancel(static_cast< uv_t* >(uv_req)); }
215 
216 public: /*conversion operators*/
217  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
218  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
220  explicit operator bool() const noexcept { return (uv_status() >= 0); } /*!< \brief Equivalent to `(uv_status() >= 0)`. */
221 };
222 
223 
224 }
225 
226 
227 namespace std
228 {
229 
230 //! \ingroup doxy_group__request
231 template<> inline void swap(uv::request &_this, uv::request &_that) noexcept { _this.swap(_that); }
232 
233 }
234 
235 
236 #endif
Namespace for all uvcc definitions.
Definition: buffer.hpp:17
The base class for the libuv requests.
A wrapper providing the feature of being a standard layout type for the given type _T_...
Definition: utility.hpp:475
const char * type_name() const noexcept
A string containing the name of the request type.
long nrefs() const noexcept
The current number of existing references to the same object as this request variable refers to...
int uv_status() const noexcept
The status value returned by the last executed libuv API function on this request.
A reference counter with atomic increment/decrement.
Definition: utility.hpp:229
::uv_req_type type() const noexcept
The tag indicating a libuv type of the request.