Skip to content

Commit 60c4dca

Browse files
support sub arrays of dynamic size as field type
* allow dynamic field types in the record dimension * add specializations to most of the core functions * add llama::dynamic to signal a dynamic array member in a RecordCoord * extend VirtualRecord to allow holding dynamic indices * extend blobNrAndOffset to allow for additional dynamic indices * add OffsetTable mapping * add customization allowing to dump OffsetTable mappings * add a few unit tests
1 parent 4e680cc commit 60c4dca

19 files changed

+822
-52
lines changed

examples/bufferguard/bufferguard.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ struct GuardMapping2D
6969
std::abort();
7070
}
7171

72-
template <std::size_t... RecordCoords>
73-
constexpr auto blobNrAndOffset(ArrayDims coord) const -> llama::NrAndOffset
72+
template <std::size_t... RecordCoords, std::size_t N = 0>
73+
constexpr auto blobNrAndOffset(ArrayDims coord, llama::Array<std::size_t, N> = {}) const -> llama::NrAndOffset
7474
{
7575
// [0][0] is at left top
7676
const auto [row, col] = coord;

include/llama/Core.hpp

+53
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ namespace llama
5858
inline constexpr bool isAllowedFieldType
5959
= std::is_trivially_constructible_v<T>&& std::is_trivially_destructible_v<T>;
6060

61+
template <typename... Fields>
62+
inline constexpr bool isAllowedFieldType<Record<Fields...>> = true;
63+
64+
template <typename T, std::size_t N>
65+
inline constexpr bool isAllowedFieldType<T[N]> = isAllowedFieldType<T>;
66+
67+
template <typename T>
68+
inline constexpr bool isAllowedFieldType<T[]> = isAllowedFieldType<T>;
69+
6170
/// Record dimension tree node which may either be a leaf or refer to a child tree presented as another \ref
6271
/// Record.
6372
/// \tparam Tag Name of the node. May be any type (struct, class).
@@ -134,6 +143,14 @@ namespace llama
134143
mp_push_front<typename GetTagsImpl<ChildTag, ChildType, RecordCoord<Coords...>>::type, CurrTag>;
135144
};
136145

146+
template <typename CurrTag, typename ChildType, std::size_t... Coords>
147+
struct GetTagsImpl<CurrTag, ChildType[], RecordCoord<dynamic, Coords...>>
148+
{
149+
using ChildTag = RecordCoord<dynamic>;
150+
using type = boost::mp11::
151+
mp_push_front<typename GetTagsImpl<ChildTag, ChildType, RecordCoord<Coords...>>::type, CurrTag>;
152+
};
153+
137154
template <typename CurrTag, typename T>
138155
struct GetTagsImpl<CurrTag, T, RecordCoord<>>
139156
{
@@ -212,6 +229,16 @@ namespace llama
212229
typename GetCoordFromTagsImpl<ChildType, RecordCoord<ResultCoords..., FirstTag::front>, Tags...>::type;
213230
};
214231

232+
template <typename ChildType, std::size_t... ResultCoords, typename FirstTag, typename... Tags>
233+
struct GetCoordFromTagsImpl<ChildType[], RecordCoord<ResultCoords...>, FirstTag, Tags...>
234+
{
235+
static_assert(
236+
std::is_same_v<FirstTag, RecordCoord<dynamic>>,
237+
"Please use a RecordCoord<dynamic> to index into dynamic arrays");
238+
using type =
239+
typename GetCoordFromTagsImpl<ChildType, RecordCoord<ResultCoords..., FirstTag::front>, Tags...>::type;
240+
};
241+
215242
template <typename RecordDim, typename RecordCoord>
216243
struct GetCoordFromTagsImpl<RecordDim, RecordCoord>
217244
{
@@ -244,6 +271,13 @@ namespace llama
244271
using type = typename GetTypeImpl<ChildType, RecordCoord<TailCoords...>>::type;
245272
};
246273

