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.
 
 
 
 

237 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/impl/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. value_type one = 1;
  142. uint8_t den = 8*sizeof(_Tp)/sizeof(uint8_t);
  143. return traits_t::Ref (_data, bit/den) & (one << ((bit % den)-1));
  144. }
  145. /*!
  146. * Write/modify a bit position from a id
  147. * \param bit The bit location we want to set
  148. * \param v The value we want to set
  149. */
  150. void bit (uint8_t bit, bool v) noexcept {
  151. value_type one = 1;
  152. uint8_t den = 8*sizeof(_Tp)/sizeof(uint8_t);
  153. if (v) traits_t::Ref (_data, bit/den) |= one << ((bit % den)-1);
  154. else traits_t::Ref (_data, bit/den) &= ~one << ((bit % den)-1);
  155. }
  156. // first item
  157. reference front () noexcept {
  158. return *begin ();
  159. }
  160. constexpr const_reference front () const noexcept {
  161. return traits_t::Ref (_data, 0);
  162. }
  163. // Last item
  164. reference back () noexcept {
  165. return _Nm ? *(end() - 1) : *end();
  166. }
  167. constexpr const_reference back () const noexcept {
  168. return _Nm ? traits_t::Ref (_data, _Nm - 1)
  169. : traits_t::Ref (_data, 0);
  170. }
  171. // Pointer to data
  172. pointer data () noexcept { return traits_t::Ptr (_data); }
  173. const_pointer data () const noexcept { return traits_t::Ptr (_data); }
  174. //!<@}
  175. };
  176. //! \name device ID comparisons.
  177. //!@{
  178. template <typename _Tp, size_t _Nm>
  179. inline bool operator== (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  180. return std::equal (lhs.begin(), lhs.end(), rhs.begin());
  181. }
  182. template <typename _Tp, size_t _Nm>
  183. inline bool operator!= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  184. return !(lhs == rhs);
  185. }
  186. template <typename _Tp, size_t _Nm>
  187. inline bool operator< (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  188. // MSB plays bigger role in comparison
  189. return std::lexicographical_compare(lhs.rbegin(), lhs.rend(), rhs.rbegin(), rhs.rend());
  190. }
  191. template <typename _Tp, size_t _Nm>
  192. inline bool operator> (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  193. return rhs < lhs;
  194. }
  195. template <typename _Tp, size_t _Nm>
  196. inline bool operator<= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  197. return !(lhs > rhs);
  198. }
  199. template <typename _Tp, size_t _Nm>
  200. inline bool operator>= (const id_t<_Tp, _Nm>& lhs, const id_t<_Tp, _Nm>& rhs) {
  201. return !(lhs < rhs);
  202. }
  203. //!@}
  204. } // namespace utl
  205. #endif /* __utl_container_id_h__ */