Basics

dandy is an easy to integrate, single-header linear algebra vector library making use of expression templates for compile-time expression parsing – as such, operations can be performed on complex vector expressions without the need for intermediary vector allocations.

Vector types

template<class Scalar, size_t Size>
using vector = impl::value<Scalar, Size>
Param Scalar

The scalar type of the vector (e.g. int or float)

Param Size

The size of the vector

namespace types

Typedefs

using bool2d = vector<bool, 2>
using char2d = vector<int8_t, 2>
using uchar2d = vector<uint8_t, 2>
using int2d = vector<int32_t, 2>
using uint2d = vector<uint32_t, 2>
using long2d = vector<int64_t, 2>
using ulong2d = vector<uint64_t, 2>
using float2d = vector<float, 2>
using double2d = vector<double, 2>
using bool3d = vector<bool, 3>
using char3d = vector<int8_t, 3>
using uchar3d = vector<uint8_t, 3>
using int3d = vector<int32_t, 3>
using uint3d = vector<uint32_t, 3>
using long3d = vector<int64_t, 3>
using ulong3d = vector<uint64_t, 3>
using float3d = vector<float, 3>
using double3d = vector<double, 3>
using bool4d = vector<bool, 4>
using char4d = vector<int8_t, 4>
using uchar4d = vector<uint8_t, 4>
using int4d = vector<int32_t, 4>
using uint4d = vector<uint32_t, 4>
using long4d = vector<int64_t, 4>
using ulong4d = vector<uint64_t, 4>
using float4d = vector<float, 4>
using double4d = vector<double, 4>

Note

Throughout this documentation, a “vector value” will refer to any of the types defined above

Construction

  • Is DefaultConstructible

    float3d v; // v contains 0, 0, 0
    
  • Is constructable from individual component values:

    float3d v { 1.0, 2.0, 3.0 }; // v contains 1.0, 2.0, 3.0
    
  • Is explicitly constructable from a single value:

    float3d v(1.0); // v contains 1.0, 1.0, 1.0
    
  • Is CopyConstructible and CopyAssignable:

    float3d a { 1.0, 2.0, 3.0 };
    float3d b = a; // b contains 1.0, 2.0, 3.0
    float3d c;
    c = a; // c contains 1.0, 2.0, 3.0
    
  • Is constructable from a vector expression of the same size:

    float3d a { 1.1, 2.2, 3.3 };
    int3d b = a; // b contains 1, 2, 3
    int3d c;
    c = a + b; // c contains 2, 4, 6
    
    int2d d = a; // error
    
  • 2D only: Is constructable from an angle specified in radians

    float2d v = float2d::from_angle(0); // v contains 1, 0
    

Expression templates

  • Operations aren’t evaluated until applied to a value:

    auto v = int3d{ 1, 2, 3 } + int3d{ 1, 2, 3 }; // v is of the intermediary type "operation"
    
  • Operations can be evaluated fully implicitly:

    int3d v = int3d{ 1, 2, 3 } + int3d{ 1, 2, 3 }; // vector v contains 2, 4, 6
    
  • Or explicitly:

    auto v = (int3d{ 1, 2, 3 } + int3d{ 1, 2, 3 }).evaluate(); // v is a vector and contains 2, 4, 6
    
    // alternate syntax:
    auto v = *(int3d{ 1, 2, 3 } + int3d{ 1, 2, 3 }); // v is a vector and contains 2, 4, 6
    

Note

Throughout this documentation, vector expression refers to an instance of either a vector value (impl::value) or a vector operation (impl::operation)

Operator overloads

Note

  • All operators require the argument vector expressions (if more than one) to be of the same size

  • All operators evaluate the expressions component-wise

  • All binary arithmetic operators (+, -, *, /, %, &, |, ^, >>, <<), including their corresponding assignment operators, are overloaded for expressions of the pattern:

    [vector expression] [operator] [vector expression]
    [vector expression] [operator] [scalar]
    
  • All binary arithmetic operators, exluding their corresponding assignment operators, are overloaded for expressions of the pattern:

    [scalar] [operator] [vector expression]
    
  • The unary operators +, -, and ~ are overloaded for all vector expressions

  • Is EqualityComparable: Two vectors are equal if all components are equal

    float3d a { 1, 2, 3 };
    float3d b = a;
    float3d c { 4, 5, 6 };
    
    assert(a == b);
    assert(a != (b + c));
    
  • Is LessThanComparable: A vector a is “lesser than” a vector b if all components in a are lesser than the corresponding components in b

    Note

    !(a < b) does not imply that a >= b

    int2d a { 1, 2 };
    int2d b { 2, 3 };
    
    assert(a < b);
    
    a.x = 2;
    
    assert_false(a < b); // since a.x >= b.x
    
  • Is explicitly convertable to a bool:

    if (double2d{ 3, 4 })
        std::cout << "This will run";
    if (double2d::zero)
        std::cout << "This will not";
    
    // explicit cast required
    bool is_nonzero = (bool)double2d{ 1, 0 }; // is_nonzero is true
    

Indexing

  • Components in all vector expressions can be retrieved either with impl::expression_base::at():

    float3d v { 1, 2, 3 };
    float x = v.at(0); // x is 1
    float y = v.at(1); // y is 2
    

    Or with the index operators:

    float3d v { 1, 2, 3 };
    float x = v[0]; // x is 1
    float y = v[1]; // y is 2
    
  • If a compatible compiler is used, components in a vector value can also be accessed by name:

    float3d v { 1, 2, 3 };
    float x = v.x; // x is 1
    float y = v.y; // y is 2
    

    Or with a range-for loop:

    int sum = 0;
    
    for (double v : double3d{ 1, 2, 3 })
        sum += v;
    
    // sum is 6