Speclib  0.1.2
The library for writing better CUDA libraries
sp::Vec< T, S > Class Template Reference

A vector of S elements of type T. More...

#include <Vec.hpp>

Inheritance diagram for sp::Vec< T, S >:
[legend]

Public Types

using ValueType = T
 
using BareValueType = sp::remove_cvref_t< sp::remove_addrspace_t< T > >
 
using ThisType = Vec< T, S >
 
using iterator = T *
 
using const_iterator = const T *
 

Public Member Functions

constexpr int size () const
 Get the size of the Vec. Provided mostly to satisfy named requirements. More...
 
constexpr bool empty () const
 
constexpr Vec ()=default
 Vec of default-constructed elements of this type and length. More...
 
constexpr Vec (const Vec< T, S > &)=default
 
constexpr Vec< T, S > & operator= (const Vec< T, S > &)=default
 
template<typename E , typename... Es>
constexpr Vec (E head, Es... tail)
 Construct a Vec containing the given variadic list of elements. More...
 
template<int InSize>
constexpr Vec (const T(&arr)[InSize])
 Construct a Vec from a constant array of elements. More...
 
constexpr iterator begin ()
 Returns an iterator to the first element of the container. More...
 
constexpr const_iterator begin () const
 Returns a const iterator to the first element of the container. More...
 
constexpr iterator end ()
 Returns an iterator to the last element of the container. More...
 
constexpr const_iterator end () const
 Returns a const iterator to the last element of the container. More...
 
__host__ std::vector< T > toVector ()
 Convert a Vec to a std::vector. More...
 
constexpr auto toTuple ()
 Convert the Vec to a std::tuple of elements of type T. More...
 
constexpr T & operator[] (int i)
 Access operator. More...
 
constexpr const T & operator[] (int i) const
 Access operator. More...
 
constexpr BareValueType read (int i) const
 Returns a copy of the value at index i. More...
 
template<int I>
constexpr T & get ()
 Read the element at index I. More...
 
template<int I>
constexpr const T & get () const
 Read the element at index I. More...
 
template<typename Q , int OtherSize>
constexpr bool operator== (const Vec< Q, OtherSize > &other) const
 Equality operator. More...
 
template<typename Q , int OtherSize>
constexpr bool operator!= (const Vec< Q, OtherSize > &other) const
 
template<typename Op >
constexpr auto map (const Op &op=Op{}) const
 Maps the Vec with the given callable, providing a Vec result of the same length. More...
 
constexpr Vec< T, Size > operator- () const
 Unary negation operator. More...
 
template<typename Q >
constexpr Vec< T, Size > & operator= (const Q &value)
 Unary scalar assignment. More...
 
constexpr void replace (T from, T to)
 In-place replacement of all instances of from with to More...
 
template<typename Op >
constexpr T reduce (Op op=Op{}) const
 Reduce the vector elements using a binary operator. More...
 
template<int NewSize>
constexpr Vec< T, NewSize > slice (int start) const
 Get a copy of a contiguous slice of this Vec More...
 
template<int InSize, int ToWrite = InSize>
constexpr void splice (int I, const Vec< T, InSize > &in)
 Overwrite a segment of this Vec with ToWrite values from another, starting at position I. More...
 
template<int I, int Len>
constexpr sp::Vec< T, Size+Len > insert (const sp::Vec< T, Len > &newValues) const
 Insert multiple values. More...
 
template<int I>
constexpr auto insert (const T &newValue) const
 Insert a single value. More...
 
constexpr sp::Vec< T, Size > reverse () const
 Get the reverse of this Vec More...
 
template<int I, int N = 1>
constexpr auto erase () const
 Erase one or more values. More...
 
constexpr auto eraseLast () const
 Erase the last value. More...
 
constexpr auto eraseFirst () const
 Erase the first value. More...
 
template<bool Foo = false, typename std::enable_if_t< Foo||Size==1 > * = nullptr>
 operator T () const
 Allow 1-vectors to convert to the corresponding scalar. More...
 

Static Public Member Functions

static __host__ Vec< T, Size > fromVector (const std::vector< T > &vector)
 Construct a Vec from a std::vector. More...
 
template<typename... Ts>
static constexpr Vec< T, Size > fromTuple (const std::tuple< Ts... > &tuple)
 Construct a Vec from a std::tuple. More...
 
