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.
 
 
 
 

531 lignes
19 KiB

  1. /*!
  2. * \file utl/dev/idx_dev.h
  3. * \brief Abstract base class implementations for indexed
  4. * devices interface 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_idx_dev_h__
  23. #define __utl_dev_idx_dev_h__
  24. #include <utl/core/impl.h>
  25. #include <utl/core/crtp.h>
  26. #include <utl/dev/dev_iterators.h>
  27. #include <utl/meta/meta.h>
  28. namespace utl {
  29. /*!
  30. * \ingroup Device Interface
  31. * \brief Abstract base class for indexed devices
  32. */
  33. //!@{
  34. /*!
  35. * \brief
  36. * Template base class for indexed (I/O) devices. using CRTP
  37. *
  38. * This class force a common interface for input, indexed (I/O) devices.
  39. * By using this common interface the class implements
  40. * - Stream-like extracting and insertion operator
  41. * - Helper operators
  42. * - Input iterator
  43. * - Const input iterator
  44. * to inherit to implementation.
  45. *
  46. * \param impl_t The CRTP type (the derived/implementation class typename).
  47. * \param data_t The devices base type of data
  48. * \param idx_t The type to use for indexing
  49. * \param streamsize The number of elements to indicate eos.
  50. */
  51. template <typename impl_t, typename data_t, typename idx_t, size_t N>
  52. class idx_dev {
  53. _CRTP_IMPL(impl_t);
  54. using idx_dev_t = idx_dev <impl_t, data_t, idx_t, N>; //!< class type syntactic sugar
  55. //!@{ Export types as index device concept demands
  56. public:
  57. using data_type = data_t;
  58. using pointer_type= data_t*;
  59. using idx_type = idx_t;
  60. //!@}
  61. using type = idx_dev_t; //!< Export type as identity meta-function
  62. /*!
  63. * \name Constructor / Destructor
  64. */
  65. //!@{
  66. protected:
  67. ~idx_dev () = default; //!< \brief Allow destructor from derived only
  68. idx_dev () = default; //!< \brief A default constructor from derived only
  69. idx_dev(const idx_dev_t&) = delete; //!< No copies
  70. idx_dev_t& operator= (const idx_dev_t&) = delete; //!< No copy assignments
  71. //!@}
  72. //! \name Common index device interface requirements
  73. //!@{
  74. private:
  75. size_t get_ (data_t& data, idx_t idx) { return impl().get_(data, idx); }
  76. size_t get_ (data_t* data, size_t n, idx_t idx) { return impl().get_(data, n, idx); }
  77. size_t put_ (const data_t& data, idx_t idx) { return impl().put_(data, idx); }
  78. size_t put_ (const data_t* data, size_t n, idx_t idx) { return impl().put_ (data, n, idx); }
  79. idx_t cursor_ () const { return impl().cursor_(); }
  80. void cursor_ (idx_t idx) { impl().cursor_(idx); }
  81. //!@}
  82. /*!
  83. * \name Public index device interface
  84. */
  85. //!@{
  86. public:
  87. /*!
  88. * \brief
  89. * Get interface. This function should read
  90. * a single data_t object from device in blocking mode.
  91. * \param data Reference to data output from device.
  92. * \return Number of data read from device
  93. * \note
  94. * A successful call should return 1
  95. */
  96. size_t get (data_t& data, idx_t cursor) {
  97. return get_ (data, cursor);
  98. }
  99. /*!
  100. * \brief
  101. * Old stile get functionality using free standing data_t*.
  102. * This function should return a stream of data from device
  103. * \param data Pointer to buffer to write the data from device.
  104. * \param n The number of data of type data_t to read
  105. * \return The read data items.
  106. */
  107. size_t get (data_t* data, size_t n, idx_t cursor) {
  108. return get_ (data, n, cursor);
  109. }
  110. /*!
  111. * \brief
  112. * Put interface. This function should send a single
  113. * data_t object to device.
  114. * \param data The data to send
  115. * \return The number of transmitted data items
  116. * \note
  117. * A successful call should return 1
  118. */
  119. size_t put (const data_t& data, idx_t cursor) {
  120. return put_ (data, cursor);
  121. }
  122. /*!
  123. * \brief
  124. * Put interface. This function should send a stream of
  125. * data_t objects to device.
  126. * \param data Pointer to buffer indenting write to device.
  127. * \param n The number of data of type data_t to send
  128. * \return The number of transmitted items.
  129. */
  130. size_t put (const data_t* data, size_t n, idx_t cursor) {
  131. return put_ (data, n, cursor);
  132. }
  133. /*!
  134. * \brief
  135. * Return the current cursor position
  136. */
  137. idx_t cursor () const { return cursor_(); }
  138. /*!
  139. * \brief
  140. * Set the cursor position
  141. * \param idx Cursor address to set
  142. * \return The current cursor
  143. */
  144. idx_t cursor (idx_t idx) { return cursor_(idx); }
  145. //!@}
  146. /*!
  147. * \name Stream operator >> interface
  148. */
  149. //!@{
  150. /*!
  151. * \brief
  152. * Template operator>> implementation for for all by value/ref parameters
  153. * \param dst Reference to destination
  154. * \return Reference to this device for chaining
  155. */
  156. template <typename _Dst_t>
  157. idx_dev_t& operator>> (_Dst_t& dst) {
  158. static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0),
  159. "Target size must be a integer multiple of device's data size");
  160. get_ (reinterpret_cast<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t), cursor_());
  161. return *this;
  162. }
  163. //! Specialization to disallow pointer types as destination
  164. template <typename _Dst_t>
  165. idx_dev_t& operator>> (_Dst_t* dst) = delete;
  166. //! Overload for single data_t object
  167. idx_dev_t& operator>> (data_t& dst) {
  168. get_ (dst, cursor_());
  169. return *this;
  170. }
  171. //!@}
  172. /*!
  173. * \name Stream operator<< interface
  174. */
  175. //!@{
  176. /*!
  177. * \brief
  178. * Template operator<< implementation for for all by value/ref parameters
  179. * \param src Reference to source data
  180. * \return Reference to this device for chaining
  181. */
  182. template <typename _Src_t>
  183. idx_dev_t& operator<< (_Src_t& src) {
  184. static_assert ((sizeof (_Src_t)%sizeof(data_t) == 0),
  185. "Source size must be a integer multiple of device's data size");
  186. put_ (reinterpret_cast<data_t*>(&src), sizeof (_Src_t)/sizeof(data_t), cursor_());
  187. return *this;
  188. }
  189. //! specialization to disallow pointer types as source
  190. template <typename _Src_t>
  191. idx_dev_t& operator<< (_Src_t* src) = delete;
  192. //! Overload for single data_t object
  193. idx_dev_t& operator<< (const data_t& src) {
  194. put_ (src, cursor_());
  195. return *this;
  196. }
  197. //!@}
  198. /*!
  199. * \name Helper operators
  200. */
  201. //!@{
  202. data_t& operator[] (const idx_t idx) {
  203. iterator it(this, idx);
  204. return *it;
  205. }
  206. //!@}
  207. /*!
  208. * \name STL-like Input iterator interface
  209. */
  210. //!@{
  211. public:
  212. using iterator = idxdev_it <idx_dev_t, data_t*, N>; //!< Iterator
  213. using const_iterator = idxdev_it <idx_dev_t, const data_t*, N>; //!< Const iterator
  214. //!@{ .begin implementation
  215. iterator begin () noexcept { return iterator(this, iterator::beg); }
  216. const_iterator begin () const noexcept { return const_iterator(this, iterator::beg); }
  217. const_iterator cbegin () const noexcept { return const_iterator(this, iterator::beg); }
  218. //!@}
  219. //!@{ .end implementation
  220. iterator end () noexcept { return iterator(this, iterator::eos); }
  221. const_iterator end () const noexcept { return const_iterator(this, iterator::eos); }
  222. const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); }
  223. //!@}
  224. //!@}
  225. };
  226. /*!
  227. * \brief
  228. * A virtual base class specialization
  229. * \param impl_t = virtual_tag
  230. * \param data_t The devices base type of data
  231. * \param idx_t The type to use for indexing
  232. * \param streamsize The number of elements to indicate eos.
  233. */
  234. template <typename data_t, typename idx_t, size_t N>
  235. class idx_dev <virtual_tag, data_t, idx_t, N> {
  236. using idx_dev_t = idx_dev <virtual_tag, data_t, idx_t, N>; //!< class type syntactic sugar
  237. //!@{ Export types as index device concept demands
  238. public:
  239. using data_type = data_t;
  240. using pointer_type= data_t*;
  241. using idx_type = idx_t;
  242. //!@}
  243. using type = idx_dev_t; //!< Export type as identity meta-function
  244. /*!
  245. * \name Constructor / Destructor
  246. */
  247. //!@{
  248. public:
  249. virtual ~idx_dev () = default; //!< \brief Virtual destructor
  250. protected:
  251. idx_dev () = default; //!< \brief A default constructor from derived only
  252. idx_dev(const idx_dev_t&) = delete; //!< No copies
  253. idx_dev_t& operator= (const idx_dev_t&) = delete; //!< No copy assignments
  254. //!@}
  255. //!@{ \name Common index device interface requirements
  256. private:
  257. virtual size_t get_ (data_t&, idx_t) =0;
  258. virtual size_t get_ (data_t*, size_t n, idx_t) =0;
  259. virtual size_t put_ (const data_t&, idx_t) =0;
  260. virtual size_t put_ (const data_t*, size_t n, idx_t) =0;
  261. virtual idx_t cursor_ () const =0;
  262. virtual void cursor_ (idx_t) =0;
  263. //!@}
  264. /*!
  265. * \name Public index device interface
  266. */
  267. //!@{
  268. public:
  269. /*!
  270. * \brief
  271. * Get interface. This function should read
  272. * a single data_t object from device in blocking mode.
  273. * \param data Reference to data output from device.
  274. * \return Number of data read from device
  275. * \note
  276. * A successful call should return 1
  277. */
  278. size_t get (data_t& data, idx_t cursor) {
  279. return get_ (data, cursor);
  280. }
  281. /*!
  282. * \brief
  283. * Old stile get functionality using free standing data_t*.
  284. * This function should return a stream of data from device
  285. * \param data Pointer to buffer to write the data from device.
  286. * \param n The number of data of type data_t to read
  287. * \return The read data items.
  288. */
  289. size_t get (data_t* data, size_t n, idx_t cursor) {
  290. return get_ (data, n, cursor);
  291. }
  292. /*!
  293. * \brief
  294. * Put interface. This function should send a single
  295. * data_t object to device.
  296. * \param data The data to send
  297. * \return The number of transmitted data items
  298. * \note
  299. * A successful call should return 1
  300. */
  301. size_t put (const data_t& data, idx_t cursor) {
  302. return put_ (data, cursor);
  303. }
  304. /*!
  305. * \brief
  306. * Put interface. This function should send a stream of
  307. * data_t objects to device.
  308. * \param data Pointer to buffer indenting write to device.
  309. * \param n The number of data of type data_t to send
  310. * \return The number of transmitted items.
  311. */
  312. size_t put (const data_t* data, size_t n, idx_t cursor) {
  313. return put_ (data, n, cursor);
  314. }
  315. /*!
  316. * \brief
  317. * Return the current cursor position
  318. */
  319. idx_t cursor () const { return cursor_(); }
  320. /*!
  321. * \brief
  322. * Set the cursor position
  323. * \param idx Cursor address to set
  324. * \return The current cursor
  325. */
  326. idx_t cursor (idx_t idx) { return cursor_(idx); }
  327. //!@}
  328. /*!
  329. * \name Stream operator>> interface
  330. */
  331. //!@{
  332. /*!
  333. * \brief
  334. * Template operator>> implementation for for all by value/ref parameters
  335. * \param dst Reference to destination
  336. * \return Reference to this device for chaining
  337. */
  338. template <typename _Dst_t>
  339. idx_dev_t& operator>> (_Dst_t& dst) {
  340. static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0),
  341. "Target size must be an integer multiple of device's data size");
  342. get_ (reinterpret_cast<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t), cursor_());
  343. return *this;
  344. }
  345. //! specialization to disallow pointer types as destination
  346. template <typename _Dst_t>
  347. idx_dev_t& operator>> (_Dst_t* dst) = delete;
  348. //! Overload for single data_t object
  349. idx_dev_t& operator>> (data_t& dst) {
  350. get_ (dst, cursor_());
  351. return *this;
  352. }
  353. //!@}
  354. /*!
  355. * \name Stream operator<< interface
  356. */
  357. //!@{
  358. /*!
  359. * \brief
  360. * Template operator<< implementation for for all by value/ref parameters
  361. * \param src Reference to source data
  362. * \return Reference to this device for chaining
  363. */
  364. template <typename _Src_t>
  365. idx_dev_t& operator<< (_Src_t& src) {
  366. static_assert ((sizeof (_Src_t)%sizeof(data_t) == 0),
  367. "Source size must be an integer multiple of device's data size");
  368. put_ (reinterpret_cast<data_t*>(&src), sizeof (_Src_t)/sizeof(data_t), cursor_());
  369. return *this;
  370. }
  371. //! specialization to disallow pointer types as source
  372. template <typename _Src_t>
  373. idx_dev_t& operator<< (_Src_t* src) = delete;
  374. //! Overload for single data_t object
  375. idx_dev_t& operator<< (const data_t& src) {
  376. put_ (src, cursor_());
  377. return *this;
  378. }
  379. //!@}
  380. /*!
  381. * \name Helper operators
  382. */
  383. //!@{
  384. data_t& operator[] (const idx_t idx) {
  385. iterator it(this, idx);
  386. return *it;
  387. }
  388. //!@}
  389. /*!
  390. * \name STL-like Input iterator interface
  391. */
  392. //!@{
  393. public:
  394. using iterator = idxdev_it <idx_dev_t, data_t*, N>; //!< Iterator
  395. using const_iterator = idxdev_it <idx_dev_t, const data_t*, N>; //!< Const iterator
  396. //!@{ .begin implementation
  397. iterator begin () noexcept { return iterator(this, iterator::beg); }
  398. const_iterator begin () const noexcept { return const_iterator(this, iterator::beg); }
  399. const_iterator cbegin () const noexcept { return const_iterator(this, iterator::beg); }
  400. //!@}
  401. //!@{ .end implementation
  402. iterator end () noexcept { return iterator(this, iterator::eos); }
  403. const_iterator end () const noexcept { return const_iterator(this, iterator::eos); }
  404. const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); }
  405. //!@}
  406. //!@}
  407. };
  408. /*!
  409. * indexed device concept
  410. */
  411. //! @{
  412. #if defined _utl_have_concepts
  413. template <typename _Tp>
  414. concept bool Idx_dev = requires (_Tp t, const _Tp ct, typename _Tp::data_type v) {
  415. // Object type
  416. // requires std::is_default_constructible<_Tp>::value;
  417. requires !std::is_copy_constructible<_Tp>::value;
  418. requires !std::is_copy_assignable<_Tp>::value;
  419. // Methods
  420. {t.get(v, 0)} -> size_t;
  421. {t.get(&v, 1, 0)} -> size_t;
  422. {t.put(v, 0)} -> size_t;
  423. {t.put(&v, 1, 0)} -> size_t;
  424. // Operators
  425. t >> v;
  426. t << v;
  427. {t[typename _Tp::idx_type{}]} -> typename _Tp::data_type&;
  428. // Iterators
  429. requires idxdev_iterator_c<typename _Tp::iterator>;
  430. typename _Tp::const_iterator; //XXX: change to concept: is_idxdev_iterator<_Tp>
  431. //requires idxdev_iterator_c<typename _Tp::const_iterator>;
  432. { t.begin()} -> typename _Tp::iterator;
  433. // {ct.begin()} -> typename _Tp::const_iterator;
  434. // { t.cbegin()} -> typename _Tp::const_iterator;
  435. { t.end()} -> typename _Tp::iterator;
  436. // {ct.end()} -> typename _Tp::const_iterator;
  437. // { t.cend()} -> typename _Tp::const_iterator;
  438. };
  439. #else
  440. namespace idx_dev_details {
  441. using std::declval;
  442. // main api members
  443. template <class _Tp> using try_get1_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type&>()));
  444. template <class _Tp> using try_get2_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type*>(), declval<size_t>()));
  445. // operators
  446. //template <class _Tp> using try_extract_t= decltype (declval<_Tp>() >> declval<typename _Tp::data_type&>());
  447. // iterator members
  448. template <class _Tp> using try_begin_t = decltype (declval<_Tp>().begin());
  449. template <class _Tp> using tryc_begin_t = decltype (declval<const _Tp>().begin());
  450. template <class _Tp> using try_cbegin_t = decltype (declval<const _Tp>().cbegin());
  451. template <class _Tp> using try_end_t = decltype (declval<_Tp>().begin());
  452. template <class _Tp> using tryc_end_t = decltype (declval<const _Tp>().begin());
  453. template <class _Tp> using try_cend_t = decltype (declval<const _Tp>().cend());
  454. //! Primary template to catch any non input device types
  455. template <typename _Tp, typename =void>
  456. struct is_idx_dev_ : false_ {};
  457. //! template to catch a proper input device type
  458. template <typename _Tp>
  459. struct is_idx_dev_ <_Tp,
  460. void_t <
  461. typename _Tp::data_type,
  462. typename _Tp::pointer_type,
  463. typename _Tp::iterator,
  464. typename _Tp::const_iterator,
  465. use_if_same_t <try_get1_t <_Tp>, size_t>,
  466. use_if_same_t <try_get2_t <_Tp>, size_t>,
  467. //if_same_t <try_extract_t<_Tp>,typename _Tp&>,
  468. use_if_same_t <try_begin_t<_Tp>, typename _Tp::iterator>,
  469. use_if_same_t <tryc_begin_t<_Tp>, typename _Tp::const_iterator>,
  470. use_if_same_t <try_cbegin_t<_Tp>, typename _Tp::const_iterator>,
  471. use_if_same_t <try_end_t<_Tp>, typename _Tp::iterator>,
  472. use_if_same_t <tryc_end_t<_Tp>, typename _Tp::const_iterator>,
  473. use_if_same_t <try_cend_t<_Tp>, typename _Tp::const_iterator>
  474. >
  475. > : true_ {};
  476. }
  477. /*!
  478. * Predicate for input device checking
  479. * \param _Tp Type to check
  480. * \return True if _Tp is a input device
  481. */
  482. template <typename _Tp>
  483. constexpr bool Idx_dev = idx_dev_details::is_idx_dev_ <_Tp>::value;
  484. #endif
  485. //!@}
  486. }
  487. //!@}
  488. #endif /* #ifndef __utl_dev_idx_dev_h__ */