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.
 
 
 
 

287 lines
10 KiB

  1. /*!
  2. * \file utl/dev/ostream_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_ostream_dev_h__
  22. #define __utl_dev_ostream_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 stream devices
  31. */
  32. //!@{
  33. /*!
  34. * \brief
  35. * Template base class for output stream devices using CRTP
  36. *
  37. * This class force a common interface for output stream 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. */
  47. template <typename impl_t, typename data_t>
  48. class ostream_dev {
  49. _CRTP_IMPL(impl_t);
  50. using ostream_dev_t = ostream_dev <impl_t, data_t>; //!< class type syntactic sugar
  51. //! Export types as output device concept demands
  52. //! @{
  53. public:
  54. using data_type = data_t;
  55. using pointer_type = data_t*;
  56. //!@}
  57. using type = ostream_dev_t; //!< Export type as identity meta-function
  58. /*!
  59. * \name Constructor / Destructor
  60. */
  61. //!@{
  62. protected:
  63. ~ostream_dev () = default; //!< \brief Allow destructor from derived only
  64. ostream_dev () = default; //!< \brief A default constructor from derived only
  65. ostream_dev(const ostream_dev_t&) = delete; //!< No copies
  66. ostream_dev_t& operator= (const ostream_dev_t&) = delete; //!< No copy assignments
  67. //!@}
  68. //! \name Common output device interface requirements
  69. //!@{
  70. private:
  71. size_t put_ (const data_t& data) { return impl().put_ (data); }
  72. size_t put_ (const data_t* data, size_t n) {
  73. return impl().put_ (data, n);
  74. }
  75. //!@}
  76. /*!
  77. * \name Common output device interface
  78. */
  79. //!@{
  80. public:
  81. /*!
  82. * \brief
  83. * Put interface. This function should send a single
  84. * data_t object to device.
  85. * \param data The data to send
  86. * \return The number of transmitted data items
  87. * \note
  88. * A successful call should return 1
  89. */
  90. size_t put (const data_t& data) {
  91. return put_ (data);
  92. }
  93. /*!
  94. * \brief
  95. * Put interface. This function should send a stream of
  96. * data_t objects to device.
  97. * \param data Pointer to buffer indenting write to device.
  98. * \param n The number of data of type data_t to send
  99. * \return The number of transmitted items.
  100. */
  101. size_t put (const data_t* data, size_t n) {
  102. return put_ (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 _Src_t size is not an exact multiple of data_t size
  115. * the write data will be truncated and there may be data loss.
  116. * \param src Reference to source data
  117. * \return Reference to this device for chaining
  118. */
  119. template <typename _Src_t>
  120. ostream_dev_t& operator<< (const _Src_t& src) {
  121. static_assert ((sizeof (_Src_t)%sizeof(data_t) == 0),
  122. "Source size must be an integer multiple of device's data size");
  123. put_ (reinterpret_cast<const data_t*>(&src), sizeof(_Src_t)/sizeof(data_t));
  124. return *this;
  125. }
  126. //! Overload to disallow pointer types as source
  127. template <typename _Src_t>
  128. ostream_dev_t& operator<< (_Src_t* src) = delete;
  129. //! Overload for single data_t object
  130. ostream_dev_t& operator<< (const data_t& src) {
  131. put_ (src);
  132. return *this;
  133. }
  134. //ToDo: Add support for c-string, utl::string, ...
  135. //!@}
  136. /*!
  137. * \name STL-like Output iterator interface
  138. */
  139. //!@{
  140. using iterator = ostreamdev_it <ostream_dev_t, data_t>; //!< Iterator
  141. using const_iterator = ostreamdev_it <const ostream_dev_t, data_t>; //!< Const iterator
  142. //!@{ .begin implementation
  143. iterator begin () noexcept { return iterator(this); }
  144. const_iterator begin () const noexcept { return const_iterator(this); }
  145. const_iterator cbegin () const noexcept { return const_iterator(this); }
  146. //!@}
  147. //!@{ .end implementation
  148. iterator end () noexcept { return iterator(); }
  149. const_iterator end () const noexcept { return const_iterator(); }
  150. const_iterator cend () const noexcept { return const_iterator(); }
  151. //!@}
  152. //!@}
  153. };
  154. template <typename data_t>
  155. class ostream_dev<virtual_tag, data_t> {
  156. using ostream_dev_t = ostream_dev <virtual_tag, data_t>; //!< class type syntactic sugar
  157. //! Export types as output device concept demands
  158. //! @{
  159. public:
  160. using data_type = data_t;
  161. using pointer_type = data_t*;
  162. //!@}
  163. using type = ostream_dev_t; //!< Export type as identity meta-function
  164. /*!
  165. * \name Constructor / Destructor
  166. */
  167. //!@{
  168. public:
  169. virtual ~ostream_dev () = default; //!< \brief Virtual destructor
  170. protected:
  171. ostream_dev () = default; //!< \brief A default constructor from derived only
  172. ostream_dev(const ostream_dev_t&) = delete; //!< No copies
  173. ostream_dev_t& operator= (const ostream_dev_t&) = delete; //!< No copy assignments
  174. //!@}
  175. //! \name Common output device interface requirements
  176. //!@{
  177. private:
  178. virtual size_t put_ (const data_t& data) =0;
  179. virtual size_t put_ (const data_t* data, size_t n) =0;
  180. //!@}
  181. /*!
  182. * \name Common output device interface
  183. */
  184. //!@{
  185. public:
  186. /*!
  187. * \brief
  188. * Put interface. This function should send a single
  189. * data_t object to device.
  190. * \param data The data to send
  191. * \return The number of transmitted data items
  192. * \note
  193. * A successful call should return 1
  194. */
  195. size_t put (const data_t& data) {
  196. return put_ (data);
  197. }
  198. /*!
  199. * \brief
  200. * Put interface. This function should send a stream of
  201. * data_t objects to device.
  202. * \param data Pointer to buffer indenting write to device.
  203. * \param n The number of data of type data_t to send
  204. * \return The number of transmitted items.
  205. */
  206. size_t put (const data_t* data, size_t n) {
  207. return put_ (data, n);
  208. }
  209. //!@}
  210. /*!
  211. * \name Stream operator << interface
  212. */
  213. //!@{
  214. public:
  215. /*!
  216. * \brief
  217. * Template operator<< implementation for for all by value/ref parameters
  218. * \note
  219. * In the case _Src_t size is not an exact multiple of data_t size
  220. * the write data will be truncated and there may be data loss.
  221. * \param src Reference to source data
  222. * \return Reference to this device for chaining
  223. */
  224. template <typename _Src_t>
  225. ostream_dev_t& operator<< (const _Src_t& src) {
  226. static_assert ((sizeof (_Src_t)%sizeof(data_t) == 0),
  227. "Source size must be an integer multiple of device's data size");
  228. put_ (reinterpret_cast<const data_t*>(&src), sizeof(_Src_t)/sizeof(data_t));
  229. return *this;
  230. }
  231. //! Overload to disallow pointer types as source
  232. template <typename _Src_t>
  233. ostream_dev_t& operator<< (_Src_t* src) = delete;
  234. //! Overload for single data_t object
  235. ostream_dev_t& operator<< (const data_t& src) {
  236. put_ (src);
  237. return *this;
  238. }
  239. //!@}
  240. /*!
  241. * \name STL-like Output iterator interface
  242. */
  243. //!@{
  244. using iterator = ostreamdev_it <ostream_dev_t, data_t>; //!< Iterator
  245. using const_iterator = ostreamdev_it <const ostream_dev_t, data_t>; //!< Const iterator
  246. //!@{ .begin implementation
  247. iterator begin () noexcept { return iterator(this); }
  248. const_iterator begin () const noexcept { return const_iterator(this); }
  249. const_iterator cbegin () const noexcept { return const_iterator(this); }
  250. //!@}
  251. //!@{ .end implementation
  252. iterator end () noexcept { return iterator(); }
  253. const_iterator end () const noexcept { return const_iterator(); }
  254. const_iterator cend () const noexcept { return const_iterator(); }
  255. //!@}
  256. //!@}
  257. };
  258. //!@}
  259. } //namespace utl
  260. #endif /* #ifndef __utl_dev_out_dev_h__ */