template<typename IT , IT... Ints>
static constexpr Vec< IT, sizeof...(Ints)> fromIntegerSequence (sp::integer_sequence< IT, Ints... >)
 Convert an sp::integer_sequence into the corresponding type of Vec. More...
 
static constexpr Vec< T, Size > copiesOf (const T &value)
 Make a Vec with Size-many copies of value. More...
 

Static Public Attributes

constexpr static int Size = S
 

Detailed Description

template<typename T, int S>
class sp::Vec< T, S >

A vector of S elements of type T.

Like CUDA's float4 and friends, it facilitates the use of vectorised memory instructions by making an alignment promise. Vec also provides a number of convenience features:

  • Arithmetic operators allowing you to write math involving Vecs in the obvious way. This lets you very directly write vectorisable loops.
  • Better metaprogramming, since the vector size and type are exposed as template parameters.
  • Full constexpr support, allowing its use in highly elaborate metaprograms.
  • Functional-programming-style operators like map() and reduce() for transforming Vecs.
  • List-style manipulations like insert() and slice().
  • Conversion to/from std::vector (CPU-only).

To facilitate interoperability, Vec transparently converts to/from CUDA vector types.

A Vec in memory is always aligned suitably for use with vector memory instructions.

Examples

The following example kernels:

  1. Load two 4-vectors in each thread
  2. Add them together
  3. Write the result back to memory.
  4. Assume the input is a multiple-of-four elements long, to make the examples shorter.

Each kernel has an example calling function showing how the data is initiated and moved around.

Example Using Vanilla CUDA

// Compute X += Y, where X and Y are vectors of size N, making sure we use 4-vector loads.
// This code assumes N is a multiple of 4, for brevity.
__global__ void sumKernelVanilla(float* X, float* Y, int N) {
// Process one 4-vector per thread
int offset = blockIdx.x * blockDim.x + threadIdx.x;
if (offset >= N) {
return;
}
// This suppression is necessary to have vanilla CUDA use vector-loads
// Vanilla cuda doesn't use alignment type annotations properly (at all)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
// Perform the vector reads from X and Y. These nasty pointer casts are necessary to get vector loads to appear.
float4 xRead = ((float4*) X)[offset];
float4 yRead = ((float4*) Y)[offset];
// Sum them. Since CUDA's vector types are storage-only, you have to manipulate the components manually:
xRead.w += yRead.w;
xRead.x += yRead.x;
xRead.y += yRead.y;
xRead.z += yRead.z;
// Write back.
*((float4*) X) = xRead;
#pragma clang diagnostic pop
}
std::vector<float> vanillaTest() {
auto stream = sp::Device::getActive().createStream(); // Get a stream to enqueue actions
// Create host-side vectors and populate them with data
std::vector<float> x = {1, 2, 3, 4};
std::vector<float> y = {1, 2, 3, 4};
// Allocate memory on device that can hold our vectors
float *a, *b = nullptr;
cudaError e1 = cudaMalloc((void**)&a, x.size() * sizeof(float));
cudaError e2 = cudaMalloc((void**)&b, y.size() * sizeof(float));
// Check alloc succeeded
if (e1 != cudaSuccess || e2 != cudaSuccess) {
fprintf(stderr, "GPU memory allocation failed");
}
// Copy vectors to device
cudaError e3 = cudaMemcpy(a, &x[0], x.size() * sizeof(float), cudaMemcpyHostToDevice);
cudaError e4 = cudaMemcpy(b, &y[0], y.size() * sizeof(float), cudaMemcpyHostToDevice);
// Check copy succeeded
if (e3 != cudaSuccess || e4 != cudaSuccess) {
fprintf(stderr, "Copy from host to GPU failed");
}
sumKernelVanilla<<<1, 1, 0, stream>>>(a, b, 4);
// Copy the result back into the host vector
cudaMemcpyAsync(&x[0], a, x.size() * sizeof(float), cudaMemcpyDeviceToHost, stream);
return x;
}
Stream createStream(const std::string &name) const
static Device & getActive()
T fprintf(T... args)
__host__ __device__ cudaError_t cudaMemcpy(void *dst, const void *src, size_t count, enum cudaMemcpyKind kind)
__host__ __device__ cudaError_t cudaMalloc(void **devPtr, size_t size)
__host__ __device__ cudaError_t cudaMemcpyAsync(void *dst, const void *src, size_t count, enum cudaMemcpyKind kind, cudaStream_t stream __dv(0))
cudaError
cudaMemcpyHostToDevice
cudaMemcpyDeviceToHost
cudaSuccess
T size(T... args)

