-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathMultiArray.hpp
133 lines (118 loc) · 4.38 KB
/
MultiArray.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#pragma once
#include <cstddef>
#include <sstream>
#include <stdexcept>
#include <vector>
namespace cda_rail {
template <typename T> class MultiArray {
private:
std::vector<size_t> shape;
std::vector<T> data;
public:
// Constructor with arbitrary number of size_t parameters
template <typename... Args> explicit MultiArray(Args... args);
// getter with arbitrary number of size_t parameters
template <typename... Args> T& operator()(Args... args);
template <typename... Args> T at(Args... args) const;
// Function to obtain shape, size and dimensions
[[nodiscard]] const std::vector<size_t>& get_shape() const { return shape; };
[[nodiscard]] size_t size() const { return data.size(); };
[[nodiscard]] size_t dimensions() const { return shape.size(); };
};
template <typename T>
template <typename... Args>
T& MultiArray<T>::operator()(Args... args) {
/**
* Getter for an arbitrary number of dimensions.
* The first parameter is the index of the first dimension.
* The remaining parameters are the indices of the remaining dimensions.
* The number of parameters must coincide with the number of dimensions
* specified in shape. The value of each parameter must be smaller than the
* size of the corresponding dimension.
*
* @param first Index of the first dimension
* @param args Indices of the remaining dimensions
*/
// If the number of dimensions and number of arguments does not coincide throw
// an error
if (shape.size() != sizeof...(args)) {
throw std::invalid_argument(
"Number of dimensions and number of arguments do not coincide.");
}
// If the value of any argument is too large throw an error
std::vector<size_t> arg_tuple = {static_cast<size_t>(args)...};
for (size_t i = 0; i < sizeof...(args); ++i) {
if (arg_tuple[i] >= shape[i]) {
std::stringstream ss;
ss << "Index " << arg_tuple[i] << " is too large for dimension " << i;
throw std::out_of_range(ss.str());
}
}
// Get the index of the element in the data respecting the row-major order
size_t index = 0;
size_t multiplier = 1;
for (size_t i = 0; i < sizeof...(args); ++i) {
index += arg_tuple[i] * multiplier;
multiplier *= shape[i];
}
return data[index];
}
template <typename T>
template <typename... Args>
T MultiArray<T>::at(Args... args) const {
/**
* Getter for an arbitrary number of dimensions.
* The first parameter is the index of the first dimension.
* The remaining parameters are the indices of the remaining dimensions.
* The number of parameters must coincide with the number of dimensions
* specified in shape. The value of each parameter must be smaller than the
* size of the corresponding dimension.
*
* @param first Index of the first dimension
* @param args Indices of the remaining dimensions
*/
// If the number of dimensions and number of arguments does not coincide throw
// an error
if (shape.size() != sizeof...(args)) {
throw std::invalid_argument(
"Number of dimensions and number of arguments do not coincide.");
}
// If the value of any argument is too large throw an error
std::vector<size_t> arg_tuple = {static_cast<size_t>(args)...};
for (size_t i = 0; i < sizeof...(args); ++i) {
if (arg_tuple[i] >= shape[i]) {
std::stringstream ss;
ss << "Index " << arg_tuple[i] << " is too large for dimension " << i;
throw std::out_of_range(ss.str());
}
}
// Get the index of the element in the data respecting the row-major order
size_t index = 0;
size_t multiplier = 1;
for (size_t i = 0; i < sizeof...(args); ++i) {
index += arg_tuple[i] * multiplier;
multiplier *= shape[i];
}
return data[index];
}
template <typename T>
template <typename... Args>
MultiArray<T>::MultiArray(Args... args)
: shape({static_cast<size_t>(args)...}) {
/**
* Constructor for an arbitrary number of dimensions.
* The first parameter is the size of the first dimension.
* The remaining parameters are the sizes of the remaining dimensions.
*
* @param first Size of the first dimension
* @param args Sizes of the remaining dimensions
*/
// If shape has only one element, allocate data
// The overall size of the array is the product of all elements in shape.
size_t cap = 1;
for (auto& shape_dim : shape) {
cap *= shape_dim;
}
data = std::vector<T>(cap);
}
} // namespace cda_rail