274+
template <typename ChildType, std::size_t HeadCoord, std::size_t... TailCoords>
275+
struct GetTypeImpl<ChildType[], RecordCoord<HeadCoord, TailCoords...>>
276+
{
277+
static_assert(HeadCoord == dynamic, "Record coord at a dynamic array must be llama::dynamic");
278+
using type = typename GetTypeImpl<ChildType, RecordCoord<TailCoords...>>::type;
279+
};
280+
247281
template <typename T>
248282
struct GetTypeImpl<T, RecordCoord<>>
249283
{
@@ -309,6 +343,12 @@ namespace llama
309343
}
310344
using type = decltype(help(std::make_index_sequence<N>{}));
311345
};
346+
347+
template <typename Child, std::size_t... RCs>
348+
struct LeafRecordCoordsImpl<Child[], RecordCoord<RCs...>>
349+
{
350+
using type = typename LeafRecordCoordsImpl<Child, RecordCoord<RCs..., dynamic>>::type;
351+
};
312352
} // namespace internal
313353

314354
/// Returns a flat type list containing all record coordinates to all leaves of the given record dimension.
@@ -553,5 +593,18 @@ namespace llama
553593
struct is_bounded_array<T[N]> : std::true_type
554594
{
555595
};
596+
597+
template <class T>
598+
struct is_unbounded_array : std::false_type
599+
{
600+
};
601+
602+
template <class T>
603+
struct is_unbounded_array<T[]> : std::true_type
604+
{
605+
};
606+
607+
template <typename T>
608+
inline constexpr bool is_unbounded_array_v = is_unbounded_array<T>::value;
556609
} // namespace internal
557610
} // namespace llama

include/llama/DumpMapping.hpp

+20
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "ArrayDimsIndexRange.hpp"
66
#include "Core.hpp"
7+
#include "mapping/OffsetTable.hpp"
78

89
#include <boost/functional/hash.hpp>
910
#include <fmt/format.h>
@@ -138,6 +139,25 @@ namespace llama
138139
return infos;
139140
}
140141

142+
template <typename ArrayDims, typename RecordDim, typename SubMappings>
143+
auto boxesFromMapping(const mapping::OffsetTable<ArrayDims, RecordDim, SubMappings>& mapping)
144+
-> std::vector<FieldBox<ArrayDims::rank>>
145+
{
146+
std::size_t previousBlobs = 0;
147+
std::vector<FieldBox<ArrayDims::rank>> infos;
148+
boost::mp11::mp_for_each<boost::mp11::mp_iota<boost::mp11::mp_size<decltype(mapping.subMappings)>>>(
149+
[&](auto ic)
150+
{
151+
const auto& subMapping = get<decltype(ic)::value>(mapping.subMappings);
152+
auto subBoxes = boxesFromMapping(subMapping);
153+
for (auto& box : subBoxes)
154+
box.nrAndOffset.nr += previousBlobs;
155+
infos.insert(infos.end(), subBoxes.begin(), subBoxes.end());
156+
previousBlobs += std::decay_t<decltype(subMapping)>::blobCount;
157+
});
158+
return infos;
159+
}
160+
141161
template <std::size_t Dim>
142162
auto breakBoxes(std::vector<FieldBox<Dim>> boxes, std::size_t wrapByteCount) -> std::vector<FieldBox<Dim>>
143163
{

include/llama/RecordCoord.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
#include <array>
77
#include <boost/mp11.hpp>
8+
#include <limits>
89
#include <type_traits>
910

1011
namespace llama
1112
{
13+
inline constexpr auto dynamic = std::numeric_limits<std::size_t>::max();
14+
1215
/// Represents a coordinate for a record inside the record dimension tree.
1316
/// \tparam Coords... the compile time coordinate.
1417
template <std::size_t... Coords>

include/llama/View.hpp

+17-12
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,12 @@ namespace llama
265265
if constexpr (isRecord<RecordDim> || internal::is_bounded_array<RecordDim>::value)
266266
{
267267
LLAMA_FORCE_INLINE_RECURSIVE
268-
return VirtualRecordTypeConst{arrayDims, *this};
268+
return VirtualRecordTypeConst{*this, arrayDims};
269269
}
270270
else
271271
{
272272
LLAMA_FORCE_INLINE_RECURSIVE
273-
return accessor(arrayDims, RecordCoord<>{});
273+
return accessor(arrayDims, Array<size_t, 0>{}, RecordCoord<>{});
274274
}
275275
}
276276

@@ -279,12 +279,12 @@ namespace llama
279279
if constexpr (isRecord<RecordDim> || internal::is_bounded_array<RecordDim>::value)
280280
{
281281
LLAMA_FORCE_INLINE_RECURSIVE
282-
return VirtualRecordType{arrayDims, *this};
282+
return VirtualRecordType{*this, arrayDims};
283283
}
284284
else
285285
{
286286
LLAMA_FORCE_INLINE_RECURSIVE
287-
return accessor(arrayDims, RecordCoord<>{});
287+
return accessor(arrayDims, Array<size_t, 0>{}, RecordCoord<>{});
288288
}
289289
}
290290