Example Using Speclib

// Compute X += Y, where X and Y are vectors, using vector load operations for performance.
__global__ void sumKernelSpeclib(sp::Vector<__device float> X, sp::Vector<__device float> Y) {
// Process one 4-vector per thread
int offset = 4 * (blockIdx.x * blockDim.x + threadIdx.x);
if (offset >= X.dim(0)) {
return;
}
// Vec-Vec addition with the `+` operator:
sp::Vec<float, 4> outValue = X.vectorRead<4>(offset) + Y.vectorRead<4>(offset);
// Vec-size template parameter here is inferred from the type of `outValue`.
X.vectorWrite(offset, outValue);
}
int dim(int d) const
Behaviour common to all TensorLikes ///.
Definition: TensorLike.hpp:233
Represents a Tensor- a multidimensional array that can represent a multilinear map.
Definition: Tensor.hpp:32
A vector of S elements of type T.
Definition: Vec.hpp:71
auto speclibTest() {
auto stream = sp::Device::getActive().createStream(); // Get a stream to enqueue actions
// Create representations of the type of data structure we will be using
auto nomadicX = sp::NomadicTensor{sp::Vector<float>{}, 4};
auto nomadicY = sp::NomadicTensor{sp::Vector<float>{}, 4};
// Get host-modifiable views, and populate them with data
auto hostX = nomadicX.mutableHostTensor(stream);
auto hostY = nomadicY.mutableHostTensor(stream);
for (int i = 0; i < 4; i++) {
hostX[i] = i + 1;
hostY[i] = i + 1;
}
// Get device-side views, transferring the data
auto deviceX = nomadicX.mutableDeviceTensor(stream);
auto deviceY = nomadicY.mutableDeviceTensor(stream);
// Execute device kernel
sumKernelSpeclib<<<1, 1, 0, stream>>>(deviceX, deviceY);
// Get a host-side, non-modifiable view, waiting on the modified content to be copied back
nomadicX.hostTensor(stream, true);
return nomadicX;
}
Represents a TensorLike that can be synchronised between the CPU and various GPUs.
Definition: NomadicTensor.hpp:36

On top of being shorter, this example:

  • Bounds-checks (and alignment-checks) the memory accesses when compiled in debug mode, producing a descriptive error message if something goes wrong. In release mode, both programs compile to the same thing.
  • Adapts seamlessly to any type by replacing float with a template parameter.

Constructor & Destructor Documentation

◆ Vec() [1/3]

template<typename T , int S>
constexpr sp::Vec< T, S >::Vec ( )
constexprdefault

Vec of default-constructed elements of this type and length.

Example

sp::Vec<std::string, 3> v; // myVec == ["", "", ""]

◆ Vec() [2/3]

template<typename T , int S>
template<typename E , typename... Es>
constexpr sp::Vec< T, S >::Vec ( head,
Es...  tail 
)
constexpr

Construct a Vec containing the given variadic list of elements.

Example

sp::Vec<int, 4> v(1, 2, 3, 4); // [1, 2, 3, 4]
sp::Vec<float, 5> vFloat(1, 5.0, 3.0, -1, 0); // Implicit conversion from int to float

◆ Vec() [3/3]

template<typename T , int S>
template<int InSize>
constexpr sp::Vec< T, S >::Vec ( const T(&)  arr[InSize])
constexpr

Construct a Vec from a constant array of elements.

The first Size-many elements of the array are copied into the new Vec. The array is unchanged.

This is mostly useful for initialising a Vec<char, ...> with a string literal. Since this constructor serves as a deduction guide, you can write:

Example

sp::Vec a = "I like trains"; // sp::Vec<char, 14> because of the trailing \0
// If you are slicing off the start of an array, you must explicitly provide your own template parameters:
char c[7] = "Trains";
// Note: no null terminator in the Vec.
sp::Vec<char, 5> e = "Trains";
sp::Vec f = "Trains"; // No parameters, no slice
sp::Vec<char, 5> g{'T', 'r', 'a', 'i', 'n'}; // d == e != f

