fork 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. const int width = 3, height = 2;
  269. int i;
  270.  
  271. Array<int, StorageOrder::rowMajor, height, width> rowArray;
  272. i = 0;
  273. for (auto it = rowArray.elementWiseBegin(); it != rowArray.elementWiseEnd(); ++it) {
  274. *it = i++;
  275. }
  276.  
  277. Array<int, StorageOrder::columnMajor, height, width> columnArray;
  278. i = 0;
  279. for (auto it = columnArray.elementWiseBegin(); it != columnArray.elementWiseEnd(); ++it) {
  280. *it = i++;
  281. }
  282.  
  283. // Show internal storage order for row
  284. for (auto &value : rowArray) {
  285. std::cout << value << " ";
  286. }
  287. std::cout << std::endl;
  288.  
  289. // Show internal storage order for column
  290. for (auto &value : columnArray) {
  291. std::cout << value << " ";
  292. }
  293. std::cout << std::endl;
  294.  
  295. auto cit = columnArray.elementWiseBegin();
  296. auto rit = rowArray.elementWiseBegin();
  297. // Compare elements
  298. for (int i = 0; i < height * width; ++i) {
  299. std::cout << *cit << " == " << *rit << "\n";
  300. ++cit; ++rit;
  301. }
  302. std::cout << std::endl;
  303.  
  304. return 0;
  305. }
Success #stdin #stdout 0s 3140KB
stdin
Standard input is empty
stdout
0 1 2 3 4 5 
0 2 4 1 3 5 
0 == 0
1 == 1
2 == 2
3 == 3
4 == 4
5 == 5