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.
 
 
 
 

241 lignes
8.2 KiB

  1. /*!
  2. * \file utl/containers/array.h
  3. * \brief An std::array equivalent implementation
  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_array_h__
  22. #define __utl_container_array_h__
  23. #include <utl/core/impl.h>
  24. #include <algorithm>
  25. namespace utl {
  26. /*!
  27. * \ingroup containers
  28. * \brief
  29. * array container traits helper
  30. */
  31. //! @{
  32. template<typename _Tp, size_t _Nm>
  33. struct array_traits {
  34. typedef _Tp type[_Nm];
  35. static constexpr _Tp& Ref (const type& t, size_t n) noexcept {
  36. return const_cast<_Tp&>(t[n]);
  37. }
  38. static constexpr _Tp* Ptr(const type& t) noexcept {
  39. return const_cast<_Tp*>(t);
  40. }
  41. };
  42. template<typename _Tp>
  43. struct array_traits<_Tp, 0> {
  44. struct type { };
  45. static constexpr _Tp& Ref(const type&, size_t) noexcept {
  46. return *static_cast<_Tp*>(nullptr);
  47. }
  48. static constexpr _Tp* Ptr(const type&) noexcept {
  49. return nullptr;
  50. }
  51. };
  52. //! @}
  53. /*!
  54. * \ingroup containers
  55. * \brief
  56. * A standard container for storing a fixed size sequence of elements.
  57. *
  58. * Meets the requirements of:
  59. * <a href="tables.html#65">container</a>,
  60. * <a href="tables.html#66">reversible container</a>,
  61. * <a href="tables.html#67">sequence</a>.
  62. * Sets support random access iterators.
  63. *
  64. * \tparam _Tp type of element. Required to be a complete type.
  65. * \tparam _Nm Number of elements.
  66. */
  67. template <typename _Tp, size_t _Nm>
  68. struct array {
  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 = 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 empty_t = array_traits<_Tp, 0>;
  83. using array_t = array_traits<_Tp, _Nm>;
  84. typename array_t::type _data;
  85. // No explicit construct/copy/destroy for aggregate type.
  86. // DR 776.
  87. void fill (const value_type& v) { std::fill_n (begin(), size(), v); }
  88. void swap (array& other) noexcept {
  89. std::swap_ranges (begin(), end(), other.begin());
  90. }
  91. //! \name Iterators.
  92. //!@{
  93. iterator begin() noexcept { return iterator (data()); }
  94. const_iterator begin() const noexcept { return const_iterator (data()); }
  95. iterator end() noexcept { return iterator (data() + _Nm); }
  96. const_iterator end() const noexcept { return const_iterator (data() + _Nm); }
  97. const_iterator cbegin() const noexcept { return const_iterator (data()); }
  98. const_iterator cend() const noexcept { return const_iterator (data() + _Nm); }
  99. reverse_iterator rbegin() noexcept { return reverse_iterator (end()); }
  100. reverse_iterator rend() noexcept { return reverse_iterator (begin()); }
  101. const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator (end()); }
  102. const_reverse_iterator rend() const noexcept { return const_reverse_iterator (begin()); }
  103. const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator (end()); }
  104. const_reverse_iterator crend() const noexcept { return const_reverse_iterator (begin()); }
  105. //!@{
  106. //! \name Capacity.
  107. //!@{
  108. constexpr size_type size() const noexcept { return _Nm; }
  109. constexpr size_type max_size() const noexcept { return _Nm; }
  110. constexpr bool empty() const noexcept { return size() == 0; }
  111. //!@{
  112. //! \name Element access.
  113. //!@{
  114. //! Operator []
  115. reference operator[] (size_type n) noexcept {
  116. return array_t::Ref(_data, n);
  117. }
  118. //! Operator [] for const
  119. constexpr const_reference operator[](size_type n) const noexcept {
  120. return array_t::Ref(_data, n);
  121. }
  122. /*!
  123. * Boundary check dereference operator.
  124. * If out of bounds, abort (for now)
  125. */
  126. reference at (size_type n) noexcept {
  127. if (n < _Nm)
  128. return array_t::Ref(_data, n);
  129. else
  130. abort (); //XXX: Throw here
  131. }
  132. //! Compile time boundary check dereference operator.
  133. constexpr const_reference at (size_type n) const noexcept {
  134. static_assert ((n < _Nm), "array::at: out of range");
  135. return array_t::Ref(_data, n);
  136. }
  137. // first item
  138. reference front () noexcept {
  139. return *begin ();
  140. }
  141. constexpr const_reference front() const noexcept {
  142. return array_t::Ref(_data, 0);
  143. }
  144. // Last item
  145. reference back () noexcept {
  146. return _Nm ? *(end() - 1) : *end();
  147. }
  148. constexpr const_reference back () const noexcept {
  149. return _Nm ? array_t::Ref(_data, _Nm - 1)
  150. : array_t::Ref(_data, 0);
  151. }
  152. // Pointer to data
  153. pointer data () noexcept { return array_t::Ptr(_data); }
  154. const_pointer data () const noexcept { return array_t::Ptr(_data); }
  155. //!<@}
  156. };
  157. //! \name Array comparisons.
  158. //!@{
  159. template<typename _Tp, size_t _Nm>
  160. inline bool operator== (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
  161. return std::equal (lhs.begin(), lhs.end(), rhs.begin());
  162. }
  163. template<typename _Tp, size_t _Nm>
  164. inline bool operator!= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
  165. return !(lhs == rhs);
  166. }
  167. template<typename _Tp, size_t _Nm>
  168. inline bool operator< (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
  169. return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
  170. }
  171. template<typename _Tp, size_t _Nm>
  172. inline bool operator> (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
  173. return rhs < lhs;
  174. }
  175. template<typename _Tp, size_t _Nm>
  176. inline bool operator<= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
  177. return !(lhs > rhs);
  178. }
  179. template<typename _Tp, size_t _Nm>
  180. inline bool
  181. operator>= (const array<_Tp, _Nm>& lhs, const array<_Tp, _Nm>& rhs) {
  182. return !(lhs < rhs);
  183. }
  184. //!@}
  185. // Specialized algorithms.
  186. template<typename _Tp, size_t _Nm>
  187. inline void swap (array<_Tp, _Nm>& lhs, array<_Tp, _Nm>& rhs)
  188. noexcept (noexcept (lhs.swap(rhs))) {
  189. lhs.swap (rhs);
  190. }
  191. template<size_t _Int, typename _Tp, size_t _Nm>
  192. constexpr _Tp& get (array<_Tp, _Nm>& arr) noexcept {
  193. static_assert(_Int < _Nm, "Index is out of bounds");
  194. return array_traits<_Tp, _Nm>::Ref(arr._data, _Int);
  195. }
  196. template<size_t _Int, typename _Tp, size_t _Nm>
  197. constexpr _Tp&& get (array<_Tp, _Nm>&& arr) noexcept {
  198. static_assert(_Int < _Nm, "Index is out of bounds");
  199. return std::move(std::get<_Int>(arr));
  200. }
  201. template<size_t _Int, typename _Tp, size_t _Nm>
  202. constexpr const _Tp& get (const array<_Tp, _Nm>& arr) noexcept {
  203. static_assert(_Int < _Nm, "Index is out of bounds");
  204. return array_traits<_Tp, _Nm>::Ref(arr._data, _Int);
  205. }
  206. } // namespace utl
  207. #endif /* __utl_continer_array_h__ */