But you can't construct a Vec from something smaller than itself:

char foo[6] = "Short";
sp::Vec<char, 10> bar(foo); // Doesn't compile

Member Function Documentation

◆ begin() [1/2]

template<typename T , int S>
constexpr iterator sp::Vec< T, S >::begin ( )
constexpr

Returns an iterator to the first element of the container.

◆ begin() [2/2]

template<typename T , int S>
constexpr const_iterator sp::Vec< T, S >::begin ( ) const
constexpr

Returns a const iterator to the first element of the container.

◆ copiesOf()

template<typename T , int S>
static constexpr Vec< T, Size > sp::Vec< T, S >::copiesOf ( const T &  value)
staticconstexpr

Make a Vec with Size-many copies of value.

Example

auto ones = sp::Vec<int, 3>::copiesOf(1); // [1, 1, 1]
auto threes = sp::Vec<double, 4>::copiesOf(3.0); // [3.0, 3.0, 3.0. 3,0]
static constexpr Vec< T, Size > copiesOf(const T &value)
Make a Vec with Size-many copies of value.
Definition: Vec.hpp:267

◆ end() [1/2]

template<typename T , int S>
constexpr iterator sp::Vec< T, S >::end ( )
constexpr

Returns an iterator to the last element of the container.

◆ end() [2/2]

template<typename T , int S>
constexpr const_iterator sp::Vec< T, S >::end ( ) const
constexpr

Returns a const iterator to the last element of the container.

◆ erase()

template<typename T , int S>
template<int I, int N = 1>
constexpr auto sp::Vec< T, S >::erase ( ) const
constexpr

Erase one or more values.

Example

sp::Vec<int, 3> source{1, 2, 3};
// Erase one value
sp::Vec<int, 2> x = source.erase<0>(); // [2, 3]
sp::Vec<int, 2> y = source.erase<1>(); // [1, 3]
sp::Vec<int, 2> z = source.erase<2>(); // [1, 2]
// Erase multiple values
sp::Vec<int, 1> a = source.erase<0, 2>(); // [3]
sp::Vec<int, 1> b = source.erase<1, 2>(); // [1]
sp::Vec<int, 0> c = source.erase<0, 3>(); // []
constexpr auto erase() const
Erase one or more values.
Definition: Vec.hpp:559
Template Parameters
IStarting position
NNumber of values to delete, I included
Returns
A new Vec equal to this Vec with N values deleted from position I.

◆ eraseFirst()

template<typename T , int S>
constexpr auto sp::Vec< T, S >::eraseFirst ( ) const
constexpr

Erase the first value.

Example

sp::Vec<int, 3> source{1, 2, 3};
sp::Vec<int, 2> x = source.eraseFirst(); // [2, 3]
constexpr auto eraseFirst() const
Erase the first value.
Definition: Vec.hpp:589
Returns
A new Vec equal to this Vec with the first element deleted.

◆ eraseLast()

template<typename T , int S>
constexpr auto sp::Vec< T, S >::eraseLast ( ) const
constexpr

Erase the last value.

Example

sp::Vec<int, 3> source{1, 2, 3};
sp::Vec<int, 2> x = source.eraseLast(); // [1, 2]
constexpr auto eraseLast() const
Erase the last value.
Definition: Vec.hpp:578
Returns
A new Vec equal to this Vec with the last element deleted.

◆ fromIntegerSequence()

template<typename T , int S>
template<typename IT , IT... Ints>
static constexpr Vec< IT, sizeof...(Ints)> sp::Vec< T, S >::fromIntegerSequence ( sp::integer_sequence< IT, Ints... >  )
staticconstexpr

Convert an sp::integer_sequence into the corresponding type of Vec.

Example

auto i32Vec = sp::Vec<int, 3>::fromIntegerSequence(i32s{}); // sp::Vec<int, 3>{1, 2, 3}
auto i64Vec = sp::Vec<uint64_t, 3>::fromIntegerSequence(i64s{}); // sp::Vec<uint64_t, 3>{1, 2, 3}
static constexpr Vec< IT, sizeof...(Ints)> fromIntegerSequence(sp::integer_sequence< IT, Ints... >)
Convert an sp::integer_sequence into the corresponding type of Vec.
Definition: Vec.hpp:261
Encodes a sequence of integral type T.
Definition: integer_sequence.hpp:113