@@ -375,29 +375,34 @@ namespace llama
375375
friend struct VirtualRecord;
376376

377377
LLAMA_SUPPRESS_HOST_DEVICE_WARNING
378-
template <std::size_t... Coords>
379-
LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayDims arrayDims, RecordCoord<Coords...> dc = {}) const
380-
-> decltype(auto)
378+
template <std::size_t N, std::size_t... Coords>
379+
LLAMA_FN_HOST_ACC_INLINE auto accessor(
380+
ArrayDims arrayDims,
381+
Array<size_t, N> dynamicArrayExtents,
382+
RecordCoord<Coords...> dc = {}) const -> decltype(auto)
381383
{
382384
if constexpr (isComputed<Mapping, RecordCoord<Coords...>>)
383385
return mapping.compute(arrayDims, dc, storageBlobs);
384386
else
385387
{
386-
const auto [nr, offset] = mapping.template blobNrAndOffset<Coords...>(arrayDims);
388+
const auto [nr, offset] = mapping.template blobNrAndOffset<Coords...>(arrayDims, dynamicArrayExtents);
387389
using Type = GetType<RecordDim, RecordCoord<Coords...>>;
388390
return reinterpret_cast<const Type&>(storageBlobs[nr][offset]);
389391
}
390392
}
391393

392394
LLAMA_SUPPRESS_HOST_DEVICE_WARNING
393-
template <std::size_t... Coords>
394-
LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayDims arrayDims, RecordCoord<Coords...> dc = {}) -> decltype(auto)
395+
template <std::size_t N, std::size_t... Coords>
396+
LLAMA_FN_HOST_ACC_INLINE auto accessor(
397+
ArrayDims arrayDims,
398+
Array<size_t, N> dynamicArrayExtents,
399+
RecordCoord<Coords...> dc = {}) -> decltype(auto)
395400
{
396401
if constexpr (isComputed<Mapping, RecordCoord<Coords...>>)
397-
return mapping.compute(arrayDims, dc, storageBlobs);
402+
return mapping.compute(arrayDims, dynamicArrayExtents, dc, storageBlobs);
398403
else
399404
{
400-
const auto [nr, offset] = mapping.template blobNrAndOffset<Coords...>(arrayDims);
405+
const auto [nr, offset] = mapping.template blobNrAndOffset<Coords...>(arrayDims, dynamicArrayExtents);
401406
using Type = GetType<RecordDim, RecordCoord<Coords...>>;
402407
return reinterpret_cast<Type&>(storageBlobs[nr][offset]);
403408
}

include/llama/VirtualRecord.hpp

+83-12
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,21 @@ namespace llama
309309
template <typename T, template <typename...> typename Tuple, typename... Args>
310310
constexpr inline auto
311311
isDirectListInitializableFromTuple<T, Tuple<Args...>> = isDirectListInitializable<T, Args...>;
312+
313+
template <typename RecordDim, typename RecordCoord>
314+
constexpr inline auto unboundArraysUntil = []() constexpr
315+
{
316+
std::size_t count = 0;
317+
boost::mp11::mp_for_each<boost::mp11::mp_iota_c<RecordCoord::size>>(
318+
[&](auto i) constexpr
319+
{
320+
using RC = RecordCoordFromList<boost::mp11::mp_take_c<typename RecordCoord::List, i>>;
321+
using TypeAtRC = GetType<RecordDim, RC>;
322+
count += static_cast<std::size_t>(internal::is_unbounded_array_v<TypeAtRC>);
323+
});
324+
return count;
325+
}
326+
();
312327
} // namespace internal
313328

