LLAMA vs. C++
LLAMA tries hard to provide experience and constructs similar to native C++. The following tables compare how various constructs in C++ translate to LLAMA:
Containers and views
Construct |
Native C++ |
LLAMA |
LLAMA (alternative) |
---|---|---|---|
Defining structs/records |
struct VecCpp {
float x;
float y;
};
struct ParticleCpp {
VecCpp pos;
float mass;
bool flags[3];
};
|
struct X{}; struct Y{}; struct Pos{}; struct Mass{}; struct Flags{};
using VecRec = llama::Record<
llama::Field<X, float>,
llama::Field<Y, float>
>;
using ParticleRec = llama::Record<
llama::Field<Pos, VecRec>,
llama::Field<Mass, float>,
llama::Field<Flags, bool[3]>
>;
|
|
Defining array extents |
using size_type = ...;
size_type n = ...;
|
using ArrayExtents = ...;
ArrayExtents n = ...;
|
|
Defining the memory layout |
- |
using Mapping = ...;
Mapping m(n, ...);
|
|
A collection of n things in memory |
std::vector<ParticleCpp> view(n);
|
auto view = llama::allocView(m);
|
llama::View<ArrayExtents, ParticleRec, ...> view;
Useful for static array dimensions. |
Values and references
Construct |
Native C++ |
LLAMA |
LLAMA (alternative) |
wrong |
---|---|---|---|---|
Declare single local record |
ParticleCpp p;
|
llama::One<ParticleRec> p
|
ParticleCpp p;
Or any type layout compatible type supporting the tuple interface. |
ParticleRec p;
ParticleRec is an empty struct (a type list)! |
Copy memory -> local |
p = view[i];
|
p = view[i];
|
p = view[i];
Assigns field by field using tuple interface. |
|
Copy local -> memory |
view[i] = p;
|
view[i] = p;
|
view[i] = p;
Assigns field by field using tuple interface. |
|
Copy a single record from memory to local |
ParticleCpp p = view[i];
|
llama::One<ParticleRec> p = view[i];
|
ParticleCpp p = view[i];
Assigns field by field using tuple interface |
auto p = view[i];
|
Create a reference to a single record in memory |
ParticleCpp& p = view[i];
|
auto p = view[i];
// decltype(p) == llama::RecordRef<...>
|
auto&& p = view[i];
|
auto& p = view[i];
Compilation error! |
Copy a single sub-record from memory to local |
VecCpp v = view[i].pos;
|
llama::One<VecRec> v = view[i](Pos{});
|
VecRec v = view[i](Pos{});
Assigns field by field using tuple interface. |
auto v = view[i](Pos{});
|
Create a reference to a single sub-record in memory |
VecCpp& v = view[i].pos;
|
auto v = view[i](Pos{});
// decltype(v) == llama::RecordRef<...>
|
auto&& v = view[i](Pos{});
|
auto& p = view[i](Pos{});
Compilation error! |
Copy a single record leaf field from memory to local |
float y = view[i].pos.y;
|
float y = view[i](Pos{}, Y{});
|
float y = view[i](Pos{})(Y{});
|
|
Create a reference to a single leaf field in memory |
float& y = view[i].pos.y;
|
float& y = view[i](Pos{});
|
auto&& y = view[i](Pos{});
|
auto y = view[i](Pos{});
|
Create a copy of a single local record |
auto p2 = p;
|
auto p2 = p;
|
||
Create a reference to a single local record |
auto& r = p;
|
auto r = p();
Access with an empty tag list. |
Notice that the use of auto
to declare a local copy of a value read through a reference, e.g. auto pos = view[i].pos; // copy
, does not work as expected in LLAMA.
LLAMA makes extensive use of proxy reference types (including llama::RecordRef
),
where a reference is sometimes represented as a value and sometimes as a real C++ reference.
The only consistent way to deal with this duality in LLAMA is the use a forwarding reference auto&&
when we want to have a reference (native or proxy) into a LLAMA data structure,
and to use a concrete type when we want to make a copy.