◆ fromTuple()

template<typename T , int S>
template<typename... Ts>
static constexpr Vec< T, Size > sp::Vec< T, S >::fromTuple ( const std::tuple< Ts... > &  tuple)
staticconstexpr

Construct a Vec from a std::tuple.

The tuple elements must all be convertible to T, but don't necessarily have to be of type T.

Example

const auto foo = std::make_tuple(1, 2, 3);
auto y = sp::Vec<int, 3>::fromTuple(foo); // y is [1, 2, 3]
static constexpr Vec< T, Size > fromTuple(const std::tuple< Ts... > &tuple)
Construct a Vec from a std::tuple.
Definition: Vec.hpp:242
T make_tuple(T... args)

◆ fromVector()

template<typename T , int S>
static __host__ Vec< T, Size > sp::Vec< T, S >::fromVector ( const std::vector< T > &  vector)
static

Construct a Vec from a std::vector.

Not a constructor because this creates an ambiguity that would require fairly elaborate template-fu to mitigate - and this explicitness is sort of nice.

Example

aVector.push_back(1);
aVector.push_back(2);
aVector.push_back(3);
auto myVec = sp::Vec<int, 3>::fromVector(aVector); // [1, 2, 3]
static __host__ Vec< T, Size > fromVector(const std::vector< T > &vector)
Construct a Vec from a std::vector.
Definition: Vec.hpp:195
T push_back(T... args)

◆ get() [1/2]

template<typename T , int S>
template<int I>
constexpr T & sp::Vec< T, S >::get ( )
constexpr

Read the element at index I.

Helpful for compatibility with sp::tuple when metaprogramming, but otherwise equivalent to operator[]

◆ get() [2/2]

template<typename T , int S>
template<int I>
constexpr const T & sp::Vec< T, S >::get ( ) const
constexpr

Read the element at index I.

Helpful for compatibility with sp::tuple when metaprogramming, but otherwise equivalent to operator[]

◆ insert() [1/2]

template<typename T , int S>
template<int I, int Len>
constexpr sp::Vec< T, Size+Len > sp::Vec< T, S >::insert ( const sp::Vec< T, Len > &  newValues) const
constexpr

Insert multiple values.

Example

sp::Vec<int, 3> source{1, 2, 3};
sp::Vec<int, 6> a = source.insert<3>(source); // [1, 2, 3, 1, 2, 3]
sp::Vec<int, 6> b = source.insert<0>(source); // [1, 2, 3, 1, 2, 3]
sp::Vec<int, 6> c = source.insert<2>(source); // [1, 2, 1, 2, 3, 3]
constexpr sp::Vec< T, Size+Len > insert(const sp::Vec< T, Len > &newValues) const
Insert multiple values.
Definition: Vec.hpp:507
Template Parameters
IPosition to insert at
LenLength of inserted Vec
Parameters
newValuesValues to insert
Returns
A new Vec equal to this Vec with newValues inserted from position I.

◆ insert() [2/2]

template<typename T , int S>
template<int I>
constexpr auto sp::Vec< T, S >::insert ( const T &  newValue) const
constexpr

Insert a single value.

Example

sp::Vec<int, 3> source{1, 2, 3};
sp::Vec<int, 4> x = source.insert<3>(4); // [1, 2, 3, 4]
sp::Vec<int, 4> y = source.insert<0>(0); // [0, 1, 2, 3]
sp::Vec<int, 4> z = source.insert<1>(2); // [1, 2, 2, 4]
Template Parameters
IPosition to insert at
Parameters
newValueValue to insert
Returns
A new Vec equal to this Vec with 'newValue` inserted at position I.

◆ map()

template<typename T , int S>
template<typename Op >
constexpr auto sp::Vec< T, S >::map ( const Op &  op = Op{}) const
constexpr

Maps the Vec with the given callable, providing a Vec result of the same length.

The result may have a different type. If op has side-effects, these may occur in any order. Without an argument, default-constructs one of the given type, for use with functor types.

Does NOT support function pointers, for performance reasons. Use a lambda or functor instead.

Example

