DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
Vector.hpp
Go to the documentation of this file.
1#pragma once
2/// @file Vector.hpp
3/// @brief Host-device vector types with optional GPU storage and device-side views.
4
5#include "DNDS/Errors.hpp"
6#include "DeviceStorage.hpp"
7#include <algorithm>
8#include <cstddef>
9#include <memory>
10#include <string>
11#include <utility>
12
13namespace DNDS
14{
15
16 /**
17 * @brief Abstract single-allocation owning byte buffer.
18 *
19 * @details A cross-backend "uniquely owned chunk of memory" interface:
20 * either a plain `std::vector<uint8_t>` on the host, or a
21 * backend-specific @ref DNDS::DeviceStorage "DeviceStorage" on a device. Used as the storage
22 * primitive for #host_device_vector_r1.
23 */
25 {
26 public:
29
30 /// @brief Allocate `bytes` on backend `B` (or on the host when @ref Unknown).
31 virtual void allocate(size_t bytes, DeviceBackend B = DeviceBackend::Unknown) = 0;
32 /// @brief Release the allocation.
33 virtual void free() = 0;
34 /// @brief Typed byte pointer to the current allocation.
35 virtual uint8_t *get() = 0;
36 /// @brief Allocation size in bytes.
37 virtual size_t bytes() const = 0;
38 /// @brief Which backend currently owns the allocation.
39 virtual DeviceBackend device() = 0;
40 /// @brief Copy `n` bytes from `host_src` into this allocation.
41 virtual void copy_from_host(uint8_t *host_src, size_t n) = 0;
42 /// @brief Copy `n` bytes from this allocation into `host_dst`.
43 virtual void copy_to_host(uint8_t *host_dst, size_t n) = 0;
44 /// @brief Deep copy; returns a new allocation containing the same bytes.
45 virtual std::unique_ptr<DeviceHostSingleAllocationBase> clone() = 0;
46 };
47
48 /**
49 * @brief Concrete @ref DNDS::DeviceHostSingleAllocationBase "DeviceHostSingleAllocationBase" using `std::vector<uint8_t>`
50 * for host memory and @ref DNDS::DeviceStorage "DeviceStorage" for device memory.
51 */
53 {
54 t_supDeviceStorageBase device_storage;
55 std::vector<uint8_t> host_data;
57 size_t bytes_ = 0;
58
60
61 public:
63
65
67 {
68 if (bytes_)
69 DNDS_check_throw_info(false, "single allocation already allocated");
70 bytes_ = bytes;
71 B_ = B;
72 if (B_ == DeviceBackend::Unknown)
73 host_data.resize(bytes_);
74 else
75 device_storage = device_storage_create(B, bytes_);
76 }
77 void free() override
78 {
80 bytes_ = 0;
81 device_storage = nullptr;
82 host_data.clear();
83 }
84 size_t bytes() const override { return bytes_; }
85 uint8_t *get() override
86 {
87 if (B_ == DeviceBackend::Unknown)
88 return host_data.data();
89 else
90 {
91 DNDS_check_throw_info(device_storage, "device storage not initialized");
92 return device_storage->raw_ptr();
93 }
94 }
95 DeviceBackend device() override { return B_; }
96
97 void copy_to_host(uint8_t *host_dst, size_t n) override
98 {
100 if (B_ == DeviceBackend::Unknown)
101 std::copy(host_data.begin(), host_data.begin() + n, host_dst);
102 else
103 {
104 DNDS_check_throw_info(device_storage, "device storage not initialized");
105 device_storage->copy_device_to_host(host_dst, n);
106 }
107 }
108
109 void copy_from_host(uint8_t *host_src, size_t n) override
110 {
112 if (B_ == DeviceBackend::Unknown)
113 std::copy(host_src, host_src + n, host_data.begin());
114 else
115 {
116 DNDS_check_throw_info(device_storage, "device storage not initialized");
117 device_storage->copy_host_to_device(host_src, n);
118 }
119 }
120
121 std::unique_ptr<DeviceHostSingleAllocationBase> clone() override
122 {
123 auto ret = std::make_unique<t_self>();
124 if (!bytes_)
125 return std::move(ret);
126 ret->allocate(bytes_, B_);
127 // if B_ == Host here, actually no allocation
128 if (B_ == DeviceBackend::Unknown)
129 std::copy(host_data.begin(), host_data.end(), ret->host_data.begin());
130 else
131 {
132 DNDS_check_throw_info(device_storage, "device storage not initialized");
133 device_storage->copy_to_device(ret->get(), bytes_);
134 // if B_ == Host here, actually no copy
135 }
136 return std::move(ret);
137 }
138 };
139
140 /**
141 * @brief Non-owning device-callable view `{pointer, size}` over a typed array.
142 *
143 * @details Analogue of `std::span<T>` that compiles inside `__device__` code.
144 * Constant copy semantics (trivially copyable); must not outlive its backing storage.
145 */
146 template <DeviceBackend B, typename T, typename TSize = int64_t>
148 {
149 static_assert(std::is_trivially_copyable_v<T> && std::is_default_constructible_v<T>,
150 "host_device_vector elements must be trivially_copyable and default_constructible");
151
152 T *_data = nullptr;
153 TSize _size = 0;
154
155 public:
157 DNDS_DEVICE_CALLABLE vector_DeviceView(T *n_data, TSize n_size) : _data(n_data), _size(n_size) {}
158
160 {
161 DNDS_HD_assert(i >= 0 && i < _size);
162 return _data[i];
163 }
165 {
166 DNDS_HD_assert(i >= 0 && i < _size);
167 return _data[i];
168 }
169 DNDS_DEVICE_CALLABLE TSize size() const { return _size; }
170 };
171
172 /**
173 * @brief CRTP base offering `operator[]` / `at` on top of a derived's
174 * `data()` and `size()` accessors. Used by both #host_device_vector_r1 and
175 * (implicitly) #host_device_vector_r0.
176 */
177 template <class T, class Derived>
179 {
180 static_assert(std::is_trivially_copyable_v<T> && std::is_default_constructible_v<T>,
181 "data_vector_base elements must be trivially_copyable and default_constructible");
182
183 public:
184 T &operator[](size_t i) { return static_cast<Derived *>(this)->data()[i]; }
185
186 const T &operator[](size_t i) const { return static_cast<const Derived *>(this)->data()[i]; }
187
188 const T &at(size_t i) const
189 {
190 auto *dThis = static_cast<const Derived *>(this);
191 DNDS_check_throw_info(dThis->size() > i, std::to_string(i) + " --- " + std::to_string(dThis->size()));
192 return this->operator[](i);
193 }
194
195 T &at(size_t i)
196 {
197 auto *dThis = static_cast<Derived *>(this);
198 DNDS_check_throw_info(dThis->size() > i, std::to_string(i) + " --- " + std::to_string(dThis->size()));
199 return this->operator[](i);
200 }
201 };
202
203 /**
204 * @brief Host + optional device vector of trivially copyable `T`.
205 *
206 * @details Primary storage type used inside @ref DNDS::Array "Array". Always maintains a
207 * host copy; on demand, a device mirror can be created via #to_device.
208 * Many "vector-like" `std::vector` operations (`resize`, `assign`,
209 * `operator[]`) have been reimplemented so the class can be used as a
210 * drop-in replacement in DNDSR code paths that need device-awareness.
211 *
212 * Use the variant #host_device_vector (a thin alias below) to pick up
213 * the appropriate specialisation based on element type.
214 */
215 template <typename T>
216 class host_device_vector_r1 : public data_vector_base<T, host_device_vector_r1<T>>
217 {
218 static_assert(std::is_trivially_copyable_v<T> && std::is_default_constructible_v<T>,
219 "host_device_vector elements must be trivially_copyable and default_constructible");
220 using t_self = host_device_vector_r1<T>;
222
223 std::unique_ptr<DeviceHostSingleAllocationBase> host_data = std::make_unique<DeviceHostSingleAllocationDirect>();
224 std::unique_ptr<DeviceHostSingleAllocationBase> device_data = std::make_unique<DeviceHostSingleAllocationDirect>();
225 T *host_ptr = reinterpret_cast<T *>(host_data->get());
226 T *device_ptr = reinterpret_cast<T *>(device_data->get());
227 size_t size_ = 0;
228
229 void sync_device_ptr()
230 {
231 device_ptr = reinterpret_cast<T *>(device_data->get());
232 }
233
234 void sync_host_ptr()
235 {
236 host_ptr = reinterpret_cast<T *>(host_data->get());
237 }
238
239 public:
241
243 {
244 this->resize(n);
245 }
246
247 template <class TFill>
249 {
250 this->resize(n, std::forward<TFill>(val));
251 }
252
253 // TODO: OPTIMIZE: support RVALUE reference of std::vector<T> HOW?
254 DNDS_HOST t_self &operator=(const std::vector<T> &v)
255 {
256 this->resize(v.size());
257 std::copy(v.begin(), v.end(), host_ptr);
258 return *this;
259 }
260
261 DNDS_HOST host_device_vector_r1(const std::vector<T> &v)
262 {
263 this->operator=(v);
264 }
265
266 DNDS_HOST size_t size() const { return size_; }
267
269 {
270 size_ = new_size;
271 host_data->free();
272 host_data->allocate(size_ * sizeof(T), DeviceBackend::Unknown);
273 sync_host_ptr();
274 }
275
276 template <class TFill>
278 {
279 this->resize(new_size);
280 std::fill(this->begin(), this->end(), std::forward<TFill>(fill));
281 }
282
284 {
285 device_data->free();
286 device_data->allocate(size_ * sizeof(T), B);
287 sync_device_ptr();
288 }
289
290 DNDS_HOST T *data() { return host_ptr; }
291 DNDS_HOST const T *data() const { return host_ptr; }
292
293 DNDS_HOST T *dataDevice() { return device_ptr; }
294 DNDS_HOST const T *dataDevice() const { return device_ptr; }
295
296 DNDS_HOST auto begin() { return host_ptr; }
297 DNDS_HOST auto end() { return host_ptr + size_; }
298 DNDS_HOST auto begin() const { return host_ptr; }
299 DNDS_HOST auto end() const { return host_ptr + size_; }
300
301 DNDS_HOST auto cbegin() const { return host_ptr; }
302 DNDS_HOST auto cend() const { return host_ptr + size_; }
303
304 DNDS_HOST explicit operator std::vector<T>() const
305 {
306 std::vector<T> ret;
307 ret.resize(this->size());
308 std::copy(this->begin(), this->end(), ret.begin());
309 return ret;
310 }
311
313 {
314 DNDS_check_throw_info(DeviceBackend::Unknown != backend, "cannot to_device to Unknown");
315 DNDS_check_throw_info(device_data, "device_data not initialized");
316 if (
317 device_data->bytes() != this->size() * sizeof(T) || // size change
318 device_data->device() != backend) // backend change
319 create_device_data(backend);
320
321 device_data->copy_from_host(reinterpret_cast<uint8_t *>(this->data()), this->size() * sizeof(T));
322 }
323
325 {
326 DNDS_check_throw_info(device_data, "device_data not initialized");
327 device_data->free();
328 sync_device_ptr();
329 }
330
332 {
333 clear_device();
334 host_data->free();
335 sync_host_ptr();
336 size_ = 0;
337 }
338
340 {
341 if (this->device() != DeviceBackend::Unknown)
342 {
343 DNDS_assert(device_data && host_data && device_data->bytes() == host_data->bytes());
344 device_data->copy_to_host(reinterpret_cast<uint8_t *>(this->data()), this->size() * sizeof(T));
345 }
346 }
347
348 template <DeviceBackend B, typename TSize = int64_t>
350 template <DeviceBackend B, typename TSize = int64_t>
352 {
354 "not on this device: " + std::string(device_backend_name(B)));
355 if constexpr (B == DeviceBackend::Host || B == DeviceBackend::Unknown)
356 return t_deviceView<B, TSize>(this->data(), this->size());
357 else
358 return t_deviceView<B, TSize>(this->dataDevice(), this->size());
359 }
360
361 t_self &operator=(const t_self &R)
362 {
363 if (this == &R)
364 return *this;
365 this->size_ = R.size();
366 this->host_data = R.host_data->clone();
367 this->sync_host_ptr();
368 this->device_data = R.device_data->clone();
369 //! the cloned host "device" has no idea where new data reference is
370 //! use to_device to sync it
371 if (this->device_data->device() == DeviceBackend::Host)
373 this->sync_device_ptr();
374 return *this;
375 }
376
378 {
379 this->size_ = R.size();
380 this->host_data = R.host_data->clone();
381 this->sync_host_ptr();
382 this->device_data = R.device_data->clone();
383 //! the cloned host "device" has no idea where new data reference is
384 //! use to_device to sync it
385 if (this->device_data->device() == DeviceBackend::Host)
387 this->sync_device_ptr();
388 }
389
391 {
392 return device_data ? device_data->device() : DeviceBackend::Unknown;
393 }
394
395 DNDS_HOST void swap(t_self &R) noexcept
396 {
397 R.device_data.swap(device_data);
398 std::swap(R.device_ptr, device_ptr);
399 R.host_data.swap(host_data);
400 std::swap(R.host_ptr, host_ptr);
401 std::swap(R.size_, size_);
402 }
403 };
404
405 /**
406 * @brief Legacy `std::vector<T>` subclass with an optional device mirror.
407 *
408 * @details Simpler predecessor of #host_device_vector_r1, kept for
409 * third-party interop that expected a true `std::vector<T>`. Prefer
410 * #host_device_vector (aliased to `_r1`) for new code.
411 */
412 template <typename T>
413 struct host_device_vector_r0 : public std::vector<T>
414 {
415 static_assert(std::is_trivially_copyable_v<T> && std::is_default_constructible_v<T>,
416 "host_device_vector elements must be trivially_copyable and default_constructible");
417 using t_base = std::vector<T>;
418 using t_base::t_base;
420
422
423 DNDS_HOST host_device_vector_r0(const std::vector<T> &v) : t_base(v) {}
424
425 DNDS_HOST t_self &operator=(const std::vector<T> &v)
426 {
427 this->t_base::operator=(v);
428 return *this;
429 }
430
431 // DNDS_HOST explicit operator std::vector<T>() const
432 // {
433 // std::vector<T> ret;
434 // ret.resize(this->size());
435 // std::copy(this->begin(), this->end(), ret.begin());
436 // return ret;
437 // }
438
440 {
441 DNDS_assert_info(DeviceBackend::Unknown != backend, "cannot to_device to Unknown");
442 if (!deviceStorage ||
443 deviceStorage->bytes() != this->size() * sizeof(T) || // size change
444 deviceStorage->backend() != backend) // backend change
445 deviceStorage = device_storage_create(backend, this->size() * sizeof(T));
446 deviceStorage->copy_host_to_device(reinterpret_cast<uint8_t *>(this->data()), this->size() * sizeof(T));
447 }
448
449 void to_host()
450 {
451 if (this->device() != DeviceBackend::Unknown)
452 {
453 DNDS_assert(deviceStorage);
454 deviceStorage->copy_device_to_host(reinterpret_cast<uint8_t *>(this->data()), this->size() * sizeof(T));
455 }
456 }
457
459 {
460 return deviceStorage ? reinterpret_cast<T *>(deviceStorage->raw_ptr()) : nullptr;
461 }
462
463 template <DeviceBackend B, typename TSize = int64_t>
465 template <DeviceBackend B, typename TSize = int64_t>
467 {
469 "not on this device: " + std::string(device_backend_name(B)));
470 if constexpr (B == DeviceBackend::Host || B == DeviceBackend::Unknown)
471 return t_deviceView<B, TSize>(this->data(), this->size());
472 else
473 return t_deviceView<B, TSize>(this->dataDevice(), this->size());
474 }
475
476 const T *dataDevice() const
477 {
478 return deviceStorage ? reinterpret_cast<const T *>(deviceStorage->raw_ptr()) : nullptr;
479 }
480
482 {
483 if (this == &R)
484 return *this;
485 this->t_base::operator=(R);
486 this->deviceStorage = R.deviceStorage ? device_storage_create(R.deviceStorage->backend(), R.deviceStorage->bytes()) : null_supDeviceStorageBase();
487 if (deviceStorage)
488 {
489 R.deviceStorage->copy_to_device(this->deviceStorage->raw_ptr(), this->deviceStorage->bytes());
490 if (deviceStorage->backend() == DeviceBackend::Host)
492 }
493 return *this;
494 }
495
497 {
498 this->deviceStorage = R.deviceStorage ? device_storage_create(R.deviceStorage->backend(), R.deviceStorage->bytes()) : null_supDeviceStorageBase();
499 if (deviceStorage)
500 {
501 R.deviceStorage->copy_to_device(this->deviceStorage->raw_ptr(), this->deviceStorage->bytes());
502 if (deviceStorage->backend() == DeviceBackend::Host)
504 }
505 }
506
511
513 {
514 deviceStorage.reset();
515 }
516
517 void swap(t_self &R) noexcept
518 {
519 R.swap(*this);
520 R.deviceStorage.swap(this->deviceStorage);
521 }
522 };
523
524 /// @brief Primary public alias: `host_device_vector<T>` = #host_device_vector_r1<T>.
525 /// Prefer this name throughout the code base.
526 template <class T>
528}
#define DNDS_DEVICE_TRIVIAL_COPY_DEFINE(T, T_Self)
Definition Defines.hpp:83
#define DNDS_DEVICE_CALLABLE
Definition Defines.hpp:76
#define DNDS_HOST
Definition Defines.hpp:78
Device memory abstraction layer with backend-specific storage and factory creation.
Assertion / error-handling macros and supporting helper functions.
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
Definition Errors.hpp:113
#define DNDS_assert(expr)
Debug-only assertion (compiled out when DNDS_NDEBUG is defined). Prints the expression + file/line + ...
Definition Errors.hpp:108
#define DNDS_check_throw_info(expr, info)
Same as DNDS_check_throw but attaches a user-supplied info message to the thrown std::runtime_error.
Definition Errors.hpp:96
#define DNDS_HD_assert(cond)
Host-only expansion of DNDS_HD_assert (equivalent to DNDS_assert).
Definition Errors.hpp:189
#define DNDS_check_throw(expr)
Runtime check active in both debug and release builds. Throws std::runtime_error if expr evaluates to...
Definition Errors.hpp:89
Abstract single-allocation owning byte buffer.
Definition Vector.hpp:25
virtual void free()=0
Release the allocation.
virtual size_t bytes() const =0
Allocation size in bytes.
virtual void allocate(size_t bytes, DeviceBackend B=DeviceBackend::Unknown)=0
Allocate bytes on backend B (or on the host when Unknown).
virtual std::unique_ptr< DeviceHostSingleAllocationBase > clone()=0
Deep copy; returns a new allocation containing the same bytes.
virtual void copy_from_host(uint8_t *host_src, size_t n)=0
Copy n bytes from host_src into this allocation.
virtual uint8_t * get()=0
Typed byte pointer to the current allocation.
virtual void copy_to_host(uint8_t *host_dst, size_t n)=0
Copy n bytes from this allocation into host_dst.
virtual DeviceBackend device()=0
Which backend currently owns the allocation.
Concrete DeviceHostSingleAllocationBase using std::vector<uint8_t> for host memory and DeviceStorage ...
Definition Vector.hpp:53
void copy_from_host(uint8_t *host_src, size_t n) override
Copy n bytes from host_src into this allocation.
Definition Vector.hpp:109
uint8_t * get() override
Typed byte pointer to the current allocation.
Definition Vector.hpp:85
void free() override
Release the allocation.
Definition Vector.hpp:77
void allocate(size_t bytes, DeviceBackend B=DeviceBackend::Unknown) override
Allocate bytes on backend B (or on the host when Unknown).
Definition Vector.hpp:66
DeviceBackend device() override
Which backend currently owns the allocation.
Definition Vector.hpp:95
void copy_to_host(uint8_t *host_dst, size_t n) override
Copy n bytes from this allocation into host_dst.
Definition Vector.hpp:97
std::unique_ptr< DeviceHostSingleAllocationBase > clone() override
Deep copy; returns a new allocation containing the same bytes.
Definition Vector.hpp:121
size_t bytes() const override
Allocation size in bytes.
Definition Vector.hpp:84
CRTP base offering operator[] / at on top of a derived's data() and size() accessors....
Definition Vector.hpp:179
const T & operator[](size_t i) const
Definition Vector.hpp:186
const T & at(size_t i) const
Definition Vector.hpp:188
T & at(size_t i)
Definition Vector.hpp:195
T & operator[](size_t i)
Definition Vector.hpp:184
Host + optional device vector of trivially copyable T.
Definition Vector.hpp:217
DNDS_HOST void to_device(DeviceBackend backend=DeviceBackend::Host)
Definition Vector.hpp:312
DNDS_HOST auto begin()
Definition Vector.hpp:296
DNDS_HOST T * dataDevice()
Definition Vector.hpp:293
DNDS_HOST auto end()
Definition Vector.hpp:297
DNDS_HOST void resize(size_t new_size, TFill &&fill)
Definition Vector.hpp:277
t_self & operator=(const t_self &R)
Definition Vector.hpp:361
DNDS_HOST void swap(t_self &R) noexcept
Definition Vector.hpp:395
DNDS_HOST auto end() const
Definition Vector.hpp:299
DNDS_HOST auto cend() const
Definition Vector.hpp:302
DNDS_HOST void clear()
Definition Vector.hpp:331
DNDS_HOST host_device_vector_r1(const std::vector< T > &v)
Definition Vector.hpp:261
DNDS_HOST void create_device_data(DeviceBackend B)
Definition Vector.hpp:283
DNDS_HOST void clear_device()
Definition Vector.hpp:324
DNDS_HOST t_self & operator=(const std::vector< T > &v)
Definition Vector.hpp:254
DNDS_HOST auto cbegin() const
Definition Vector.hpp:301
host_device_vector_r1(const t_self &R)
Definition Vector.hpp:377
DNDS_HOST auto begin() const
Definition Vector.hpp:298
DNDS_HOST host_device_vector_r1(size_t n)
Definition Vector.hpp:242
t_deviceView< B, TSize > deviceView()
Definition Vector.hpp:351
DNDS_HOST void resize(size_t new_size)
Definition Vector.hpp:268
DNDS_HOST const T * data() const
Definition Vector.hpp:291
vector_DeviceView< B, T, TSize > t_deviceView
Definition Vector.hpp:349
DNDS_HOST size_t size() const
Definition Vector.hpp:266
DeviceBackend device()
Definition Vector.hpp:390
DNDS_HOST const T * dataDevice() const
Definition Vector.hpp:294
DNDS_HOST host_device_vector_r1()=default
DNDS_HOST host_device_vector_r1(size_t n, TFill &&val)
Definition Vector.hpp:248
DNDS_HOST void to_host()
Definition Vector.hpp:339
Non-owning device-callable view {pointer, size} over a typed array.
Definition Vector.hpp:148
DNDS_DEVICE_CALLABLE T operator[](TSize i) const
Definition Vector.hpp:159
DNDS_DEVICE_CALLABLE TSize size() const
Definition Vector.hpp:169
DNDS_DEVICE_CALLABLE T & operator[](TSize i)
Definition Vector.hpp:164
the host side operators are provided as implemented
t_supDeviceStorageBase device_storage_create(DeviceBackend backend, size_t n_bytes)
Top-level factory: dispatches to the per-backend factory based on backend. Returns a null unique_ptr ...
DeviceBackend
Enumerates the backends a DeviceStorage / Array can live on.
@ Unknown
Unset / sentinel.
@ Host
Plain CPU memory.
const char * device_backend_name(DeviceBackend B)
Canonical string name for a DeviceBackend (used in log messages).
std::unique_ptr< DeviceStorageBase, std::function< void(DeviceStorageBase *)> > t_supDeviceStorageBase
Owning unique pointer to a DeviceStorageBase with cross-DLL-safe deleter.
t_supDeviceStorageBase null_supDeviceStorageBase()
Null-value helper for t_supDeviceStorageBase.
Legacy std::vector<T> subclass with an optional device mirror.
Definition Vector.hpp:414
std::vector< T > t_base
Definition Vector.hpp:417
host_device_vector_r0< T > t_self
Definition Vector.hpp:419
t_deviceView< B, TSize > deviceView()
Definition Vector.hpp:466
vector_DeviceView< B, T, TSize > t_deviceView
Definition Vector.hpp:464
const T * dataDevice() const
Definition Vector.hpp:476
void to_device(DeviceBackend backend=DeviceBackend::Host)
Definition Vector.hpp:439
DNDS_HOST t_self & operator=(const std::vector< T > &v)
Definition Vector.hpp:425
void swap(t_self &R) noexcept
Definition Vector.hpp:517
DeviceBackend device()
Definition Vector.hpp:507
t_supDeviceStorageBase deviceStorage
Definition Vector.hpp:421
t_self & operator=(const t_self &R)
Definition Vector.hpp:481
host_device_vector_r0(const t_self &R)
Definition Vector.hpp:496
DNDS_HOST host_device_vector_r0(const std::vector< T > &v)
Definition Vector.hpp:423
Eigen::Matrix< real, 5, 1 > v
Eigen::Vector3d n(1.0, 0.0, 0.0)