fork(2) download
  1. #include <array>
  2. #include <cstddef>
  3. #include <iostream>
  4. #include <iterator>
  5.  
  6. enum class ArithmeticOperator {
  7. addition,
  8. subtraction,
  9. multiplication,
  10. division
  11. };
  12.  
  13. namespace _arithmeticoperationresult
  14. {
  15.  
  16. template<ArithmeticOperator T_operator, typename T1, typename T2>
  17. struct BinaryResult;
  18.  
  19. template<typename T1, typename T2>
  20. struct BinaryResult<ArithmeticOperator::addition, T1, T2>
  21. { using type = decltype(std::declval<T1>() + std::declval<T2>()); };
  22.  
  23. template<typename T1, typename T2>
  24. struct BinaryResult<ArithmeticOperator::subtraction, T1, T2>
  25. { using type = decltype(std::declval<T1>() - std::declval<T2>()); };
  26.  
  27. template<typename T1, typename T2>
  28. struct BinaryResult<ArithmeticOperator::multiplication, T1, T2>
  29. { using type = decltype(std::declval<T1>() * std::declval<T2>()); };
  30.  
  31. template<typename T1, typename T2>
  32. struct BinaryResult<ArithmeticOperator::division, T1, T2>
  33. { using type = decltype(std::declval<T1>() / std::declval<T2>()); };
  34.  
  35. }
  36.  
  37. template<
  38. ArithmeticOperator T_operator,
  39. typename T_First,
  40. typename ... T_Others
  41. >
  42. struct ArithmeticOperationResult;
  43.  
  44. template<
  45. ArithmeticOperator T_operator,
  46. typename T_First,
  47. typename T_Second,
  48. typename ... T_Others
  49. >
  50. struct ArithmeticOperationResult<
  51. T_operator,
  52. T_First,
  53. T_Second,
  54. T_Others ...
  55. >
  56. {
  57. using type = typename ArithmeticOperationResult<
  58. T_operator,
  59. typename _arithmeticoperationresult::BinaryResult<
  60. T_operator,
  61. T_First,
  62. T_Second
  63. >::type,
  64. T_Others ...
  65. >::type;
  66. };
  67.  
  68. template<
  69. ArithmeticOperator T_operator,
  70. typename T_Unique
  71. >
  72. struct ArithmeticOperationResult<T_operator, T_Unique>
  73. {
  74. using type = T_Unique;
  75. };
  76.  
  77. template<typename ... T_Values>
  78. using MultiplicationResult =
  79. ArithmeticOperationResult<ArithmeticOperator::multiplication, T_Values ...>;
  80.  
  81. template<typename ... T_Values>
  82. using MultiplicationResultT =
  83. typename MultiplicationResult<T_Values ...>::type;
  84.  
  85. template<typename T_Unique>
  86. constexpr T_Unique
  87. product(T_Unique unique) noexcept
  88. {
  89. return unique;
  90. }
  91.  
  92. template<typename T_First, typename T_Second, typename ... T_Others>
  93. constexpr MultiplicationResultT<T_First, T_Second, T_Others ...>
  94. product(T_First first, T_Second second, T_Others ... others) noexcept
  95. {
  96. return product(first * second, others ...);
  97. }
  98.  
  99.  
  100. enum class StorageOrder {
  101. rowMajor,
  102. columnMajor
  103. };
  104.  
  105. template<StorageOrder> struct StorageOrderTag {};
  106. using RowMajorStorageOrderTag = StorageOrderTag<StorageOrder::rowMajor>;
  107. using ColumnMajorStorageOrderTag = StorageOrderTag<StorageOrder::columnMajor>;
  108.  
  109.  
  110. // - Converts a list of indices for a specific shape array into a 1-D index.
  111.  
  112. template<typename T_Shape>
  113. std::size_t storageIndex(const T_Shape &indices, const T_Shape &shape)
  114. {
  115. std::size_t i = 0;
  116. std::size_t out = indices[i];
  117. while (i++ < indices.size() - 1) {
  118. out = indices[i] + shape[i] * out;
  119. }
  120.  
  121. return out;
  122. }
  123.  
  124.  
  125. //- Element-wise iterator.
  126.  
  127. template<
  128. typename T,
  129. typename T_Data,
  130. StorageOrder T_storageOrder,
  131. std::size_t T_dimensionality
  132. >
  133. class ElementWiseIterator
  134. : public std::iterator<std::bidirectional_iterator_tag, T>
  135. {
  136. private:
  137. using Shape = std::array<std::size_t, T_dimensionality>;
  138.  
  139. public:
  140. T & operator*() const
  141. { return *_currentElement; }
  142.  
  143. ElementWiseIterator & operator++()
  144. {
  145. std::size_t i = _shape.size();
  146.  
  147. if ( T_storageOrder == StorageOrder::columnMajor ) {
  148. std::swap(_shape[T_dimensionality-1], _shape[T_dimensionality-2]);
  149. std::swap(_currentIndices[T_dimensionality-1], _currentIndices[T_dimensionality-2]);
  150. }
  151. // For each dimension
  152. while (i-- > 0) {
  153. // Find the lowest index one can increase
  154. // Indeces are stored from top to bottom
  155. if (_currentIndices[i] < _shape[i] - 1) {
  156. ++_currentIndices[i];
  157. break;
  158. }
  159. }
  160. bool endOfContainer = ( i == -1 );
  161.  
  162. // Then we reset all the others, since they could not be increased.
  163. for (++i; i < _currentIndices.size(); ++i) {
  164. _currentIndices[i] = 0;
  165. }
  166.  
  167. if ( T_storageOrder == StorageOrder::columnMajor ) {
  168. std::swap(_shape[T_dimensionality-1], _shape[T_dimensionality-2]);
  169. std::swap(_currentIndices[T_dimensionality-1], _currentIndices[T_dimensionality-2]);
  170. }
  171.  
  172. if ( endOfContainer )
  173. _currentIndices[0] = _shape[0];
  174.  
  175. setCurrentElement();
  176. return *this;
  177. }
  178.  
  179. friend bool operator==(const ElementWiseIterator &iterator1, const ElementWiseIterator &iterator2)
  180. { return iterator1._currentElement == iterator2._currentElement; }
  181.  
  182. friend bool operator!=(const ElementWiseIterator &iterator1, const ElementWiseIterator &iterator2)
  183. { return !(iterator1 == iterator2); }
  184.  
  185. private:
  186. ElementWiseIterator(T_Data *data, const Shape &indices, const Shape &shape)
  187. : _currentElement(nullptr),
  188. _data(data),
  189. _currentIndices(indices),
  190. _shape(shape)
  191. {
  192. setCurrentElement();
  193. }
  194.  
  195. void setCurrentElement()
  196. {
  197. std::size_t index = storageIndex(
  198. _currentIndices,
  199. _shape
  200. );
  201. _currentElement = &(*_data)[index];
  202. }
  203.  
  204. T *_currentElement;
  205. T_Data *_data;
  206. Shape _currentIndices;
  207. Shape _shape;
  208.  
  209. template<typename, StorageOrder, std::size_t ...> friend class Array;
  210. };
  211.  
  212.  
  213. //- Array class.
  214.  
  215. template<typename T, StorageOrder T_storageOrder, std::size_t ... T_dimensions>
  216. class Array
  217. {
  218. public:
  219. static constexpr std::size_t size()
  220. { return product(T_dimensions ...); }
  221.  
  222. using Shape = std::array<std::size_t, sizeof ... (T_dimensions)>;
  223.  
  224. static constexpr Shape shape()
  225. { return {T_dimensions ...}; }
  226.  
  227. protected:
  228. using Storage = std::array<T, size()>;
  229.  
  230. public:
  231. using Iterator = typename Storage::iterator;
  232. using EWiseIterator = ElementWiseIterator<
  233. T,
  234. Storage,
  235. T_storageOrder,
  236. sizeof ... (T_dimensions)
  237. >;
  238.  
  239. Iterator begin()
  240. { return _data.begin(); }
  241.  
  242. Iterator end()
  243. { return _data.end(); }
  244.  
  245. EWiseIterator elementWiseBegin()
  246. { // Passes all zeros, N dimension, starting index.
  247. return EWiseIterator(&_data, {0}, shape());
  248. }
  249.  
  250. EWiseIterator elementWiseEnd()
  251. {
  252. // Set the current iterator indices to the first out of range element.
  253. // Ie: for an a 2x3 array, that would be {2, 0}.
  254. Shape shape = this->shape();
  255. //if ( T_storageOrder == StorageOrder::columnMajor )
  256. // std::cout << "Making end: ";
  257. return EWiseIterator(&_data, {shape[0]}, shape);
  258. }
  259.  
  260. private:
  261. Storage _data;
  262. };
  263.  
  264.  
  265.  
  266. int main(int argc, char **argv)
  267. {
  268. int i;
  269.  
  270. Array<int, StorageOrder::rowMajor, 2, 3> rowArray;
  271. i = 0;
  272. for (auto &value : rowArray) {
  273. value = i++;
  274. }
  275.  
  276. Array<int, StorageOrder::columnMajor, 2, 3> columnArray;
  277. i = 0;
  278. for (auto &value : columnArray) {
  279. value = i++;
  280. }
  281.  
  282. // Below returns 0 1 2 3 4 5 as expected.
  283. for (auto it = rowArray.elementWiseBegin(); it != rowArray.elementWiseEnd(); ++it) {
  284. std::cout << *it << " ";
  285. }
  286. std::cout << std::endl;
  287.  
  288. // Below returns only 0.
  289. for (auto it = columnArray.elementWiseBegin(); it != columnArray.elementWiseEnd(); ++it) {
  290. std::cout << *it << " ";
  291. }
  292. std::cout << std::endl;
  293.  
  294. // This is because the end iterator, pointing to the indices {2, 0} is
  295. // (fairly enough) converted into the index 2 by the `storageIndex` function,
  296. // instead of an index beyond the last element.
  297. // std::cout << storageIndex({columnArray.shape()[0]}, columnArray.shape(), ColumnMajorStorageOrderTag()) << std::endl;
  298.  
  299. return 0;
  300. }
Success #stdin #stdout 0s 3096KB
stdin
Standard input is empty
stdout
0 1 2 3 4 5 
0 3 1 4 2 5