sp::Vec<int, 4> source{1, 2, 3, 4};
// Using lambda
sp::Vec<int, 4> squares = source.map([](int x){return x * x;}); // squares == [1, 4, 9, 16]
sp::Vec<double, 4> roots = source.map([](int x){return std::sqrt(x);}); // roots == [1, 1.414..., 1.732..., 2.0]
// Using functor
sp::Vec<int, 4> negated = source.map<sp::f::Negate>(); // negated == [-1, -2, -3, -4] == -foo
constexpr auto map(const Op &op=Op{}) const
Maps the Vec with the given callable, providing a Vec result of the same length.
Definition: Vec.hpp:374
T sqrt(T... args)
Template Parameters
OpType of functor to apply
Parameters
opfunctor to apply

◆ operator T()

template<typename T , int S>
template<bool Foo = false, typename std::enable_if_t< Foo||Size==1 > * = nullptr>
sp::Vec< T, S >::operator T ( ) const

Allow 1-vectors to convert to the corresponding scalar.

◆ operator-()

template<typename T , int S>
constexpr Vec< T, Size > sp::Vec< T, S >::operator- ( ) const
constexpr

Unary negation operator.

Returns
A new Vec containing the element-wise negation of this Vec

Example

sp::Vec<int, 3> x{1, 2, 3};
sp::Vec<int, 3> y{-x}; // [-1, -2, -3]

◆ operator=()

template<typename T , int S>
template<typename Q >
constexpr Vec< T, Size > & sp::Vec< T, S >::operator= ( const Q &  value)
constexpr

Unary scalar assignment.

Fills the vector with the given scalar

Example

sp::Vec<int, 4> source{1, 2, 3, 4};
source = 5; // source == [5, 5, 5, 5]

◆ operator==()

template<typename T , int S>
template<typename Q , int OtherSize>
constexpr bool sp::Vec< T, S >::operator== ( const Vec< Q, OtherSize > &  other) const
constexpr

Equality operator.

Two Vecs compare equal iff all their elements compare equal.

Example

sp::Vec<int, 3> v{3, 4, 2};
sp::Vec<int, 3> e{3, 4, 2};
sp::Vec<int, 3> n{3, 4, 4};
bool a = v == e; // True
bool b = v == n; // False

◆ operator[]() [1/2]

template<typename T , int S>
constexpr T & sp::Vec< T, S >::operator[] ( int  i)
constexpr

Access operator.

Example

sp::Vec<int, 5> v{4, 3, 6, 1, 2};
int a = v[0]; // 4
int b = v[1]; // 3
int c = v[2]; // 6
int d = v[3]; // 1
int e = v[4]; // 2

◆ operator[]() [2/2]

template<typename T , int S>
constexpr const T & sp::Vec< T, S >::operator[] ( int  i) const
constexpr

Access operator.

Example

sp::Vec<int, 5> v{4, 3, 6, 1, 2};
int a = v[0]; // 4
int b = v[1]; // 3
int c = v[2]; // 6
int d = v[3]; // 1
int e = v[4]; // 2

◆ read()

template<typename T , int S>
constexpr BareValueType sp::Vec< T, S >::read ( int  i) const
constexpr

Returns a copy of the value at index i.

◆ reduce()

template<typename T , int S>
template<typename Op >
constexpr T sp::Vec< T, S >::reduce ( Op  op = Op{}) const
constexpr

Reduce the vector elements using a binary operator.

Any side effects of op are not guaranteed to occur in order. If no argument is given, default-constructs one of the provided type, allowing use of functor types.

Does NOT support function pointers for performance reasons. Use a lambda or functor instead.

Example

sp::Vec<int, 4> source{1, 2, 3, 4};
int w = source.template reduce<sp::f::Mul>(); // 24
int x = source.template reduce<sp::f::Add>(); // 10
int y = source.reduce([](int a, int b){return a + b;}); // 10
int z = source.reduce([](int a, int b){return std::lcm(a, b);}); // 12
T lcm(T... args)
Parameters
opBinary operation functor, must be associative and commutative.
Returns
Object of type T

◆ replace()

template<typename T , int S>
constexpr void sp::Vec< T, S >::replace ( from,
to 
)
constexpr

In-place replacement of all instances of from with to

Example

