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.
 
 
 
 

365 lignes
14 KiB

  1. /*!
  2. * \file utl/dev/out_dev.h
  3. * \brief Abstract base class interface for output 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_out_dev_h__
  22. #define __utl_dev_out_dev_h__
  23. #include <utl/core/impl.h>
  24. #include <utl/core/crtp.h>
  25. #include <utl/dev/dev_iterators.h>
  26. #include <utl/meta/meta.h>
  27. namespace utl {
  28. /*!
  29. * \ingroup Device Interface
  30. * \brief Abstract base classes for output devices
  31. */
  32. //!@{
  33. /*!
  34. * \brief
  35. * Template base class for output devices. using CRTP
  36. *
  37. * This class force a common interface for output devices.
  38. * By using this common interface the class implements
  39. * - Stream-like inserting operator
  40. * - Output iterator
  41. * - Const output 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 out_dev {
  51. _CRTP_IMPL(impl_t);
  52. using out_dev_t = out_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 = out_dev_t; //!< Export type as identity meta-function
  60. /*!
  61. * \name Constructor / Destructor
  62. */
  63. //!@{
  64. protected:
  65. ~out_dev () = default; //!< \brief Allow destructor from derived only
  66. out_dev () = default; //!< \brief A default constructor from derived only
  67. out_dev(const out_dev_t&) = delete; //!< No copies
  68. out_dev_t& operator= (const out_dev_t&) = delete; //!< No copy assignments
  69. //!@}
  70. //! \name Common output device interface requirements
  71. //!@{
  72. private:
  73. size_t put_ (const data_t& data) { return impl().put_ (data); }
  74. size_t put_ (const data_t* data, size_t n) {
  75. return impl().put_ (data, n);
  76. }
  77. //!@}
  78. /*!
  79. * \name Common output device interface
  80. */
  81. //!@{
  82. public:
  83. /*!
  84. * \brief
  85. * Put interface. This function should send a single
  86. * data_t object to device.
  87. * \param data The data to send
  88. * \return The number of transmitted data items
  89. * \note
  90. * A successful call should return 1
  91. */
  92. size_t put (const data_t& data) {
  93. return put_ (data);
  94. }
  95. /*!
  96. * \brief
  97. * Put interface. This function should send a stream of
  98. * data_t objects to device.
  99. * \param data Pointer to buffer indenting write to device.
  100. * \param n The number of data of type data_t to send
  101. * \return The number of transmitted items.
  102. */
  103. size_t put (const data_t* data, size_t n) {
  104. return put_ (data, n);
  105. }
  106. //!@}
  107. /*!
  108. * \name Stream operator << interface
  109. */
  110. //!@{
  111. public:
  112. /*!
  113. * \brief
  114. * Template operator<< implementation for for all by value/ref parameters
  115. * \note
  116. * In the case _Src_t size is not an exact multiple of data_t size
  117. * the write data will be truncated and there may be data loss.
  118. * \param src Reference to source data
  119. * \return Reference to this device for chaining
  120. */
  121. template <typename _Src_t>
  122. out_dev_t& operator<< (_Src_t& src) {
  123. static_assert ((sizeof (_Src_t)%sizeof(data_t) == 0),
  124. "Source size must be an integer multiple of device's data size");
  125. put_ (reinterpret_cast<data_t*>(&src), sizeof(_Src_t)/sizeof(data_t));
  126. return *this;
  127. }
  128. //! Overload to disallow pointer types as source
  129. template <typename _Src_t>
  130. out_dev_t& operator<< (_Src_t* src) = delete;
  131. //! Overload for single data_t object
  132. out_dev_t& operator<< (const data_t& src) {
  133. put_ (src);
  134. return *this;
  135. }
  136. //!@}
  137. /*!
  138. * \name STL-like Output iterator interface
  139. */
  140. //!@{
  141. using iterator = outdev_it <out_dev_t, data_t*, streamsize>; //!< Iterator
  142. using const_iterator = outdev_it <const out_dev_t, data_t*, streamsize>; //!< Const iterator
  143. //!@{ .begin implementation
  144. iterator begin () noexcept { return iterator(this, iterator::beg); }
  145. const_iterator begin () const noexcept { return const_iterator(this, iterator::beg); }
  146. const_iterator cbegin () const noexcept { return const_iterator(this, iterator::beg); }
  147. //!@}
  148. //!@{ .end implementation
  149. iterator end () noexcept { return iterator(this, iterator::eos); }
  150. const_iterator end () const noexcept { return const_iterator(this, iterator::eos); }
  151. const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); }
  152. //!@}
  153. //!@}
  154. };
  155. /*!
  156. * \brief
  157. * A virtual base class specialization
  158. * \param impl_t = virtual_tag
  159. * \param data_t The devices base type of data
  160. * \param streamsize The number of elements to indicate eos.
  161. * \arg None or 0 Stream only. No iterator as begin() now equals end().
  162. */
  163. template <typename data_t, size_t streamsize>
  164. class out_dev <virtual_tag, data_t, streamsize> {
  165. using out_dev_t = out_dev <virtual_tag, data_t, streamsize>; //!< class type syntactic sugar
  166. //! Export types as input device concept demands
  167. //! @{
  168. public:
  169. using data_type = data_t;
  170. using pointer_type = data_t*;
  171. //! @}
  172. using type = out_dev_t; //!< Export type as identity meta-function
  173. /*!
  174. * \name Constructor / Destructor
  175. */
  176. //!@{
  177. public:
  178. virtual ~out_dev () = default; //!< \brief Virtual destructor
  179. protected:
  180. out_dev () = default; //!< \brief A default constructor from derived only
  181. out_dev(const out_dev&) = delete; //!< No copies
  182. out_dev_t& operator= (const out_dev_t&) = delete; //!< No copy assignments
  183. //!@}
  184. /*!
  185. * \name Common output device interface requirements
  186. */
  187. //!@{
  188. private:
  189. /*!
  190. * \brief
  191. * Put interface. This function should send a single
  192. * data_t object to device.
  193. * \param data The data to send
  194. * \return The number of transmitted data items
  195. * \note
  196. * A successful call should return 1
  197. */
  198. virtual size_t put_ (const data_t& data) = 0;
  199. /*!
  200. * \brief
  201. * Put interface. This function should send a stream of
  202. * data_t objects to device.
  203. * \param data Pointer to buffer indenting write to device.
  204. * \param n The number of data of type data_t to send
  205. * \return The number of transmitted items.
  206. */
  207. virtual size_t put_ (const data_t* data, size_t n) = 0;
  208. //!@}
  209. /*!
  210. * \name Public Put interface
  211. */
  212. //!@{
  213. public:
  214. size_t put (const data_t& data) { return put_ (data); }
  215. size_t put (const data_t* data, size_t n) { return put_ (data, n); }
  216. //!@}
  217. /*!
  218. * \name Stream operator<< interface
  219. */
  220. //!@{
  221. public:
  222. /*!
  223. * \brief
  224. * Template operator<< implementation for for all by value/ref parameters
  225. * \param src Reference to source data
  226. * \return Reference to this device for chaining
  227. */
  228. template <typename _Src_t>
  229. out_dev_t& operator<< (_Src_t& src) {
  230. static_assert ((sizeof (_Src_t)%sizeof(data_t) == 0),
  231. "Source size must be an integer multiple of device's data size");
  232. put_ (reinterpret_cast<data_t*>(&src), sizeof(_Src_t)/sizeof(data_t));
  233. return *this;
  234. }
  235. //! Overload to disallow pointer types as source
  236. template <typename _Src_t>
  237. out_dev_t& operator<< (_Src_t* src) = delete;
  238. //! Overload for single data_t object
  239. out_dev_t& operator<< (const data_t& src) {
  240. put_ (src);
  241. return *this;
  242. }
  243. //!@}
  244. /*!
  245. * \name STL-like Output iterator interface
  246. */
  247. //!@{
  248. using iterator = outdev_it <out_dev_t, data_t*, streamsize>; //!< Iterator
  249. using const_iterator = outdev_it <const out_dev_t, data_t*, streamsize>; //!< Const iterator
  250. //!@{ .begin implementation
  251. iterator begin () noexcept { return iterator(this, iterator::beg); }
  252. const_iterator begin () const noexcept { return const_iterator(this, iterator::beg); }
  253. const_iterator cbegin () const noexcept { return const_iterator(this, iterator::beg); }
  254. //!@}
  255. //!@{ .end implementation
  256. iterator end () noexcept { return iterator(this, iterator::eos); }
  257. const_iterator end () const noexcept { return const_iterator(this, iterator::eos); }
  258. const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); }
  259. //!@}
  260. //!@}
  261. };
  262. /*!
  263. * Output device concept
  264. */
  265. //! @{
  266. #if defined _utl_have_concepts
  267. template <typename _Tp>
  268. concept bool Out_dev = requires (_Tp t, const _Tp ct, typename _Tp::data_type v) {
  269. // Object type
  270. requires !std::is_copy_constructible<_Tp>::value;
  271. requires !std::is_copy_assignable<_Tp>::value;
  272. // Methods
  273. {t.put(v)} -> size_t;
  274. {t.put(&v, sizeof(v))} -> size_t;
  275. // Operators
  276. t << v;
  277. // Iterators
  278. typename _Tp::const_iterator;
  279. requires Outdev_it<typename _Tp::iterator>;
  280. requires Outdev_it<typename _Tp::const_iterator>;
  281. { t.begin() } -> typename _Tp::iterator;
  282. {ct.begin()} -> typename _Tp::const_iterator;
  283. { t.cbegin()} -> typename _Tp::const_iterator;
  284. { t.end() } -> typename _Tp::iterator;
  285. {ct.end()} -> typename _Tp::const_iterator;
  286. { t.cend()} -> typename _Tp::const_iterator;
  287. };
  288. #else
  289. namespace out_dev_details {
  290. using std::declval;
  291. template <class _Tp> using try_put1_t = decltype (declval<_Tp>().put (declval<const typename _Tp::data_type&>()));
  292. template <class _Tp> using try_put2_t = decltype (declval<_Tp>().put (declval<const typename _Tp::data_type*>(),
  293. declval<size_t>()));
  294. // operators
  295. //template <class _Tp> using try_insert_t= decltype (declval<_Tp>() << declval<typename _Tp::data_type&>());
  296. // iterator members
  297. template <class _Tp> using try_begin_t = decltype (declval<_Tp>().begin());
  298. template <class _Tp> using tryc_begin_t = decltype (declval<const _Tp>().begin());
  299. template <class _Tp> using try_cbegin_t = decltype (declval<const _Tp>().cbegin());
  300. template <class _Tp> using try_end_t = decltype (declval<_Tp>().begin());
  301. template <class _Tp> using tryc_end_t = decltype (declval<const _Tp>().begin());
  302. template <class _Tp> using try_cend_t = decltype (declval<const _Tp>().cend());
  303. //! Primary template to catch any non output device types
  304. template <typename _Tp, typename =void>
  305. struct is_out_dev_ : false_ { };
  306. //! template to catch a proper output device type
  307. template <typename _Tp>
  308. struct is_out_dev_ <_Tp,
  309. void_t <
  310. typename _Tp::data_type,
  311. typename _Tp::pointer_type,
  312. typename _Tp::iterator,
  313. typename _Tp::const_iterator,
  314. use_if_same_t <try_put1_t <_Tp>, size_t>,
  315. use_if_same_t <try_put2_t <_Tp>, size_t>,
  316. //if_same_t <try_insert_t<_Tp>,_Tp&>,
  317. use_if_same_t <try_begin_t<_Tp>, typename _Tp::iterator>,
  318. use_if_same_t <tryc_begin_t<_Tp>, typename _Tp::const_iterator>,
  319. use_if_same_t <try_cbegin_t<_Tp>, typename _Tp::const_iterator>,
  320. use_if_same_t <try_end_t<_Tp>, typename _Tp::iterator>,
  321. use_if_same_t <tryc_end_t<_Tp>, typename _Tp::const_iterator>,
  322. use_if_same_t <try_cend_t<_Tp>, typename _Tp::const_iterator>
  323. >
  324. > : true_ { };
  325. }
  326. /*!
  327. * Predicate for output device checking
  328. * \param _Tp Type to check
  329. * \return True if _Tp is a output device
  330. */
  331. template <typename _Tp>
  332. constexpr bool Out_dev = out_dev_details::is_out_dev_<_Tp>::value;
  333. #endif
  334. //!@}
  335. //!@}
  336. } //namespace utl
  337. #endif /* #ifndef __utl_dev_out_dev_h__ */