314329
/// Virtual record type returned by \ref View after resolving an array dimensions coordinate or partially resolving
@@ -324,9 +339,11 @@ namespace llama
324339
private:
325340
using ArrayDims = typename View::Mapping::ArrayDims;
326341
using RecordDim = typename View::Mapping::RecordDim;
342+
using DynamicArrayExtentsArray = Array<std::size_t, internal::unboundArraysUntil<RecordDim, BoundRecordCoord>>;
327343

328-
[[no_unique_address]] const ArrayDims arrayDimsCoord;
329344
std::conditional_t<OwnView, View, View&> view;
345+
[[no_unique_address]] const ArrayDims arrayDimsCoord;
346+
[[no_unique_address]] const DynamicArrayExtentsArray dynamicArrayExtents;
330347

331348
public:
332349
/// Subtree of the record dimension of View starting at BoundRecordCoord. If BoundRecordCoord is `RecordCoord<>`
@@ -337,15 +354,20 @@ namespace llama
337354
LLAMA_FN_HOST_ACC_INLINE VirtualRecord()
338355
/* requires(OwnView) */
339356
: arrayDimsCoord({})
357+
, dynamicArrayExtents({})
340358
, view{allocViewStack<0, RecordDim>()}
341359
{
342360
static_assert(OwnView, "The default constructor of VirtualRecord is only available if it owns the view.");
343361
}
344362

345363
LLAMA_FN_HOST_ACC_INLINE
346-
VirtualRecord(ArrayDims arrayDimsCoord, std::conditional_t<OwnView, View&&, View&> view)
347-
: arrayDimsCoord(arrayDimsCoord)
348-
, view{static_cast<decltype(view)>(view)}
364+
VirtualRecord(
365+
std::conditional_t<OwnView, View&&, View&> view,
366+
ArrayDims arrayDimsCoord,
367+
DynamicArrayExtentsArray dynamicArrayExtents = {})
368+
: view{static_cast<decltype(view)>(view)}
369+
, arrayDimsCoord(arrayDimsCoord)
370+
, dynamicArrayExtents{dynamicArrayExtents}
349371
{
350372
}
351373

@@ -388,15 +410,21 @@ namespace llama
388410
{
389411
using AbsolutCoord = Cat<BoundRecordCoord, RecordCoord<Coord...>>;
390412
using AccessedType = GetType<RecordDim, AbsolutCoord>;
391-
if constexpr (isRecord<AccessedType> || internal::is_bounded_array<AccessedType>::value)
413+
if constexpr (
414+
isRecord<AccessedType> || internal::is_bounded_array<AccessedType>::value
415+
|| internal::is_unbounded_array_v<AccessedType>)
392416
{
393417
LLAMA_FORCE_INLINE_RECURSIVE
394-
return VirtualRecord<const View, AbsolutCoord>{arrayDimsCoord, this->view};
418+
return VirtualRecord<const View, AbsolutCoord>{
419+
this->view,
420+
arrayDimsCoord,
421+
dynamicArrayExtents,
422+
};
395423
}
396424
else
397425
{
398426
LLAMA_FORCE_INLINE_RECURSIVE
399-
return this->view.accessor(arrayDimsCoord, AbsolutCoord{});
427+
return this->view.accessor(arrayDimsCoord, dynamicArrayExtents, AbsolutCoord{});
400428
}
401429
}
402430

@@ -406,22 +434,24 @@ namespace llama
406434
{
407435
using AbsolutCoord = Cat<BoundRecordCoord, RecordCoord<Coord...>>;
408436
using AccessedType = GetType<RecordDim, AbsolutCoord>;
409-
if constexpr (isRecord<AccessedType> || internal::is_bounded_array<AccessedType>::value)
437+
if constexpr (
438+
isRecord<AccessedType> || internal::is_bounded_array<AccessedType>::value
439+
|| internal::is_unbounded_array_v<AccessedType>)
410440
{
411441
LLAMA_FORCE_INLINE_RECURSIVE
412-
return VirtualRecord<View, AbsolutCoord>{arrayDimsCoord, this->view};
442+
return VirtualRecord<View, AbsolutCoord>{this->view, arrayDimsCoord, dynamicArrayExtents};
413443
}
414444
else
415445
{
416446
LLAMA_FORCE_INLINE_RECURSIVE
417-
return this->view.accessor(arrayDimsCoord, AbsolutCoord{});
447+
return this->view.accessor(arrayDimsCoord, dynamicArrayExtents, AbsolutCoord{});
418448
}
419449
}
420450

