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.
 
 
 
 

236 lines
8.1 KiB

  1. /*!
  2. * \file utl/container/id.h
  3. * \brief A container for device IDs
  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_container_id_h__
  22. #define __utl_container_id_h__
  23. #include <utl/core/impl.h>
  24. #include <utl/container/array.h>
  25. #include <algorithm>
  26. namespace utl {
  27. /*!
  28. * \ingroup containers
  29. * \brief
  30. * id container traits helper
  31. */
  32. //! @{
  33. template <typename _Tp, size_t _Nm>
  34. struct id_traits {
  35. typedef _Tp type[_Nm];
  36. static constexpr _Tp& Ref (const type& t, size_t n) noexcept {
  37. return const_cast<_Tp&> (t[n]);
  38. }
  39. static constexpr _Tp* Ptr(const type& t) noexcept {
  40. return const_cast<_Tp*> (t);
  41. }
  42. };
  43. template <typename _Tp>
  44. struct id_traits<_Tp, 0> {
  45. struct type { };
  46. static constexpr _Tp& Ref(const type& t, size_t n) noexcept {
  47. return *static_cast<_Tp*>(nullptr);
  48. }
  49. static constexpr _Tp* Ptr(const type& t) noexcept {
  50. return nullptr;
  51. }
  52. };
  53. //! @{
  54. /*!
  55. * \ingroup containers
  56. * \brief
  57. * A standard container for storing IDs as a fixed size
  58. * sequence of bytes. This type is based on etl::array
  59. * Meets the requirements of:
  60. * <a href="tables.html#65">container</a>,
  61. * <a href="tables.html#66">reversible container</a>,
  62. * <a href="tables.html#67">sequence</a>.
  63. * Sets support random access iterators.
  64. * \tparam _Tp The base type
  65. * \tparam _Nm Number of bytes.
  66. */
  67. template <typename _Tp, size_t _Nm>
  68. struct id_t {
  69. using value_type = _Tp;
  70. using pointer = value_type*;
  71. using const_pointer = const value_type*;
  72. using reference = value_type&;
  73. using const_reference = const value_type&;
  74. using iterator = value_type*;
  75. using const_iterator = const value_type*;
  76. using size_type = size_t;
  77. using difference_type = std::ptrdiff_t;
  78. using reverse_iterator = std::reverse_iterator <iterator>;
  79. using const_reverse_iterator
  80. = std::reverse_iterator <const_iterator>;
  81. // type and data
  82. using traits_t = id_traits<_Tp, _Nm>;
  83. typename traits_t::type _data;
  84. // No explicit construct/copy/destroy for aggregate type.
  85. // DR 776 (std::array)
  86. void fill (const value_type& v) { std::fill_n (begin(), size(), v); }
  87. void swap (id_t& other) noexcept {
  88. std::swap_ranges (begin(), end(), other.begin());
  89. }
  90. //! \name Iterators.
  91. //!@{
  92. iterator begin() noexcept { return iterator (data()); }
  93. const_iterator begin() const noexcept { return const_iterator (data()); }
  94. iterator end() noexcept { return iterator (data() + _Nm); }
  95. const_iterator end() const noexcept { return const_iterator (data() + _Nm); }
  96. const_iterator cbegin() const noexcept { return const_iterator (data()); }
  97. const_iterator cend() const noexcept { return const_iterator (data() + _Nm); }
  98. reverse_iterator rbegin() noexcept { return reverse_iterator (end()); }
  99. reverse_iterator rend() noexcept { return reverse_iterator (begin()); }
  100. const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator (end()); }
  101. const_reverse_iterator rend() const noexcept { return const_reverse_iterator (begin()); }
  102. const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator (end()); }
  103. const_reverse_iterator crend() const noexcept { return const_reverse_iterator (begin()); }
  104. //!@{
  105. //! \name Capacity.
  106. //!@{
  107. constexpr size_type size() const noexcept { return _Nm; }
  108. constexpr size_type max_size() const noexcept { return _Nm; }
  109. constexpr bool empty() const noexcept { return size() == 0; }
  110. //!@{
  111. //! \name Element access.
  112. //!@{
  113. //! Operator []
  114. reference operator[] (size_type n) noexcept {
  115. return traits_t::Ref (_data, n);
  116. }
  117. //! Operator [] for const
  118. constexpr const_reference operator[] (size_type n) const noexcept {
  119. return traits_t::Ref (_data, n);
  120. }
  121. /*!
  122. * Boundary check dereference operator.
  123. * If out of bounds, abort (for now).
  124. */
  125. reference at (size_type n) noexcept {
  126. if (n < _Nm)
  127. return traits_t::Ref (_data, n);
  128. else
  129. abort ();
  130. }
  131. //! Compile time boundary check dereference operator.
  132. constexpr const_reference at (size_type n) const noexcept {
  133. static_assert ((n < _Nm), "id_t::at: out of range");
  134. return traits_t::Ref (_data, n);
  135. }
  136. /*!
  137. * Read a bit position from a id
  138. * \param bit The bit location we want to read
  139. */
  140. constexpr bool bit (uint8_t bit) const noexcept {
  141. return traits_t::Ref (_data, bit/(8*sizeof(_Tp))) &
  142. (static_cast<value_type>(0x01) << ((bit % (8*sizeof(_Tp)))-1));
  143. }
  144. /*!
  145. * Write/modify a bit position from a id
  146. * \param bit The bit location we want to set
  147. * \param v The value we want to set
  148. */
  149. void bit (uint8_t bit, bool v) noexcept {
  150. value_type one = 1;
  151. uint8_t den = 8*sizeof(_Tp)/sizeof(uint8_t);
  152. if (v) traits_t::Ref (_data, bit/den) |= one << ((bit % den)-1);
  153. else traits_t::Ref (_data, bit/den) &= ~one << ((bit % den)-1);
  154. }
  155. // first item
  156. reference front () noexcept {
  157. return *begin ();
  158. }
  159. constexpr const_reference front () const noexcept {
  160. return traits_t::Ref (_data, 0);
  161. }
  162. // Last item
  163. reference back () noexcept {
  164. return _Nm ? *(end() - 1) : *end();
  165. }
  166. constexpr const_reference back () const noexcept {
  167. return _Nm ? traits_t::Ref (_data, _Nm - 1)
  168. : traits_t::Ref (_data, 0);
  169. }
  170. // Pointer to data
  171. pointer data () noexcept { return traits_t::Ptr (_data); }
  172. const_pointer data () const noexcept { return traits_t::Ptr (_data); }
  173. //!<@}
  174. };
  175. //! \name device ID comparisons.
  176. //!@{
  177. template <typename _Tp, size_t _Nm>
  178. inline bool operator== (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  179. return std::equal (lhs.begin(), lhs.end(), rhs.begin());
  180. }
  181. template <typename _Tp, size_t _Nm>
  182. inline bool operator!= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  183. return !(lhs == rhs);
  184. }
  185. template <typename _Tp, size_t _Nm>
  186. inline bool operator< (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  187. // MSB plays bigger role in comparison
  188. return std::lexicographical_compare(lhs.rbegin(), lhs.rend(), rhs.rbegin(), rhs.rend());
  189. }
  190. template <typename _Tp, size_t _Nm>
  191. inline bool operator> (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  192. return rhs < lhs;
  193. }
  194. template <typename _Tp, size_t _Nm>
  195. inline bool operator<= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  196. return !(lhs > rhs);
  197. }
  198. template <typename _Tp, size_t _Nm>
  199. inline bool operator>= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  200. return !(lhs < rhs);
  201. }
  202. //!@}
  203. } // namespace utl
  204. #endif /* __utl_container_id_h__ */