KFR

Introduction

Data types

Unsigned:

u8, u16, u32 and u64

Signed:

i8, i16, i32 and i64

Floating point:

f32 and f64

Complex:

complex<f32> and complex<f64>

Vector:

vec<u8, 4>, vec<f32, 3>, vec<i64, 1>, vec<complex<float>, 15>, vec<u8, 256>, vec<vec<int, 3>, 3>

You are not limited to sizes of SIMD registers and basic types.

univector class

univector class is a base of all containers in KFR.

univector can have both static and dynamic size and can even hold only reference to an external data (just like array_view or string_view)

univector<float> is derived from std::vector<float> and contains all its member functions and constructors.

univector<float, 10> is derived from std::array<float, 10> and contains all its member functions and constructors.

univector<float, 0> is only reference to data and doesn’t contain any values.

Such universal template allows functions in KFR to get data in any format.

You can get subrange of an array using slice function:

univector<float, 100> v;
// ...
const float s1 = sum(v); // Sum all elements
const float s2 = sum(v.slice(2, 50)); // Sum 50 elements starting from 2

Result of the call to slice is always univector<T, 0>.

Expressions

Calling functions on arrays of data is performed lazily using C++ template expressions. This allows better optimization and does not require saving temporary data.

For example, subtracting one univector from another gives expression type, not univector:

univector<int, 5> x{1, 2, 3, 4, 5};
univector<int, 5> y{0, 0, 1, 10, -5};

auto z = x - y; // z is of type expression, not univector.
                // This only constructs an expression and does not perform any calculation

But you can always convert expression back to univector to get actual data:

univector<int, 5> x{1, 2, 3, 4, 5};
univector<int, 5> y{0, 0, 1, 10, -5};

univector<int, 5> z = x - y; // when an expression is assigned to univector, expression is evaluated
                             // and values are being written to univector.

Same applies to calling KFR functions on univectors, this doesn’t calculate value immediately. Instead, new expression will be created.

univector<float, 5> x{1, 2, 3, 4, 5}; sqrt(x); // only constructs an expression univector<float, 5> values = sqrt(x); // constructs an expression and writes data to univector

Input expressions can be read from and output expressions can be written to. Class can be an input and output expression at same time. univector is an example of such class.

Data type of an input expressions can be determined by calling value_type_of<Expression>. However, not all expressions have their types specified. In such cases value_type_of will return special type generic.

Size (length) of an expression also can be specified or not. counter is an example of generic (untyped) expression without the size.