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.
 
 
 
 

241 lines
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__ */