sp::Vec<int, 8> source{1, 2, 3, 4, 1, 2, 3, 4};
source.replace(2, 3); // [1, 3, 3, 4, 1, 3, 3, 4]
source.replace(3, 4); // [1, 4, 4, 4, 1, 4, 4, 4]
constexpr void replace(T from, T to)
In-place replacement of all instances of from with to
Definition: Vec.hpp:415

◆ reverse()

template<typename T , int S>
constexpr sp::Vec< T, Size > sp::Vec< T, S >::reverse ( ) const
constexpr

Get the reverse of this Vec

Example

sp::Vec<int, 3> three{1, 2, 3};
sp::Vec<int, 4> four{1, 2, 3, 4};
auto threeReversed = three.reverse(); // [3, 2, 1]
auto fourReversed = four.reverse(); // [4, 3, 2, 1]
constexpr sp::Vec< T, Size > reverse() const
Get the reverse of this Vec
Definition: Vec.hpp:538

◆ size()

template<typename T , int S>
constexpr int sp::Vec< T, S >::size ( ) const
constexpr

Get the size of the Vec. Provided mostly to satisfy named requirements.

◆ slice()

template<typename T , int S>
template<int NewSize>
constexpr Vec< T, NewSize > sp::Vec< T, S >::slice ( int  start) const
constexpr

Get a copy of a contiguous slice of this Vec

Example

sp::Vec<int, 5> source{1, 2, 3, 4, 5};
auto x = source.slice<2>(1); // [2, 3]
auto y = source.slice<5>(0); // [1, 2, 3, 4, 5]
auto z = source.slice<1>(2); // [3]
constexpr Vec< T, NewSize > slice(int start) const
Get a copy of a contiguous slice of this Vec
Definition: Vec.hpp:460
Template Parameters
NewSizeHow large of a slice to take. Constexpr so this function can return a Vec!
Parameters
startWhere to start the slice
Returns
A new Vec equal to {this[start], this[start + 1], ..., this[start+NewSize-1]}

◆ splice()

template<typename T , int S>
template<int InSize, int ToWrite = InSize>
constexpr void sp::Vec< T, S >::splice ( int  I,
const Vec< T, InSize > &  in 
)
constexpr

Overwrite a segment of this Vec with ToWrite values from another, starting at position I.

Partial splice example: splice<(int)in.size(), X>(in)

Example

sp::Vec<int, 3> x{1, 2, 3};
sp::Vec<int, 3> y{1, 2, 3};
x.splice(1, sp::Vec<int, 2>{1, 1}); // x is now [1, 1, 1]
y.splice(0, sp::Vec<int, 2>{3, 3}); // y is now [3, 3, 3]
// Splicing with a zero-vec shouldn't do anything
sp::Vec<int, 3> z{1, 2, 3};
z.splice(2, sp::Vec<int, 0>{});
z.splice(3, sp::Vec<int, 0>{}); // z remains [1, 2, 3] throughout
// Partial splice
sp::Vec<int, 5> a{1, 2, 3, 4, 5};
a.splice<7, 3>(1, sp::Vec<int, 7>{8, 8, 8, 8, 8, 8, 8}); // a is now [1, 8, 8, 8, 5]
constexpr void splice(int I, const Vec< T, InSize > &in)
Overwrite a segment of this Vec with ToWrite values from another, starting at position I.
Definition: Vec.hpp:486
Template Parameters
ToWriteHow many values to write. Defaults to in.size(). Must be <= in.size().
Parameters
IIndex to begin writing values at
inVec providing values to write from

◆ toTuple()

template<typename T , int S>
constexpr auto sp::Vec< T, S >::toTuple ( )
constexpr

Convert the Vec to a std::tuple of elements of type T.

Because fromTuple() converts input values to type T, doing fromTuple followed by toTuple may not be a no-op.

Example

sp::Vec<int, 3> x{1, 2, 3};
auto y = x.toTuple(); // y is std::tuple<int, int, int>{1, 2, 3}
constexpr auto toTuple()
Convert the Vec to a std::tuple of elements of type T.
Definition: Vec.hpp:254

◆ toVector()

template<typename T , int S>
__host__ std::vector< T > sp::Vec< T, S >::toVector ( )

Convert a Vec to a std::vector.

Not a user-defined conversion operator because this is a fairly unusual thing to want to do...

Example

sp::Vec<int, 3> someVec{1, 2, 3};
std::vector<int> aVector = someVec.toVector(); // [1, 2, 3]