Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

387 lignes
14 KiB

  1. /*!
  2. * \file utl/dev/inbuf_dev.h
  3. * \brief Abstract base class interface for input buffered
  4. * devices of utl.
  5. *
  6. * Copyright (C) 2018 Christos Choutouridis
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as
  10. * published by the Free Software Foundation, either version 3
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #ifndef __utl_dev_inbuf_dev_h__
  23. #define __utl_dev_inbuf_dev_h__
  24. #include <utl/impl/impl.h>
  25. #include <utl/helper/crtp.h>
  26. #include <utl/meta/sfinae.h>
  27. #include <utl/dev/dev_iterators.h>
  28. namespace utl {
  29. /*!
  30. * \ingroup Device Interface
  31. * \brief Abstract base class for input buffered devices
  32. */
  33. //!@{
  34. /*!
  35. * \brief
  36. * Template base class for buffered input buffered devices. using CRTP
  37. *
  38. * This class force a common interface for input, buffered devices.
  39. * By using this common interface the class implements
  40. * - Stream-like extracting operator
  41. * - Input iterator
  42. * - Const input iterator
  43. * to inherit to implementation.
  44. *
  45. * \param impl_t The CRTP type (the derived/implementation class typename).
  46. * \param data_t The devices base type of data
  47. * \param streamsize The number of elements to indicate eos.
  48. * \arg None or 0 Stream only. No iterator as begin() now equals end().
  49. */
  50. template <typename impl_t, typename data_t, size_t streamsize =0>
  51. class inbuf_dev {
  52. _CRTP_IMPL(impl_t);
  53. using inbuf_dev_t = inbuf_dev <impl_t, data_t, streamsize>; //!< class type syntactic sugar
  54. //! Export types as input device concept demands
  55. //!@{
  56. public:
  57. using data_type = data_t;
  58. using pointer_type = data_t*;
  59. //!@}
  60. using type = inbuf_dev_t; //!< Export type as identity meta-function
  61. /*!
  62. * \name Constructor / Destructor
  63. */
  64. //!@{
  65. protected:
  66. ~inbuf_dev () = default; //!< \brief Allow destructor from derived only
  67. inbuf_dev () = default; //!< \brief A default constructor from derived only
  68. inbuf_dev(const inbuf_dev_t&) = delete; //!< No copies
  69. inbuf_dev_t& operator= (const inbuf_dev_t&) = delete; //!< No copy assignments
  70. //!@}
  71. //! \name Common input device interface requirements
  72. //!@{
  73. private:
  74. size_t in_avail_ () { return impl().in_avail_(); }
  75. size_t get_ (data_t& data) { return impl().get_(data); }
  76. size_t get_ (data_t* data, size_t n) { return impl().get_ (data, n); }
  77. //!@}
  78. /*!
  79. * \name Public Get interface
  80. */
  81. //!@{
  82. public:
  83. /*!
  84. * \return
  85. * The available @a data_t typed items in input buffer.
  86. */
  87. size_t in_avail () {
  88. return in_avail_ ();
  89. }
  90. /*!
  91. * \brief
  92. * The base get interface. This function should read
  93. * a single data_t object from device usually in non-blocking mode.
  94. * \param data Reference to data output from device.
  95. * \return Number of data read from device
  96. * \note
  97. * A successful call should return 1
  98. */
  99. size_t get (data_t& data) {
  100. return get_ (data);
  101. }
  102. /*!
  103. * \brief
  104. * Old stile get functionality using free standing data_t*.
  105. * This function should return a stream of data from device
  106. * \param data Pointer to buffer to write the data from device.
  107. * \param n The number of data of type data_t to read
  108. * \return The read data items.
  109. */
  110. size_t get (data_t* data, size_t n) {
  111. return get_ (data, n);
  112. }
  113. //!@}
  114. /*!
  115. * \name Stream operator >> interface
  116. */
  117. //!@{
  118. public:
  119. /*!
  120. * \brief
  121. * Template operator >> implementation for for all by value/ref parameters
  122. * \note
  123. * In the case _Dst_t size is not a integer multiple of device's data size
  124. * this will fail by static assertion
  125. * \param dst Reference to destination
  126. * \return Reference to this device for chaining
  127. */
  128. template <typename _Dst_t>
  129. inbuf_dev_t& operator>> (_Dst_t& dst) {
  130. static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0),
  131. "Target size must be an integer multiple of device's data size");
  132. get_ (reinterpret_cast<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t));
  133. return *this;
  134. }
  135. //! Specialization to disallow pointer types as destination
  136. template <typename _Dst_t>
  137. inbuf_dev_t& operator>> (_Dst_t* dst) = delete;
  138. //! Overload for single data_t object
  139. inbuf_dev_t& operator>> (data_t& dst) {
  140. get_ (dst);
  141. return *this;
  142. }
  143. //!@}
  144. /*!
  145. * \name STL-like Input iterator interface
  146. */
  147. //!@{
  148. using iterator = indev_it <inbuf_dev_t, data_t*, streamsize>; //!< Iterator
  149. using const_iterator = indev_it <inbuf_dev_t, const data_t*, streamsize>; //!< Const iterator
  150. //!@{ .begin implementation
  151. iterator begin () noexcept { return iterator(this, iterator::init); }
  152. const_iterator begin () const noexcept { return const_iterator(this, iterator::init); }
  153. const_iterator cbegin () const noexcept { return const_iterator(this, iterator::init); }
  154. //!@}
  155. //!@{ .end implementation
  156. iterator end () noexcept { return iterator(this, iterator::eos); }
  157. const_iterator end () const noexcept { return const_iterator(this, iterator::eos); }
  158. const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); }
  159. //!@}
  160. //!@}
  161. };
  162. /*!
  163. * \brief
  164. * A virtual base class specialization
  165. * \param impl_t = virtual_tag
  166. * \param data_t The devices base type of data
  167. * \param streamsize The number of elements to indicate eos.
  168. * \arg None or 0 Stream only. No iterator as begin() now equals end().
  169. */
  170. template <typename data_t, size_t streamsize>
  171. class inbuf_dev <virtual_tag, data_t, streamsize> {
  172. //!< class type syntactic sugar
  173. using inbuf_dev_t = inbuf_dev <virtual_tag, data_t, streamsize>;
  174. //! Export types as input device concept demands
  175. //!@{
  176. public:
  177. using data_type = data_t;
  178. using pointer_type = data_t*;
  179. //!@}
  180. using type = inbuf_dev_t; //!< Export type as identity meta-function
  181. /*!
  182. * \name Constructor / Destructor
  183. */
  184. //!@{
  185. public:
  186. virtual ~inbuf_dev () = default; //!< \brief Virtual destructor
  187. protected:
  188. inbuf_dev () = default; //!< \brief A default constructor from derived only
  189. inbuf_dev(const inbuf_dev_t&) = delete; //!< No copies
  190. inbuf_dev_t& operator= (const inbuf_dev_t&) = delete; //!< No copy assignments
  191. //!@}
  192. /*!
  193. * \name Common input device interface requirements
  194. */
  195. //!@{
  196. private:
  197. /*!
  198. * \return
  199. * The available @a data_t typed items in input buffer.
  200. */
  201. virtual size_t in_avail_ () = 0;
  202. /*!
  203. * \brief
  204. * The base get interface. This function should read
  205. * a single data_t object from device usually in non-blocking mode.
  206. * \param data Reference to data output from device.
  207. * \return Number of data read from device
  208. * \note
  209. * A successful call should return 1
  210. */
  211. virtual size_t get_ (data_t& data) = 0;
  212. /*!
  213. * \brief
  214. * Old stile get functionality using free standing data_t*.
  215. * This function should return a stream of data from device
  216. * \param data Pointer to buffer to write the data from device.
  217. * \param n The number of data of type data_t to read
  218. * \return The read data items.
  219. */
  220. virtual size_t get_ (data_t* data, size_t n) = 0;
  221. //!@}
  222. /*!
  223. * \name Public Get interface
  224. */
  225. //!@{
  226. public:
  227. size_t in_avail() { return in_avail_(); }
  228. size_t get (data_t& data) { return get_ (data); }
  229. size_t get (data_t* data, size_t n) { return get_ (data, n); }
  230. //!@}
  231. /*!
  232. * \name Stream operator >> interface
  233. */
  234. //!@{
  235. /*!
  236. * \brief
  237. * Template operator >> implementation for for all by value/ref parameters
  238. * \note
  239. * In the case _Dst_t size is not a integer multiple of device's data size
  240. * this will fail by static assertion
  241. * \param dst Reference to destination
  242. * \return Reference to this device for chaining
  243. */
  244. template <typename _Dst_t>
  245. inbuf_dev_t& operator>> (_Dst_t& dst) {
  246. static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0),
  247. "Target size must be an integer multiple of device's data size");
  248. get_ (reinterpret_cast<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t));
  249. return *this;
  250. }
  251. //! specialization to disallow pointer types as destination
  252. template <typename _Dst_t>
  253. inbuf_dev_t& operator>> (_Dst_t* dst) = delete;
  254. //! Overload for single data_t object
  255. inbuf_dev_t& operator>> (data_t& dst) {
  256. get_ (dst);
  257. return *this;
  258. }
  259. //!@}
  260. /*!
  261. * \name STL-like Input iterator interface
  262. */
  263. //!@{
  264. using iterator = indev_it <inbuf_dev_t, data_t*, streamsize>; //!< Iterator
  265. using const_iterator = indev_it <inbuf_dev_t, const data_t*, streamsize>; //!< Const iterator
  266. //!@{ .begin implementation
  267. iterator begin () noexcept { return iterator(this, iterator::init); }
  268. const_iterator begin () const noexcept { return const_iterator(this, iterator::init); }
  269. const_iterator cbegin () const noexcept { return const_iterator(this, iterator::init); }
  270. //!@}
  271. //!@{ .end implementation
  272. iterator end () noexcept { return iterator(this, iterator::eos); }
  273. const_iterator end () const noexcept { return const_iterator(this, iterator::eos); }
  274. const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); }
  275. //!@}
  276. //!@}
  277. };
  278. /*!
  279. * Input buffer device concept
  280. */
  281. //! @{
  282. #if defined _utl_have_concepts
  283. template <typename _Tp>
  284. concept bool Inbuf_dev = requires (_Tp t, const _Tp ct, typename _Tp::data_type v) {
  285. // Object type
  286. // requires std::is_default_constructible<_Tp>::value;
  287. requires !std::is_copy_constructible<_Tp>::value;
  288. requires !std::is_copy_assignable<_Tp>::value;
  289. // Methods
  290. {t.get(v, 0)} -> size_t;
  291. {t.get(&v, 1, 0)} -> size_t;
  292. // Operators
  293. t >> v;
  294. // Iterators
  295. typename _Tp::const_iterator; //XXX: change to concept: is_idxdev_iterator<_Tp>
  296. requires Indev_it<typename _Tp::iterator>;
  297. //requires Indev_it<typename _Tp::const_iterator>;
  298. { t.begin() } -> typename _Tp::iterator;
  299. // {ct.begin()} -> typename _Tp::const_iterator;
  300. // { t.cbegin()} -> typename _Tp::const_iterator;
  301. { t.end() } -> typename _Tp::iterator;
  302. // {ct.end()} -> typename _Tp::const_iterator;
  303. // { t.cend()} -> typename _Tp::const_iterator;
  304. };
  305. #else
  306. namespace inbuf_dev_details {
  307. using std::declval;
  308. // main api members
  309. template <class _Tp> using try_get1_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type&>()));
  310. template <class _Tp> using try_get2_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type*>(), declval<size_t>()));
  311. // operators
  312. //template <class _Tp> using try_extract_t= decltype (declval<_Tp>() >> declval<typename _Tp::data_type&>());
  313. // iterator members
  314. template <class _Tp> using try_begin_t = decltype (declval<_Tp>().begin());
  315. template <class _Tp> using tryc_begin_t = decltype (declval<const _Tp>().begin());
  316. template <class _Tp> using try_cbegin_t = decltype (declval<const _Tp>().cbegin());
  317. template <class _Tp> using try_end_t = decltype (declval<_Tp>().begin());
  318. template <class _Tp> using tryc_end_t = decltype (declval<const _Tp>().begin());
  319. template <class _Tp> using try_cend_t = decltype (declval<const _Tp>().cend());
  320. //! Primary template to catch any non input device types
  321. template <typename _Tp, typename =void>
  322. struct is_inbuf_dev_ : false_ {};
  323. //! template to catch a proper input device type
  324. template <typename _Tp>
  325. struct is_inbuf_dev_ <_Tp,
  326. void_t <
  327. typename _Tp::data_type,
  328. typename _Tp::pointer_type,
  329. typename _Tp::iterator,
  330. typename _Tp::const_iterator,
  331. use_if_same_t <try_get1_t <_Tp>, size_t>,
  332. use_if_same_t <try_get2_t <_Tp>, size_t>,
  333. //if_same_t <try_extract_t<_Tp>,typename _Tp&>,
  334. use_if_same_t <try_begin_t<_Tp>, typename _Tp::iterator>,
  335. use_if_same_t <tryc_begin_t<_Tp>, typename _Tp::const_iterator>,
  336. use_if_same_t <try_cbegin_t<_Tp>, typename _Tp::const_iterator>,
  337. use_if_same_t <try_end_t<_Tp>, typename _Tp::iterator>,
  338. use_if_same_t <tryc_end_t<_Tp>, typename _Tp::const_iterator>,
  339. use_if_same_t <try_cend_t<_Tp>, typename _Tp::const_iterator>
  340. >
  341. > : true_ {};
  342. }
  343. /*!
  344. * Predicate for input device checking
  345. * \param _Tp Type to check
  346. * \return True if _Tp is a input device
  347. */
  348. template <typename _Tp>
  349. constexpr bool Inbuf_dev = inbuf_dev_details::is_inbuf_dev_ <_Tp>::value;
  350. #endif
  351. //!@}
  352. }
  353. //!@}
  354. #endif /* #ifndef __utl_dev_inbuf_dev_h__ */