Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

387 lines
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__ */