31 NdArray<T>::Iterator<Const>::Iterator(ContainerInterface* container_ptr,
size_t offset,
34 : m_container_ptr(container_ptr)
36 , m_row_size(std::
accumulate(shape.
begin(), shape.
end(), 1, std::multiplies<size_t>()))
37 , m_stride{strides.
back()}
42 NdArray<T>::Iterator<Const>::Iterator(ContainerInterface* container_ptr,
size_t offset,
size_t row_size,
size_t stride,
44 : m_container_ptr(container_ptr), m_offset(offset), m_row_size(row_size), m_stride(stride), m_i(start) {}
48 NdArray<T>::Iterator<Const>::Iterator(
const Iterator<false>& other)
49 : m_container_ptr{other.m_container_ptr}
50 , m_offset{other.m_offset}
51 , m_row_size{other.m_row_size}
52 , m_stride{other.m_stride}
57 auto NdArray<T>::Iterator<Const>::operator++() -> Iterator& {
64 auto NdArray<T>::Iterator<Const>::operator++(
int) ->
const Iterator {
65 return Iterator{m_container_ptr, m_offset, m_row_size, m_stride, m_i + 1};
70 bool NdArray<T>::Iterator<Const>::operator==(
const Iterator& other)
const {
71 return std::memcmp(
this, &other,
sizeof(*
this)) == 0;
77 return !(*
this == other);
82 auto NdArray<T>::Iterator<Const>::operator*() -> value_t& {
88 auto NdArray<T>::Iterator<Const>::operator*() const -> value_t {
94 auto NdArray<T>::Iterator<Const>::operator+=(
size_t n) -> Iterator& {
100 template <
bool Const>
101 auto NdArray<T>::Iterator<Const>::operator+(
size_t n)
const -> Iterator {
102 return Iterator{m_container_ptr, m_offset, m_row_size, m_stride, m_i + n};
105 template <
typename T>
106 template <
bool Const>
107 auto NdArray<T>::Iterator<Const>::operator-=(
size_t n) -> Iterator& {
113 template <
typename T>
114 template <
bool Const>
115 auto NdArray<T>::Iterator<Const>::operator-(
size_t n)
const -> Iterator {
117 return Iterator{m_container_ptr, m_offset, m_row_size, m_stride, m_i - n};
120 template <
typename T>
121 template <
bool Const>
122 auto NdArray<T>::Iterator<Const>::operator-(
const Iterator& other) -> difference_type {
123 assert(m_container_ptr == other.m_container_ptr);
124 return m_i - other.m_i;
127 template <
typename T>
128 template <
bool Const>
129 auto NdArray<T>::Iterator<Const>::operator[](
size_t i) -> value_t& {
130 return m_container_ptr->get(m_offset + (m_i + i) * m_stride);
133 template <
typename T>
134 template <
bool Const>
135 auto NdArray<T>::Iterator<Const>::operator[](
size_t i)
const -> value_t {
136 return m_container_ptr->get(m_offset + (m_i + i) * m_stride);
139 template <
typename T>
140 template <
bool Const>
141 bool NdArray<T>::Iterator<Const>::operator<(
const Iterator& other) {
142 assert(m_container_ptr == other.m_container_ptr);
143 return m_i < other.m_i;
146 template <
typename T>
147 template <
bool Const>
148 bool NdArray<T>::Iterator<Const>::operator>(
const Iterator& other) {
149 assert(m_container_ptr == other.m_container_ptr);
150 return m_i > other.m_i;
153 template <
typename T>
156 , m_shape(std::
move(shape_))
157 , m_size(std::
accumulate(m_shape.
begin(), m_shape.
end(), 1u, std::multiplies<size_t>()))
158 , m_container(new ContainerWrapper<std::vector>(m_size)) {
162 template <
typename T>
163 template <
template <
class...>
class Container>
166 , m_shape(std::
move(shape_))
167 , m_size(std::
accumulate(m_shape.
begin(), m_shape.
end(), 1u, std::multiplies<size_t>()))
168 , m_container(new ContainerWrapper<Container>(data)) {
169 if (m_size != m_container->size()) {
175 template <
typename T>
176 template <
template <
class...>
class Container>
179 , m_shape(std::
move(shape_))
180 , m_size(std::
accumulate(m_shape.
begin(), m_shape.
end(), 1u, std::multiplies<size_t>()))
181 , m_container(new ContainerWrapper<Container>(std::
move(data))) {
182 if (m_size != m_container->size()) {
188 template <
typename T>
189 template <
template <
class...>
class Container>
192 , m_shape(std::
move(shape_))
193 , m_stride_size(std::
move(strides_))
194 , m_size(std::
accumulate(m_shape.
begin(), m_shape.
end(), 1u, std::multiplies<size_t>()))
195 , m_total_stride(m_shape.front() * m_stride_size.front())
196 , m_container(new ContainerWrapper<Container>(std::
move(data))) {
197 if (m_shape.size() != m_stride_size.size()) {
200 if (!
std::is_sorted(m_stride_size.rbegin(), m_stride_size.rend())) {
205 template <
typename T>
206 template <
typename II>
209 , m_shape(std::
move(shape_))
210 , m_size(std::
accumulate(m_shape.
begin(), m_shape.
end(), 1u, std::multiplies<size_t>()))
211 , m_container(new ContainerWrapper<std::vector>(ibegin, iend)) {
212 if (m_size != m_container->size()) {
218 template <
typename T>
219 NdArray<T>::NdArray(
const self_type* other)
221 , m_shape(other->m_shape)
222 , m_attr_names(other->m_attr_names)
223 , m_size(std::
accumulate(m_shape.
begin(), m_shape.
end(), 1u, std::multiplies<size_t>()))
224 , m_container(other->m_container->
copy()) {
234 template <
typename T>
235 template <
typename... Args>
237 : NdArray(appendAttrShape(shape_, attr_names.size()), std::
forward<Args>(args)...) {
238 m_attr_names = attr_names;
241 template <
typename T>
243 if (!m_attr_names.empty())
247 if (new_size != m_size) {
248 throw std::range_error(
"New shape does not match the number of contained elements");
255 template <
typename T>
256 template <
typename... D>
257 auto NdArray<T>::reshape(
size_t i, D... rest) -> self_type& {
259 return reshape_helper(acc, rest...);
262 template <
typename T>
264 auto offset = get_offset(coords);
266 return m_container->get(offset);
269 template <
typename T>
271 auto offset = get_offset(coords);
273 return m_container->get(offset);
276 template <
typename T>
278 auto offset = get_offset(coords, attr);
280 return m_container->get(offset);
283 template <
typename T>
285 auto offset = get_offset(coords, attr);
287 return m_container->get(offset);
290 template <
typename T>
291 template <
typename... D>
292 T& NdArray<T>::at(
size_t i, D... rest) {
293 return at_helper(m_offset, 0, i, rest...);
296 template <
typename T>
297 template <
typename... D>
298 const T& NdArray<T>::at(
size_t i, D... rest)
const {
299 return at_helper(m_offset, 0, i, rest...);
302 template <
typename T>
303 auto NdArray<T>::begin() -> iterator {
304 return iterator{m_container.get(), m_offset, m_shape, m_stride_size, 0};
307 template <
typename T>
308 auto NdArray<T>::end() -> iterator {
309 return iterator{m_container.get(), m_offset, m_shape, m_stride_size, size()};
312 template <
typename T>
313 auto NdArray<T>::begin() const -> const_iterator {
314 return const_iterator{m_container.get(), m_offset, m_shape, m_stride_size, 0};
317 template <
typename T>
318 auto NdArray<T>::end() const -> const_iterator {
319 return const_iterator{m_container.get(), m_offset, m_shape, m_stride_size, size()};
322 template <
typename T>
323 size_t NdArray<T>::size()
const {
327 template <
typename T>
328 bool NdArray<T>::operator==(
const self_type& b)
const {
329 if (shape() != b.shape())
331 for (
auto ai =
begin(), bi = b.begin(); ai !=
end() && bi != b.end(); ++ai, ++bi) {
338 template <
typename T>
340 return !(*
this == b);
343 template <
typename T>
348 template <
typename T>
349 auto NdArray<T>::concatenate(
const self_type& other) -> self_type& {
351 if (m_shape.size() != other.m_shape.size()) {
352 throw std::length_error(
"Can not concatenate arrays with different dimensionality");
354 for (
size_t i = 1; i < m_shape.size(); ++i) {
355 if (m_shape[i] != other.m_shape[i])
356 throw std::length_error(
"The size of all axis except for the first one must match");
360 auto old_size = size();
361 auto new_shape = m_shape;
362 new_shape[0] += other.m_shape[0];
365 m_container->resize(new_shape);
371 m_size += other.m_size;
375 template <
typename T>
379 , m_shape(std::
move(shape_))
380 , m_stride_size(std::
move(stride))
381 , m_attr_names(std::
move(attr_names))
382 , m_size(std::
accumulate(m_shape.
begin(), m_shape.
end(), 1, std::multiplies<size_t>()))
383 , m_total_stride(m_stride_size.front() * m_shape.front())
384 , m_container(std::
move(container)) {}
386 template <
typename T>
387 auto NdArray<T>::slice(
size_t i) -> self_type {
388 if (m_shape.size() <= 1) {
392 if (!m_attr_names.empty()) {
393 attrs.
resize(m_attr_names.size());
394 std::copy(m_attr_names.begin(), m_attr_names.end(), attrs.
begin());
396 if (i >= m_shape[0]) {
399 auto offset = m_offset + i * m_stride_size[0];
405 template <
typename T>
406 auto NdArray<T>::slice(
size_t i)
const ->
const self_type {
407 return const_cast<NdArray<T>*
>(
this)->slice(i);
410 template <
typename T>
411 auto NdArray<T>::rslice(
size_t i) -> self_type {
412 if (m_shape.size() <= 1) {
415 if (!m_attr_names.empty()) {
418 if (i >= m_shape.back()) {
421 auto offset = m_offset + i * m_stride_size.back();
424 return NdArray(m_container, offset,
std::move(shape_),
std::move(strides_), m_attr_names);
427 template <
typename T>
428 auto NdArray<T>::rslice(
size_t i)
const ->
const self_type {
429 return const_cast<NdArray<T>*
>(
this)->rslice(i);
432 template <
typename T>
433 void NdArray<T>::next_slice() {
434 m_offset += m_total_stride;
437 template <
typename T>
439 if (coords.
size() != m_shape.size()) {
444 size_t offset = m_offset;
445 for (
size_t i = 0; i < coords.
size(); ++i) {
446 if (coords[i] >= m_shape[i]) {
450 offset += coords[i] * m_stride_size[i];
453 assert(offset < m_container->nbytes());
457 template <
typename T>
458 size_t NdArray<T>::get_attr_offset(
const std::string& attr)
const {
459 auto i =
std::find(m_attr_names.begin(), m_attr_names.end(), attr);
460 if (i == m_attr_names.end())
462 return (i - m_attr_names.begin()) *
sizeof(T);
465 template <
typename T>
466 void NdArray<T>::update_strides() {
467 m_stride_size.resize(m_shape.size());
469 size_t acc =
sizeof(T);
470 for (
size_t i = m_stride_size.size(); i > 0; --i) {
471 m_stride_size[i - 1] = acc;
472 acc *= m_shape[i - 1];
475 m_total_stride = m_shape.front() * m_stride_size.front();
481 template <
typename T>
482 template <
typename... D>
483 T& NdArray<T>::at_helper(
size_t offset_acc,
size_t axis,
size_t i, D... rest) {
484 assert(axis <= m_shape.size() && i < m_shape[axis]);
485 offset_acc += i * m_stride_size[axis];
486 return at_helper(offset_acc, ++axis, rest...);
489 template <
typename T>
490 T& NdArray<T>::at_helper(
size_t offset_acc, ELEMENTS_UNUSED
size_t axis) {
491 assert(axis == m_shape.size());
492 assert(offset_acc < m_container->nbytes());
493 return m_container->get(offset_acc);
496 template <
typename T>
497 T& NdArray<T>::at_helper(
size_t offset_acc, ELEMENTS_UNUSED
size_t axis,
const std::string& attr) {
498 offset_acc += get_attr_offset(attr);
499 assert(axis == m_shape.size() - 1);
500 assert(offset_acc < m_container->nbytes());
501 return m_container->get(offset_acc);
504 template <
typename T>
505 template <
typename... D>
506 const T& NdArray<T>::at_helper(
size_t offset_acc,
size_t axis,
size_t i, D... rest)
const {
507 assert(axis <= m_shape.size() && i < m_shape[axis]);
508 offset_acc += i * m_stride_size[axis];
509 return at_helper(offset_acc, ++axis, rest...);
512 template <
typename T>
513 const T& NdArray<T>::at_helper(
size_t offset_acc, ELEMENTS_UNUSED
size_t axis)
const {
514 assert(axis == m_shape.size());
515 assert(offset_acc < m_container->nbytes());
517 return m_container->get(offset_acc);
520 template <
typename T>
521 const T& NdArray<T>::at_helper(
size_t offset_acc, ELEMENTS_UNUSED
size_t axis,
const std::string& attr)
const {
522 offset_acc += get_attr_offset(attr);
523 assert(axis == m_shape.size() - 1);
524 assert(offset_acc < m_container->nbytes());
526 return m_container->get(offset_acc);
529 template <
typename T>
530 template <
typename... D>
531 auto NdArray<T>::reshape_helper(
std::vector<size_t>& acc,
size_t i, D... rest) -> self_type& {
533 return reshape_helper(acc, rest...);
536 template <
typename T>
541 template <
typename T>
542 std::ostream& operator<<(std::ostream& out, const NdArray<T>& ndarray) {
543 auto shape = ndarray.shape();
545 if (ndarray.size()) {
548 for (i = 0; i < shape.
size() - 1; ++i) {
549 out << shape[i] <<
",";
551 out << shape[i] <<
">";
553 auto iter = ndarray.
begin(), end_iter = ndarray.end() - 1;
554 for (; iter != end_iter; ++iter) {
565 #endif // NDARRAY_IMPL
bool operator!=(const Euclid::SourceCatalog::Source::id_type &a, const Euclid::SourceCatalog::Source::id_type &b)
boost::variant specifies an equality operator (==), but, in older boost versions, not an inequality o...