Expression Templates Library (ETL)
dyn_base.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c) 2014-2023 Baptiste Wicht
3 // Distributed under the terms of the MIT License.
4 // (See accompanying file LICENSE or copy at
5 // http://opensource.org/licenses/MIT)
6 //=======================================================================
7 
13 #pragma once
14 
15 #include "etl/index.hpp"
16 #include <type_traits>
17 
18 namespace etl {
19 
23 enum class init_flag_t {
24  DUMMY
25 };
26 
31 
35 template <typename... V>
36 struct values_t {
37  const std::tuple<V...> values;
38 
42  explicit values_t(V... v) : values(v...){};
43 
48  template <typename T>
49  std::vector<T> list() const {
50  return list_sub<T>(std::make_index_sequence<sizeof...(V)>());
51  }
52 
53 private:
57  template <typename T, size_t... I>
58  std::vector<T> list_sub(const std::index_sequence<I...>& /*i*/) const {
59  return {static_cast<T>(std::get<I>(values))...};
60  }
61 };
62 
66 template <typename... V>
67 values_t<V...> values(V... v) {
68  return values_t<V...>{v...};
69 }
70 
71 namespace dyn_detail {
72 
76 template <typename... S>
77 struct is_init_constructor : std::false_type {};
78 
82 template <typename S1, typename S2, typename S3, typename... S>
83 struct is_init_constructor<S1, S2, S3, S...> : std::is_same<init_flag_t, typename cpp::nth_type<sizeof...(S), S2, S3, S...>::type> {};
84 
88 template <typename... S>
89 struct is_initializer_list_constructor : std::false_type {};
90 
94 template <typename S1, typename S2, typename... S>
95 struct is_initializer_list_constructor<S1, S2, S...> : cpp::is_specialization_of<std::initializer_list, typename cpp::last_type<S2, S...>::type> {};
96 
100 template <size_t... I, typename... T>
101 inline std::array<size_t, sizeof...(I)> sizes(const std::index_sequence<I...>& /*i*/, const T&... args) {
102  return {{static_cast<size_t>(cpp::nth_value<I>(args...))...}};
103 }
104 
105 } // end of namespace dyn_detail
106 
112 template <typename Derived, typename T, size_t D>
113 requires(D > 0) struct dyn_base {
114 protected:
115  static constexpr size_t n_dimensions = D;
116  static constexpr size_t alignment = default_intrinsic_traits<T>::alignment;
117 
118  using value_type = T;
119  using dimension_storage_impl = std::array<size_t, n_dimensions>;
120  using memory_type = value_type*;
121  using const_memory_type = const value_type*;
122  using derived_t = Derived;
123  using this_type = dyn_base<Derived, T, D>;
124 
125  size_t _size;
126  dimension_storage_impl _dimensions;
127 
134  void check_invariants() {
135  cpp_assert(_dimensions.size() == D, "Invalid dimensions");
136 
137 #ifndef NDEBUG
138  auto computed = std::accumulate(_dimensions.begin(), _dimensions.end(), size_t(1), std::multiplies<size_t>());
139  cpp_assert(computed == _size, "Incoherency in dimensions");
140 #endif
141  }
142 
149  template <typename M = value_type>
150  static M* allocate(size_t n) {
151  inc_counter("cpu:allocate");
152 
153  cpp_assert(n, "Impossible allocate zero elements");
154 
155  M* memory = aligned_allocator<alignment>::template allocate<M>(n);
156 
157  cpp_assert(memory, "Impossible to allocate memory for dyn_matrix");
158  cpp_assert(reinterpret_cast<uintptr_t>(memory) % alignment == 0, "Failed to align memory of matrix");
159 
160  //In case of non-trivial type, we need to call the constructors
161  if constexpr (!std::is_trivially_default_constructible_v<M>) {
162  new (memory) M[n]();
163  }
164 
165  if constexpr (padding) {
166  std::fill_n(memory, n, M());
167  }
168 
169  return memory;
170  }
171 
177  template <typename M>
178  static void release(M* ptr, size_t n) {
179  //In case of non-trivial type, we need to call the destructors
180  if constexpr (!std::is_trivially_default_constructible_v<M>) {
181  for (size_t i = 0; i < n; ++i) {
182  ptr[i].~M();
183  }
184  }
185 
187  }
188 
192  dyn_base() noexcept : _size(0) {
193  std::fill(_dimensions.begin(), _dimensions.end(), 0);
194 
195  check_invariants();
196  }
197 
202  dyn_base(const dyn_base& rhs) noexcept = default;
203 
208  dyn_base(dyn_base&& rhs) noexcept = default;
209 
215  dyn_base(size_t size, dimension_storage_impl dimensions) noexcept : _size(size), _dimensions(dimensions) {
216  check_invariants();
217  }
218 
223  template <etl_expr E>
224  explicit dyn_base(E&& rhs) requires(!std::same_as<std::decay<E>, derived_t>) : _size(etl::size(rhs)) {
225  for (size_t d = 0; d < etl::dimensions(rhs); ++d) {
226  _dimensions[d] = etl::dim(rhs, d);
227  }
228 
229  check_invariants();
230  }
231 
232 public:
237  static constexpr size_t dimensions() noexcept {
238  return n_dimensions;
239  }
240 
245  size_t size() const noexcept {
246  return _size;
247  }
248 
253  size_t rows() const noexcept {
254  return _dimensions[0];
255  }
256 
261  size_t columns() const noexcept requires(n_dimensions > 1) {
262  return _dimensions[1];
263  }
264 
270  size_t dim(size_t d) const noexcept(assert_nothrow) {
271  cpp_assert(d < n_dimensions, "Invalid dimension");
272 
273  return _dimensions[d];
274  }
275 
280  template <size_t D2>
281  size_t dim() const noexcept(assert_nothrow) {
282  cpp_assert(D2 < n_dimensions, "Invalid dimension");
283 
284  return _dimensions[D2];
285  }
286 };
287 
293 template <typename Derived, typename T, order SO, size_t D>
294 struct dense_dyn_base : dyn_base<Derived, T, D> {
295  using value_type = T;
296  using base_type = dyn_base<Derived, T, D>;
298  using derived_t = Derived;
300  using const_memory_type = const value_type*;
303 
304  using dimension_storage_impl = typename base_type::dimension_storage_impl;
305 
306  static constexpr size_t n_dimensions = D;
307  static constexpr order storage_order = SO;
308 
309  using base_type::_size;
310  using base_type::dim;
311 
312  value_type* ETL_RESTRICT _memory = nullptr;
314 
318  dense_dyn_base() noexcept : base_type() {
319  //Nothing else to init
320  }
321 
326  dense_dyn_base(const dense_dyn_base& rhs) noexcept : base_type(rhs), _gpu(rhs._gpu) {
327  //Nothing else to init
328  }
329 
338  explicit dense_dyn_base(const derived_t& rhs) noexcept : base_type(rhs), _gpu(rhs._gpu) {
339  //Nothing else to init
340  }
341 
346  dense_dyn_base(dense_dyn_base&& rhs) noexcept : base_type(std::move(rhs)), _gpu(std::move(rhs._gpu)) {
347  //Nothing else to init
348  }
349 
358  explicit dense_dyn_base(derived_t&& rhs) noexcept : base_type(std::move(rhs)), _gpu(std::move(rhs._gpu)) {
359  //Nothing else to init
360  }
361 
367  dense_dyn_base(size_t size, dimension_storage_impl dimensions) noexcept : base_type(size, dimensions) {
368  //Nothing else to init
369  }
370 
375  template <etl_expr E>
376  explicit dense_dyn_base(E&& rhs) requires(!std::same_as<std::decay_t<E>, derived_t>) : base_type(std::forward(rhs)) {
377  //Nothing else to init
378  }
379 
392  decltype(auto) operator()(size_t i) noexcept(assert_nothrow) {
393  cpp_assert(i < dim(0), "Out of bounds");
394 
395  if constexpr (n_dimensions == 1) {
397  invalidate_gpu();
398 
399  return _memory[i];
400  } else {
401  return sub(as_derived(), i);
402  }
403  }
404 
417  decltype(auto) operator()(size_t i) const noexcept(assert_nothrow) {
418  cpp_assert(i < dim(0), "Out of bounds");
419 
420  if constexpr (n_dimensions == 1) {
422 
423  return _memory[i];
424  } else {
425  return sub(as_derived(), i);
426  }
427  }
428 
434  template <size_c... S>
435  const value_type& operator()(S... sizes) const noexcept(assert_nothrow) requires(sizeof...(S) > 1 && sizeof...(S) == n_dimensions) {
437  return _memory[etl::dyn_index(as_derived(), sizes...)];
438  }
439 
445  template <size_c... S>
446  value_type& operator()(S... sizes) noexcept(assert_nothrow) requires(sizeof...(S) > 1 && sizeof...(S) == n_dimensions){
448  invalidate_gpu();
449  return _memory[etl::dyn_index(as_derived(), sizes...)];
450  }
451 
457  template <size_c... S>
458  const value_type& operator[](size_t first, S... sizes) const noexcept(assert_nothrow) requires(sizeof...(S) >= 1 && (1 + sizeof...(S)) == n_dimensions) {
460  return _memory[etl::dyn_index(as_derived(), first, sizes...)];
461  }
462 
468  template <size_c... S>
469  value_type& operator[](size_t first, S... sizes) noexcept(assert_nothrow) requires(sizeof...(S) >= 1 && (1 + sizeof...(S)) == n_dimensions){
471  invalidate_gpu();
472  return _memory[etl::dyn_index(as_derived(), first, sizes...)];
473  }
474 
480  const value_type& operator[](size_t i) const noexcept(assert_nothrow) {
481  cpp_assert(i < _size, "Out of bounds");
482 
484 
485  return _memory[i];
486  }
487 
493  value_type& operator[](size_t i) noexcept(assert_nothrow) {
494  cpp_assert(i < _size, "Out of bounds");
495 
497  invalidate_gpu();
498 
499  return _memory[i];
500  }
501 
508  value_type read_flat(size_t i) const noexcept(assert_nothrow) {
509  cpp_assert(i < _size, "Out of bounds");
510 
512 
513  return _memory[i];
514  }
515 
521  template <typename E>
522  bool alias(const E& rhs) const noexcept {
523  if constexpr (is_dma<E>) {
524  return memory_alias(memory_start(), memory_end(), rhs.memory_start(), rhs.memory_end());
525  } else {
526  return rhs.alias(as_derived());
527  }
528  }
529 
534  inline memory_type memory_start() noexcept {
535  return _memory;
536  }
537 
542  inline const_memory_type memory_start() const noexcept {
543  return _memory;
544  }
545 
550  memory_type memory_end() noexcept {
551  return _memory + _size;
552  }
553 
558  const_memory_type memory_end() const noexcept {
559  return _memory + _size;
560  }
561 
568  auto slice(size_t first, size_t last) noexcept {
569  return etl::slice(as_derived(), first, last);
570  }
571 
578  auto slice(size_t first, size_t last) const noexcept {
579  return etl::slice(as_derived(), first, last);
580  }
581 
586  T* gpu_memory() const noexcept {
587  return _gpu.gpu_memory();
588  }
589 
593  void gpu_evict() const noexcept {
594  _gpu.gpu_evict();
595  }
596 
600  void invalidate_cpu() const noexcept {
601  _gpu.invalidate_cpu();
602  }
603 
607  void invalidate_gpu() const noexcept {
608  _gpu.invalidate_gpu();
609  }
610 
614  void validate_cpu() const noexcept {
615  _gpu.validate_cpu();
616  }
617 
621  void validate_gpu() const noexcept {
622  _gpu.validate_gpu();
623  }
624 
629  void ensure_gpu_allocated() const {
630  _gpu.ensure_gpu_allocated(_size);
631  }
632 
636  void ensure_gpu_up_to_date() const {
637  _gpu.ensure_gpu_up_to_date(memory_start(), _size);
638  }
639 
644  void ensure_cpu_up_to_date() const {
645  _gpu.ensure_cpu_up_to_date(memory_start(), _size);
646  }
647 
652  void gpu_copy_from(const T* gpu_memory) const {
653  _gpu.gpu_copy_from(gpu_memory, _size);
654  }
655 
660  bool is_cpu_up_to_date() const noexcept {
661  return _gpu.is_cpu_up_to_date();
662  }
663 
668  bool is_gpu_up_to_date() const noexcept {
669  return _gpu.is_gpu_up_to_date();
670  }
671 
672 private:
677  derived_t& as_derived() noexcept {
678  return *static_cast<derived_t*>(this);
679  }
680 
685  const derived_t& as_derived() const noexcept {
686  return *static_cast<const derived_t*>(this);
687  }
688 };
689 
690 } //end of namespace etl
Simple collection of values to initialize a dyn matrix.
Definition: dyn_base.hpp:36
constexpr bool padding
Indicates if ETL is allowed to pad matrices and vectors.
Definition: config.hpp:135
const_memory_type const_iterator
The type of const iterator.
Definition: dyn_base.hpp:302
void ensure_gpu_allocated() const
Ensures that the GPU memory is allocated and that the GPU memory is up to date (to undefined value)...
Definition: sub_view.hpp:717
dense_dyn_base(E &&rhs) requires(!std
Move construct a dense_dyn_base.
Definition: dyn_base.hpp:376
Dense Matrix with run-time fixed dimensions. The matrix support an arbitrary number of dimensions...
Definition: dyn_base.hpp:294
Dummy value for the flag.
const value_type * const_memory_type
The const memory type.
Definition: dyn_base.hpp:300
auto slice(E &&value, size_t first, size_t last) -> slice_view< detail::build_identity_type< E >>
Returns view representing a slice view of the given expression.
Definition: view_expression_builder.hpp:112
value_type * memory_type
The memory type.
Definition: dyn_base.hpp:299
bool alias(const E &rhs) const noexcept
Test if this expression aliases with the given expression.
Definition: dyn_matrix_view.hpp:197
void ensure_gpu_up_to_date([[maybe_unused]] const T *cpu_memory, [[maybe_unused]] size_t etl_size) const
Allocate memory on the GPU for the expression and copy the values into the GPU.
Definition: gpu_handler.hpp:611
values_t< V... > values(V... v)
Create a list of values for initializing a dyn_matrix.
Definition: dyn_base.hpp:67
value_t< sub_type > value_type
The value contained in the expression.
Definition: dyn_matrix_view.hpp:31
void gpu_evict() const noexcept
Evict the expression from GPU.
Definition: gpu_handler.hpp:577
const_memory_t< sub_type > const_memory_type
The const memory access type.
Definition: dyn_matrix_view.hpp:33
D D
The number of dimensions.
Definition: dyn_matrix_view.hpp:24
Base class and utilities for dyn matrix implementations.
Define traits to get vectorization information for types when no vector mode is available.
Definition: no_vectorization.hpp:16
order
Storage order of a matrix.
Definition: order.hpp:15
T * gpu_memory() const noexcept
Return GPU memory of this expression, if any.
Definition: gpu_handler.hpp:554
values_t(V... v)
Construct a new sequence of values.
Definition: dyn_base.hpp:42
bool is_gpu_up_to_date() const noexcept
Indicates if the GPU memory is up to date.
Definition: gpu_handler.hpp:570
dense_dyn_base(const dense_dyn_base &rhs) noexcept
Copy construct a dense_dyn_base.
Definition: dyn_base.hpp:326
constexpr size_t dimensions() noexcept
Return the number of dimensions of the given ETL type.
Definition: helpers.hpp:28
bool is_cpu_up_to_date() const noexcept
Indicates if the CPU memory is up to date.
Definition: sub_view.hpp:777
void gpu_copy_from([[maybe_unused]] const value_type *new_gpu_memory) const
Copy from GPU to GPU.
Definition: sub_view.hpp:761
memory_t< sub_type > memory_type
The memory acess type.
Definition: dyn_matrix_view.hpp:32
dyn_base< this_type, T, D > base_type
The base type.
Definition: sparse.hpp:227
void validate_gpu() const noexcept
Validates the GPU memory.
Definition: gpu_handler.hpp:597
void gpu_evict() const noexcept
Evict the expression from GPU.
Definition: sub_view.hpp:681
typename base_type::dimension_storage_impl dimension_storage_impl
The storage type used to store the dimensions.
Definition: dyn_base.hpp:304
Root namespace for the ETL library.
Definition: adapter.hpp:15
void invalidate_gpu() const noexcept
Invalidates the GPU memory.
Definition: gpu_handler.hpp:587
bool memory_alias(const P1 *a_begin, const P1 *a_end, const P2 *b_begin, const P2 *b_end)
Test if two memory ranges overlap.
Definition: helpers.hpp:264
void invalidate_gpu() const noexcept
Invalidates the GPU memory.
Definition: sub_view.hpp:695
auto dim(E &&value, size_t i) -> detail::identity_helper< E, dim_view< detail::build_identity_type< E >, D >>
Return a view representing the ith Dth dimension.
Definition: view_expression_builder.hpp:25
const std::tuple< V... > values
The contained values.
Definition: dyn_base.hpp:37
init_flag_t
A simple type to use as init flag to constructor.
Definition: dyn_base.hpp:23
size_t columns(const E &expr)
Returns the number of columns of the given ETL expression.
Definition: helpers.hpp:78
void ensure_cpu_up_to_date() const
Ensures that the GPU memory is allocated and that the GPU memory is up to date (to undefined value)...
Definition: dyn_matrix_view.hpp:271
void invalidate_cpu() const noexcept
Invalidates the CPU memory.
Definition: sub_view.hpp:688
bool is_cpu_up_to_date() const noexcept
Indicates if the CPU memory is up to date.
Definition: gpu_handler.hpp:562
const_return_type operator()(size_t j) const
Access to the element at the given position.
Definition: dyn_matrix_view.hpp:89
Matrix with run-time fixed dimensions.
Definition: dyn.hpp:26
void ensure_gpu_allocated([[maybe_unused]] size_t etl_size) const
Ensures that the GPU memory is allocated and that the GPU memory is up to date (to undefined value)...
Definition: gpu_handler.hpp:604
value_type read_flat(size_t j) const noexcept
Returns the value at the given index This function never has side effects.
Definition: dyn_matrix_view.hpp:111
Allocated for aligned memory.
Definition: allocator.hpp:42
constexpr size_t size(const E &expr) noexcept
Returns the size of the given ETL expression.
Definition: helpers.hpp:108
requires(D > 0) struct dyn_base
Matrix with run-time fixed dimensions.
Definition: dyn_base.hpp:113
constexpr init_flag_t init_flag
A simple value to use as init flag to constructor.
Definition: dyn_base.hpp:30
bool is_gpu_up_to_date() const noexcept
Indicates if the GPU memory is up to date.
Definition: sub_view.hpp:785
void ensure_gpu_up_to_date() const
Copy back from the GPU to the expression memory if necessary.
Definition: dyn_matrix_view.hpp:280
Definition: expr_fwd.hpp:59
void validate_gpu() const noexcept
Validates the GPU memory.
Definition: sub_view.hpp:709
std::vector< T > list() const
Returns the sequence of values as a std::vector.
Definition: dyn_base.hpp:49
dyn_base< dyn_matrix_impl< T, SO, D >, T, D > base_type
The base type.
Definition: dyn_base.hpp:296
dense_dyn_base() noexcept
Initialize the dense_dyn_base with a size of 0.
Definition: dyn_base.hpp:318
std::array< size_t, n_dimensions > dimension_storage_impl
The type used to store the dimensions.
Definition: sparse.hpp:231
memory_type iterator
The type of iterator.
Definition: dyn_base.hpp:301
void validate_cpu() const noexcept
Validates the CPU memory.
Definition: gpu_handler.hpp:592
void invalidate_cpu() const noexcept
Invalidates the CPU memory.
Definition: gpu_handler.hpp:582
dense_dyn_base(size_t size, dimension_storage_impl dimensions) noexcept
Construct a dense_dyn_base if the given size and dimensions.
Definition: dyn_base.hpp:367
const_return_type operator[](size_t j) const
Returns the element at the given index.
Definition: dyn_matrix_view.hpp:71
auto allocate(size_t size, mangling_faker< S >=mangling_faker< S >())
Allocate an array of the given size for the given type.
Definition: allocator.hpp:80
Traits to test if the constructor is an initializer list constructor.
Definition: dyn_base.hpp:89
dense_dyn_base(dense_dyn_base &&rhs) noexcept
Move construct a dense_dyn_base.
Definition: dyn_base.hpp:346
dense_dyn_base(const derived_t &rhs) noexcept
Copy construct a derived_t.
Definition: dyn_base.hpp:338
size_t rows(const E &expr)
Returns the number of rows of the given ETL expression.
Definition: helpers.hpp:58
void ensure_cpu_up_to_date([[maybe_unused]] const T *cpu_memory, [[maybe_unused]] size_t etl_size) const
Copy back from the GPU to the expression memory if necessary.
Definition: gpu_handler.hpp:619
Traits to test if the constructor is an init constructor.
Definition: dyn_base.hpp:77
void inc_counter([[maybe_unused]] const char *name)
Increase the given counter.
Definition: counters.hpp:25
dense_dyn_base(derived_t &&rhs) noexcept
Move construct a derived_t.
Definition: dyn_base.hpp:358
void validate_cpu() const noexcept
Validates the CPU memory.
Definition: sub_view.hpp:702
value_type * gpu_memory() const noexcept
Return GPU memory of this expression, if any.
Definition: sub_view.hpp:674
Definition: gpu_handler.hpp:549
void gpu_copy_from([[maybe_unused]] const T *gpu_memory, [[maybe_unused]] size_t etl_size) const
Copy from GPU to GPU.
Definition: gpu_handler.hpp:626
gpu_memory_handler< T > _gpu
The GPU memory handler.
Definition: dyn_base.hpp:313
size_t dyn_index([[maybe_unused]] const T &expression, size_t i) noexcept(assert_nothrow)
Compute the index for a 1D dynamic matrix.
Definition: index.hpp:187