421451
/// Access a record in the record dimension underneath the current virtual record using a series of tags. If the
422452
/// access resolves to a leaf, a reference to a variable inside the \ref View storage is returned, otherwise
423453
/// another virtual record.
424-
template <typename... Tags>
454+
template <typename... Tags, std::enable_if_t<!std::disjunction_v<std::is_integral<Tags>...>, bool> = true>
425455
LLAMA_FN_HOST_ACC_INLINE auto operator()(Tags...) const -> decltype(auto)
426456
{
427457
using RecordCoord = GetCoordFromTagsRelative<RecordDim, BoundRecordCoord, Tags...>;
@@ -431,7 +461,7 @@ namespace llama
431461
}
432462

433463
// FIXME(bgruber): remove redundancy
434-
template <typename... Tags>
464+
template <typename... Tags, std::enable_if_t<!std::disjunction_v<std::is_integral<Tags>...>, bool> = true>
435465
LLAMA_FN_HOST_ACC_INLINE auto operator()(Tags...) -> decltype(auto)
436466
{
437467
using RecordCoord = GetCoordFromTagsRelative<RecordDim, BoundRecordCoord, Tags...>;
@@ -440,6 +470,47 @@ namespace llama
440470
return operator()(RecordCoord{});
441471
}
442472

473+
template <
474+
typename ADD = AccessibleRecordDim,
475+
std::enable_if_t<internal::is_unbounded_array_v<ADD>, bool> = true>
476+
LLAMA_FN_HOST_ACC_INLINE auto operator()(std::size_t i) const -> decltype(auto)
477+
{
478+
using AbsolutCoord = Cat<BoundRecordCoord, RecordCoord<dynamic>>;
479+
using ResolvedType = GetType<RecordDim, AbsolutCoord>;
480+
auto newDynamicArrayExtents = push_back(dynamicArrayExtents, i);
481+
if constexpr (isRecord<ResolvedType> || internal::is_unbounded_array_v<ResolvedType>)
482+
{
483+
LLAMA_FORCE_INLINE_RECURSIVE
484+
return VirtualRecord<const View, AbsolutCoord>{this->view, arrayDimsCoord, newDynamicArrayExtents};
485+
}
486+
else
487+
{
488+
LLAMA_FORCE_INLINE_RECURSIVE
489+
return this->view.accessor(arrayDimsCoord, newDynamicArrayExtents, AbsolutCoord{});
490+
}
491+
}
492+
493+
// FIXME(bgruber): remove redundancy
494+
template <
495+
typename ADD = AccessibleRecordDim,
496+
std::enable_if_t<internal::is_unbounded_array_v<ADD>, bool> = true>
497+
LLAMA_FN_HOST_ACC_INLINE auto operator()(std::size_t i) -> decltype(auto)
498+
{
499+
using AbsolutCoord = Cat<BoundRecordCoord, RecordCoord<dynamic>>;
500+
using ResolvedType = GetType<RecordDim, AbsolutCoord>;
501+
auto newDynamicArrayExtents = push_back(dynamicArrayExtents, i);
502+
if constexpr (isRecord<ResolvedType> || internal::is_unbounded_array_v<ResolvedType>)
503+
{
504+
LLAMA_FORCE_INLINE_RECURSIVE
505+
return VirtualRecord<View, AbsolutCoord>{this->view, arrayDimsCoord, newDynamicArrayExtents};
506+
}
507+
else
508+
{
509+
LLAMA_FORCE_INLINE_RECURSIVE
510+
return this->view.accessor(arrayDimsCoord, newDynamicArrayExtents, AbsolutCoord{});
511+
}
512+
}
513+
443514
// we need this one to disable the compiler generated copy assignment
444515
LLAMA_FN_HOST_ACC_INLINE auto operator=(const VirtualRecord& other) -> VirtualRecord&
445516
{

0 commit comments

Comments
 (0)