Array.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Util/Functions.h>
  7. namespace anki {
  8. /// @addtogroup util_containers
  9. /// @{
  10. /// Like std::array but with some additions
  11. template<typename T, PtrSize kSize>
  12. class Array
  13. {
  14. public:
  15. using Value = T;
  16. using Iterator = Value*;
  17. using ConstIterator = const Value*;
  18. using Reference = Value&;
  19. using ConstReference = const Value&;
  20. // STL compatible
  21. using iterator = Iterator;
  22. using const_iterator = ConstIterator;
  23. using reference = Reference;
  24. using const_reference = ConstReference;
  25. Value m_data[kSize];
  26. /// Access an element using an integer.
  27. template<typename TInt>
  28. constexpr Reference operator[](const TInt n) requires(!std::is_enum<TInt>::value)
  29. {
  30. ANKI_ASSERT(PtrSize(n) < kSize);
  31. return m_data[n];
  32. }
  33. /// Access an element using an integer.
  34. template<typename TInt>
  35. constexpr ConstReference operator[](const TInt n) const requires(!std::is_enum<TInt>::value)
  36. {
  37. ANKI_ASSERT(PtrSize(n) < kSize);
  38. return m_data[n];
  39. }
  40. /// Access an element using an enumerant. It's a little bit special and separate from operator[] that accepts integer. This to avoid any short of
  41. /// arbitrary integer type casting.
  42. template<typename TEnum>
  43. constexpr Reference operator[](const TEnum n) requires(std::is_enum<TEnum>::value)
  44. {
  45. return operator[](typename std::underlying_type<TEnum>::type(n));
  46. }
  47. /// Access an element using an enumerant. It's a little bit special and separate from operator[] that accepts integer. This to avoid any short of
  48. /// arbitrary integer type casting.
  49. template<typename TEnum>
  50. constexpr ConstReference operator[](const TEnum n) const requires(std::is_enum<TEnum>::value)
  51. {
  52. return operator[](typename std::underlying_type<TEnum>::type(n));
  53. }
  54. Bool operator==(const Array&) const = default;
  55. Iterator getBegin()
  56. {
  57. return &m_data[0];
  58. }
  59. ConstIterator getBegin() const
  60. {
  61. return &m_data[0];
  62. }
  63. Iterator getEnd()
  64. {
  65. return &m_data[0] + kSize;
  66. }
  67. ConstIterator getEnd() const
  68. {
  69. return &m_data[0] + kSize;
  70. }
  71. Reference getFront()
  72. {
  73. return m_data[0];
  74. }
  75. ConstReference getFront() const
  76. {
  77. return m_data[0];
  78. }
  79. Reference getBack()
  80. {
  81. return m_data[kSize - 1];
  82. }
  83. ConstReference getBack() const
  84. {
  85. return m_data[kSize - 1];
  86. }
  87. /// Make it compatible with the C++11 range based for loop
  88. Iterator begin()
  89. {
  90. return getBegin();
  91. }
  92. /// Make it compatible with the C++11 range based for loop
  93. ConstIterator begin() const
  94. {
  95. return getBegin();
  96. }
  97. /// Make it compatible with the C++11 range based for loop
  98. Iterator end()
  99. {
  100. return getEnd();
  101. }
  102. /// Make it compatible with the C++11 range based for loop
  103. ConstIterator end() const
  104. {
  105. return getEnd();
  106. }
  107. /// Make it compatible with STL
  108. Reference front()
  109. {
  110. return getFront();
  111. }
  112. /// Make it compatible with STL
  113. ConstReference front() const
  114. {
  115. return getFront();
  116. }
  117. /// Make it compatible with STL
  118. Reference back()
  119. {
  120. return getBack;
  121. }
  122. /// Make it compatible with STL
  123. ConstReference back() const
  124. {
  125. return getBack();
  126. }
  127. // Get size
  128. #define ANKI_ARRAY_SIZE_METHOD(type, condition) \
  129. static constexpr type getSize() requires(condition) \
  130. { \
  131. return type(kSize); \
  132. }
  133. ANKI_ARRAY_SIZE_METHOD(U8, kSize <= kMaxU8)
  134. ANKI_ARRAY_SIZE_METHOD(U16, kSize > kMaxU8 && kSize <= kMaxU16)
  135. ANKI_ARRAY_SIZE_METHOD(U32, kSize > kMaxU16 && kSize <= kMaxU32)
  136. ANKI_ARRAY_SIZE_METHOD(U64, kSize > kMaxU32)
  137. #undef ANKI_ARRAY_SIZE_METHOD
  138. /// Make it compatible with STL
  139. static constexpr size_t size()
  140. {
  141. return kSize;
  142. }
  143. /// Fill the array.
  144. static void fill(Iterator begin, Iterator end, const T& val)
  145. {
  146. while(begin != end)
  147. {
  148. *begin = val;
  149. ++begin;
  150. }
  151. }
  152. void fill(const T& val)
  153. {
  154. auto begin = getBegin();
  155. auto end = getEnd();
  156. while(begin != end)
  157. {
  158. *begin = val;
  159. ++begin;
  160. }
  161. }
  162. // Get size in bytes
  163. #define ANKI_ARRAY_SIZE_IN_BYTES_METHOD(type, condition) \
  164. static constexpr type getSizeInBytes() requires(condition) \
  165. { \
  166. return type(kSize * sizeof(Value)); \
  167. }
  168. ANKI_ARRAY_SIZE_IN_BYTES_METHOD(U8, kSize * sizeof(Value) <= kMaxU8)
  169. ANKI_ARRAY_SIZE_IN_BYTES_METHOD(U16, kSize * sizeof(Value) > kMaxU8 && kSize * sizeof(Value) <= kMaxU16)
  170. ANKI_ARRAY_SIZE_IN_BYTES_METHOD(U32, kSize * sizeof(Value) > kMaxU16 && kSize * sizeof(Value) <= kMaxU32)
  171. ANKI_ARRAY_SIZE_IN_BYTES_METHOD(U64, kSize * sizeof(Value) > kMaxU32)
  172. #undef ANKI_ARRAY_SIZE_IN_BYTES_METHOD
  173. };
  174. // Some trick stolen from GCC's std::array. It allows deduction of Array's template params. For example you can write: Array a{1, 2, 3};
  175. template<typename TFirst, typename... TRest>
  176. Array(TFirst, TRest...) -> Array<std::enable_if_t<(std::is_same_v<TFirst, TRest> && ...), TFirst>, 1 + sizeof...(TRest)>;
  177. /// 2D Array. @code Array2d<X, 10, 2> a; @endcode is equivelent to @code X a[10][2]; @endcode
  178. template<typename T, PtrSize I, PtrSize J>
  179. using Array2d = Array<Array<T, J>, I>;
  180. /// 3D Array. @code Array3d<X, 10, 2, 3> a; @endcode is equivelent to @code X a[10][2][3]; @endcode
  181. template<typename T, PtrSize I, PtrSize J, PtrSize K>
  182. using Array3d = Array<Array<Array<T, K>, J>, I>;
  183. /// 4D Array. @code Array4d<X, 10, 2, 3, 4> a; @endcode is equivelent to @code X a[10][2][3][4]; @endcode
  184. template<typename T, PtrSize I, PtrSize J, PtrSize K, PtrSize L>
  185. using Array4d = Array<Array<Array<Array<T, L>, K>, J>, I>;
  186. /// 5D Array. @code Array5d<X, 10, 2, 3, 4, 5> a; @endcode is equivelent to @code X a[10][2][3][4][5]; @endcode
  187. template<typename T, PtrSize I, PtrSize J, PtrSize K, PtrSize L, PtrSize M>
  188. using Array5d = Array<Array<Array<Array<Array<T, M>, L>, K>, J>, I>;
  189. /// @}
  190. } // end namespace anki