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.
 
 
 
 

341 lignes
13 KiB

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