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.

284 lignes
8.0 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net>
  5. // © 2013—2014 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
  6. // © 2013—2014 Guillaume Bittoun <guillaume.bittoun@gmail.com>
  7. //
  8. // Lol Engine is free software. It comes without any warranty, to
  9. // the extent permitted by applicable law. You can redistribute it
  10. // and/or modify it under the terms of the Do What the Fuck You Want
  11. // to Public License, Version 2, as published by the WTFPL Task Force.
  12. // See http://www.wtfpl.net/ for more details.
  13. //
  14. #pragma once
  15. //
  16. // The arraynd class
  17. // -----------------
  18. // A N-Dimensional array class allowing var[i][j][k]... indexing,
  19. //
  20. //
  21. // XXX: This file is in lol/math/ instead of lol/base/ because it uses vec_t.
  22. //
  23. #include <lol/base/array.h>
  24. #include <lol/math/vector.h> // vec_t
  25. #include <algorithm> // std::min
  26. #include <cstring> // memset
  27. #include <climits>
  28. #include <type_traits> // std::enable_if
  29. namespace lol
  30. {
  31. template<typename T, int L>
  32. class arraynd_initializer
  33. {
  34. public:
  35. arraynd_initializer(std::initializer_list<arraynd_initializer<T, L - 1> > const & initializers) :
  36. m_initializers(initializers)
  37. {
  38. }
  39. void fill_sizes(size_t * sizes)
  40. {
  41. *sizes = std::max(*sizes, m_initializers.size());
  42. for (auto subinitializer : m_initializers)
  43. subinitializer.fill_sizes(sizes - 1);
  44. }
  45. void fill_values(T * origin, size_t prev, size_t * sizes)
  46. {
  47. int pos = 0;
  48. for (auto subinitializer : m_initializers)
  49. subinitializer.fill_values(origin, pos++ + prev * *sizes, sizes - 1);
  50. }
  51. private:
  52. std::initializer_list<arraynd_initializer<T, L - 1> > const & m_initializers;
  53. };
  54. template<typename T>
  55. class arraynd_initializer<T, 1>
  56. {
  57. public:
  58. arraynd_initializer(std::initializer_list<T> const & initializers) :
  59. m_initializers(initializers)
  60. {
  61. }
  62. void fill_sizes(size_t * sizes)
  63. {
  64. *sizes = std::max(*sizes, m_initializers.size());
  65. }
  66. void fill_values(T * origin, size_t prev, size_t * sizes)
  67. {
  68. int pos = 0;
  69. for (auto value : m_initializers)
  70. *(origin + prev * *sizes + pos++) = value;
  71. }
  72. private:
  73. std::initializer_list<T> const & m_initializers;
  74. };
  75. template<int N, typename... T>
  76. class [[nodiscard]] arraynd : protected array<T...>
  77. {
  78. public:
  79. typedef array<T...> super;
  80. typedef typename super::element_t element_t;
  81. inline arraynd() = default;
  82. inline arraynd(vec_t<size_t, N> sizes, element_t e = element_t())
  83. : m_sizes(sizes)
  84. {
  85. resize_data(e);
  86. }
  87. /* Additional constructor if size_t != int */
  88. template<typename T2 = int, typename T3 = typename std::enable_if<!std::is_same<size_t, T2>::value, int>::type>
  89. inline arraynd(vec_t<T2, N> sizes, element_t e = element_t())
  90. : m_sizes(vec_t<size_t, N>(sizes))
  91. {
  92. resize_data(e);
  93. }
  94. inline arraynd(std::initializer_list<arraynd_initializer<element_t, N - 1> > initializer)
  95. {
  96. m_sizes[N - 1] = initializer.size();
  97. for (auto inner_initializer : initializer)
  98. inner_initializer.fill_sizes(&m_sizes[N - 2]);
  99. resize_data();
  100. int pos = 0;
  101. for (auto inner_initializer : initializer)
  102. inner_initializer.fill_values(&super::operator[](0), pos++, &m_sizes[N - 2]);
  103. }
  104. /* Access elements directly using an vec_t<size_t, N> index */
  105. inline element_t const & operator[](vec_t<size_t, N> const &pos) const
  106. {
  107. size_t n = pos[N - 1];
  108. for (size_t i = N - 1; i > 0; --i)
  109. n = pos[i - 1] + m_sizes[i] * n;
  110. return super::operator[](n);
  111. }
  112. inline element_t & operator[](vec_t<size_t, N> const &pos)
  113. {
  114. return const_cast<element_t &>(
  115. const_cast<arraynd<N, T...> const&>(*this)[pos]);
  116. }
  117. /* If int != size_t, access elements directly using an ivec2,
  118. * ivec3 etc. */
  119. template<typename T2 = int, typename T3 = typename std::enable_if<!std::is_same<size_t, T2>::value, int>::type>
  120. inline element_t const & operator[](vec_t<T2, N> const &pos) const
  121. {
  122. size_t n = pos[N - 1];
  123. for (size_t i = N - 1; i > 0; --i)
  124. n = pos[i - 1] + m_sizes[i] * n;
  125. return super::operator[](n);
  126. }
  127. template<typename T2 = int, typename T3 = typename std::enable_if<!std::is_same<size_t, T2>::value, int>::type>
  128. inline element_t & operator[](vec_t<T2, N> const &pos)
  129. {
  130. return const_cast<element_t &>(
  131. const_cast<arraynd<N, T...> const&>(*this)[pos]);
  132. }
  133. /* Proxy to access slices */
  134. template<typename ARRAY_TYPE, int L = N - 1>
  135. class slice
  136. {
  137. public:
  138. typedef slice<ARRAY_TYPE, L - 1> subslice;
  139. inline slice(ARRAY_TYPE &array, size_t index, size_t accumulator)
  140. : m_array(array),
  141. m_index(index),
  142. m_accumulator(accumulator)
  143. {
  144. }
  145. /* Accessors for the const version of the proxy */
  146. template<bool V = L != 1 && std::is_const<ARRAY_TYPE>::value>
  147. inline typename std::enable_if<V, subslice>::type
  148. operator[](size_t pos) const
  149. {
  150. return subslice(m_array, m_index + pos * m_accumulator,
  151. m_accumulator * m_array.m_sizes[N - L]);
  152. }
  153. template<bool V = L == 1 && std::is_const<ARRAY_TYPE>::value>
  154. inline typename std::enable_if<V, typename ARRAY_TYPE::element_t>::type
  155. const & operator[](size_t pos) const
  156. {
  157. return m_array.super::operator[](m_index + pos * m_accumulator);
  158. }
  159. /* Accessors for the non-const version of the proxy */
  160. template<bool V = L != 1 && !std::is_const<ARRAY_TYPE>::value>
  161. inline typename std::enable_if<V, subslice>::type
  162. operator[](size_t pos)
  163. {
  164. return subslice(m_array, m_index + pos * m_accumulator,
  165. m_accumulator * m_array.m_sizes[N - L]);
  166. }
  167. template<bool V = L == 1 && !std::is_const<ARRAY_TYPE>::value>
  168. inline typename std::enable_if<V, typename ARRAY_TYPE::element_t>::type
  169. & operator[](size_t pos)
  170. {
  171. return m_array.super::operator[](m_index + pos * m_accumulator);
  172. }
  173. private:
  174. ARRAY_TYPE &m_array;
  175. size_t m_index, m_accumulator;
  176. };
  177. /* Access addressable slices, allowing for array[i][j][...] syntax. */
  178. inline slice<arraynd<N, T...> const> operator[](size_t pos) const
  179. {
  180. return slice<arraynd<N, T...> const>(*this, pos, m_sizes[0]);
  181. }
  182. inline slice<arraynd<N, T...>> operator[](size_t pos)
  183. {
  184. return slice<arraynd<N, T...>>(*this, pos, m_sizes[0]);
  185. }
  186. /* Resize the array.
  187. * FIXME: data gets scrambled; should we care? */
  188. inline void resize(vec_t<int, N> sizes, element_t e = element_t())
  189. {
  190. resize_s(vec_t<size_t, N>(sizes), e);
  191. }
  192. inline void resize_s(vec_t<size_t, N> sizes, element_t e = element_t())
  193. {
  194. m_sizes = sizes;
  195. resize_data(e);
  196. }
  197. inline vec_t<int, N> size() const
  198. {
  199. return vec_t<int, N>(this->m_sizes);
  200. }
  201. inline vec_t<size_t, N> size_s() const
  202. {
  203. return this->m_sizes;
  204. }
  205. public:
  206. inline element_t *data() { return super::data(); }
  207. inline element_t const *data() const { return super::data(); }
  208. inline int count() const { return super::count(); }
  209. inline int bytes() const { return super::bytes(); }
  210. inline size_t count_s() const { return super::count_s(); }
  211. inline size_t bytes_s() const { return super::bytes_s(); }
  212. private:
  213. inline void resize_data(element_t e = element_t())
  214. {
  215. size_t total_size = 1;
  216. /* HACK: we can't use for (auto s : m_sizes) because of an ICE in
  217. * the Visual Studio compiler. */
  218. for (int i = 0; i < N; ++i)
  219. total_size *= m_sizes[i];
  220. this->array<T...>::resize(total_size, e);
  221. }
  222. vec_t<size_t, N> m_sizes { 0 };
  223. };
  224. template<typename... T> using array2d = arraynd<2, T...>;
  225. template<typename... T> using array3d = arraynd<3, T...>;
  226. } /* namespace lol */