Skip to content

Commit

Permalink
support sub arrays of dynamic size as field type
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
bernhardmgruber committed Jul 7, 2021
1 parent 225108d commit 7ab012e
Show file tree
Hide file tree
Showing 19 changed files with 823 additions and 52 deletions.
4 changes: 2 additions & 2 deletions examples/bufferguard/bufferguard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ struct GuardMapping2D
std::abort();
}

template <std::size_t... RecordCoords>
constexpr auto blobNrAndOffset(ArrayDims coord) const -> llama::NrAndOffset
template <std::size_t... RecordCoords, std::size_t N = 0>
constexpr auto blobNrAndOffset(ArrayDims coord, llama::Array<std::size_t, N> = {}) const -> llama::NrAndOffset
{
// [0][0] is at left top
const auto [row, col] = coord;
Expand Down
53 changes: 53 additions & 0 deletions include/llama/Core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ namespace llama
inline constexpr bool isAllowedFieldType
= std::is_trivially_constructible_v<T>&& std::is_trivially_destructible_v<T>;

template <typename... Fields>
inline constexpr bool isAllowedFieldType<Record<Fields...>> = true;

template <typename T, std::size_t N>
inline constexpr bool isAllowedFieldType<T[N]> = isAllowedFieldType<T>;

template <typename T>
inline constexpr bool isAllowedFieldType<T[]> = isAllowedFieldType<T>;

/// Record dimension tree node which may either be a leaf or refer to a child tree presented as another \ref
/// Record.
/// \tparam Tag Name of the node. May be any type (struct, class).
Expand Down Expand Up @@ -134,6 +143,14 @@ namespace llama
mp_push_front<typename GetTagsImpl<ChildTag, ChildType, RecordCoord<Coords...>>::type, CurrTag>;
};

template <typename CurrTag, typename ChildType, std::size_t... Coords>
struct GetTagsImpl<CurrTag, ChildType[], RecordCoord<dynamic, Coords...>>
{
using ChildTag = RecordCoord<dynamic>;
using type = boost::mp11::
mp_push_front<typename GetTagsImpl<ChildTag, ChildType, RecordCoord<Coords...>>::type, CurrTag>;
};

template <typename CurrTag, typename T>
struct GetTagsImpl<CurrTag, T, RecordCoord<>>
{
Expand Down Expand Up @@ -212,6 +229,16 @@ namespace llama
typename GetCoordFromTagsImpl<ChildType, RecordCoord<ResultCoords..., FirstTag::front>, Tags...>::type;
};

template <typename ChildType, std::size_t... ResultCoords, typename FirstTag, typename... Tags>
struct GetCoordFromTagsImpl<ChildType[], RecordCoord<ResultCoords...>, FirstTag, Tags...>
{
static_assert(
std::is_same_v<FirstTag, RecordCoord<dynamic>>,
"Please use a RecordCoord<dynamic> to index into dynamic arrays");
using type =
typename GetCoordFromTagsImpl<ChildType, RecordCoord<ResultCoords..., FirstTag::front>, Tags...>::type;
};

template <typename RecordDim, typename RecordCoord>
struct GetCoordFromTagsImpl<RecordDim, RecordCoord>
{
Expand Down Expand Up @@ -244,6 +271,13 @@ namespace llama
using type = typename GetTypeImpl<ChildType, RecordCoord<TailCoords...>>::type;
};

template <typename ChildType, std::size_t HeadCoord, std::size_t... TailCoords>
struct GetTypeImpl<ChildType[], RecordCoord<HeadCoord, TailCoords...>>
{
static_assert(HeadCoord == dynamic, "Record coord at a dynamic array must be llama::dynamic");
using type = typename GetTypeImpl<ChildType, RecordCoord<TailCoords...>>::type;
};

template <typename T>
struct GetTypeImpl<T, RecordCoord<>>
{
Expand Down Expand Up @@ -309,6 +343,12 @@ namespace llama
}
using type = decltype(help(std::make_index_sequence<N>{}));
};

template <typename Child, std::size_t... RCs>
struct LeafRecordCoordsImpl<Child[], RecordCoord<RCs...>>
{
using type = typename LeafRecordCoordsImpl<Child, RecordCoord<RCs..., dynamic>>::type;
};
} // namespace internal

/// Returns a flat type list containing all record coordinates to all leaves of the given record dimension.
Expand Down Expand Up @@ -553,5 +593,18 @@ namespace llama
struct is_bounded_array<T[N]> : std::true_type
{
};

template <class T>
struct is_unbounded_array : std::false_type
{
};

template <class T>
struct is_unbounded_array<T[]> : std::true_type
{
};

template <typename T>
inline constexpr bool is_unbounded_array_v = is_unbounded_array<T>::value;
} // namespace internal
} // namespace llama
20 changes: 20 additions & 0 deletions include/llama/DumpMapping.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "ArrayDimsIndexRange.hpp"
#include "Core.hpp"
#include "mapping/OffsetTable.hpp"

#include <boost/functional/hash.hpp>
#include <fmt/format.h>
Expand Down Expand Up @@ -138,6 +139,25 @@ namespace llama
return infos;
}

template <typename ArrayDims, typename RecordDim, typename SubMappings>
auto boxesFromMapping(const mapping::OffsetTable<ArrayDims, RecordDim, SubMappings>& mapping)
-> std::vector<FieldBox<ArrayDims::rank>>
{
std::size_t previousBlobs = 0;
std::vector<FieldBox<ArrayDims::rank>> infos;
boost::mp11::mp_for_each<boost::mp11::mp_iota<boost::mp11::mp_size<decltype(mapping.subMappings)>>>(
[&](auto ic)
{
const auto& subMapping = get<decltype(ic)::value>(mapping.subMappings);
auto subBoxes = boxesFromMapping(subMapping);
for (auto& box : subBoxes)
box.nrAndOffset.nr += previousBlobs;
infos.insert(infos.end(), subBoxes.begin(), subBoxes.end());
previousBlobs += std::decay_t<decltype(subMapping)>::blobCount;
});
return infos;
}

template <std::size_t Dim>
auto breakBoxes(std::vector<FieldBox<Dim>> boxes, std::size_t wrapByteCount) -> std::vector<FieldBox<Dim>>
{
Expand Down
3 changes: 3 additions & 0 deletions include/llama/RecordCoord.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
#include "Meta.hpp"

#include <array>
#include <limits>
#include <type_traits>

namespace llama
{
inline constexpr auto dynamic = std::numeric_limits<std::size_t>::max();

/// Represents a coordinate for a record inside the record dimension tree.
/// \tparam Coords... the compile time coordinate.
template <std::size_t... Coords>
Expand Down
29 changes: 17 additions & 12 deletions include/llama/View.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,12 @@ namespace llama
if constexpr (isRecord<RecordDim> || internal::is_bounded_array<RecordDim>::value)
{
LLAMA_FORCE_INLINE_RECURSIVE
return VirtualRecordTypeConst{arrayDims, *this};
return VirtualRecordTypeConst{*this, arrayDims};
}
else
{
LLAMA_FORCE_INLINE_RECURSIVE
return accessor(arrayDims, RecordCoord<>{});
return accessor(arrayDims, Array<size_t, 0>{}, RecordCoord<>{});
}
}

Expand All @@ -279,12 +279,12 @@ namespace llama
if constexpr (isRecord<RecordDim> || internal::is_bounded_array<RecordDim>::value)
{
LLAMA_FORCE_INLINE_RECURSIVE
return VirtualRecordType{arrayDims, *this};
return VirtualRecordType{*this, arrayDims};
}
else
{
LLAMA_FORCE_INLINE_RECURSIVE
return accessor(arrayDims, RecordCoord<>{});
return accessor(arrayDims, Array<size_t, 0>{}, RecordCoord<>{});
}
}

Expand Down Expand Up @@ -375,29 +375,34 @@ namespace llama
friend struct VirtualRecord;

LLAMA_SUPPRESS_HOST_DEVICE_WARNING
template <std::size_t... Coords>
LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayDims arrayDims, RecordCoord<Coords...> dc = {}) const
-> decltype(auto)
template <std::size_t N, std::size_t... Coords>
LLAMA_FN_HOST_ACC_INLINE auto accessor(
ArrayDims arrayDims,
Array<size_t, N> dynamicArrayExtents,
RecordCoord<Coords...> dc = {}) const -> decltype(auto)
{
if constexpr (isComputed<Mapping, RecordCoord<Coords...>>)
return mapping.compute(arrayDims, dc, storageBlobs);
else
{
const auto [nr, offset] = mapping.template blobNrAndOffset<Coords...>(arrayDims);
const auto [nr, offset] = mapping.template blobNrAndOffset<Coords...>(arrayDims, dynamicArrayExtents);
using Type = GetType<RecordDim, RecordCoord<Coords...>>;
return reinterpret_cast<const Type&>(storageBlobs[nr][offset]);
}
}

LLAMA_SUPPRESS_HOST_DEVICE_WARNING
template <std::size_t... Coords>
LLAMA_FN_HOST_ACC_INLINE auto accessor(ArrayDims arrayDims, RecordCoord<Coords...> dc = {}) -> decltype(auto)
template <std::size_t N, std::size_t... Coords>
LLAMA_FN_HOST_ACC_INLINE auto accessor(
ArrayDims arrayDims,
Array<size_t, N> dynamicArrayExtents,
RecordCoord<Coords...> dc = {}) -> decltype(auto)
{
if constexpr (isComputed<Mapping, RecordCoord<Coords...>>)
return mapping.compute(arrayDims, dc, storageBlobs);
return mapping.compute(arrayDims, dynamicArrayExtents, dc, storageBlobs);
else
{
const auto [nr, offset] = mapping.template blobNrAndOffset<Coords...>(arrayDims);
const auto [nr, offset] = mapping.template blobNrAndOffset<Coords...>(arrayDims, dynamicArrayExtents);
using Type = GetType<RecordDim, RecordCoord<Coords...>>;
return reinterpret_cast<Type&>(storageBlobs[nr][offset]);
}
Expand Down
95 changes: 83 additions & 12 deletions include/llama/VirtualRecord.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,21 @@ namespace llama
template <typename T, template <typename...> typename Tuple, typename... Args>
constexpr inline auto
isDirectListInitializableFromTuple<T, Tuple<Args...>> = isDirectListInitializable<T, Args...>;

template <typename RecordDim, typename RecordCoord>
constexpr inline auto unboundArraysUntil = []() constexpr
{
std::size_t count = 0;
boost::mp11::mp_for_each<boost::mp11::mp_iota_c<RecordCoord::size>>(
[&](auto i) constexpr
{
using RC = RecordCoordFromList<boost::mp11::mp_take_c<typename RecordCoord::List, i>>;
using TypeAtRC = GetType<RecordDim, RC>;
count += static_cast<std::size_t>(internal::is_unbounded_array_v<TypeAtRC>);
});
return count;
}
();
} // namespace internal

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

[[no_unique_address]] const ArrayDims arrayDimsCoord;
std::conditional_t<OwnView, View, View&> view;
[[no_unique_address]] const ArrayDims arrayDimsCoord;
[[no_unique_address]] const DynamicArrayExtentsArray dynamicArrayExtents;

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

LLAMA_FN_HOST_ACC_INLINE
VirtualRecord(ArrayDims arrayDimsCoord, std::conditional_t<OwnView, View&&, View&> view)
: arrayDimsCoord(arrayDimsCoord)
, view{static_cast<decltype(view)>(view)}
VirtualRecord(
std::conditional_t<OwnView, View&&, View&> view,
ArrayDims arrayDimsCoord,
DynamicArrayExtentsArray dynamicArrayExtents = {})
: view{static_cast<decltype(view)>(view)}
, arrayDimsCoord(arrayDimsCoord)
, dynamicArrayExtents{dynamicArrayExtents}
{
}

Expand Down Expand Up @@ -388,15 +410,21 @@ namespace llama
{
using AbsolutCoord = Cat<BoundRecordCoord, RecordCoord<Coord...>>;
using AccessedType = GetType<RecordDim, AbsolutCoord>;
if constexpr (isRecord<AccessedType> || internal::is_bounded_array<AccessedType>::value)
if constexpr (
isRecord<AccessedType> || internal::is_bounded_array<AccessedType>::value
|| internal::is_unbounded_array_v<AccessedType>)
{
LLAMA_FORCE_INLINE_RECURSIVE
return VirtualRecord<const View, AbsolutCoord>{arrayDimsCoord, this->view};
return VirtualRecord<const View, AbsolutCoord>{
this->view,
arrayDimsCoord,
dynamicArrayExtents,
};
}
else
{
LLAMA_FORCE_INLINE_RECURSIVE
return this->view.accessor(arrayDimsCoord, AbsolutCoord{});
return this->view.accessor(arrayDimsCoord, dynamicArrayExtents, AbsolutCoord{});
}
}

Expand All @@ -406,22 +434,24 @@ namespace llama
{
using AbsolutCoord = Cat<BoundRecordCoord, RecordCoord<Coord...>>;
using AccessedType = GetType<RecordDim, AbsolutCoord>;
if constexpr (isRecord<AccessedType> || internal::is_bounded_array<AccessedType>::value)
if constexpr (
isRecord<AccessedType> || internal::is_bounded_array<AccessedType>::value
|| internal::is_unbounded_array_v<AccessedType>)
{
LLAMA_FORCE_INLINE_RECURSIVE
return VirtualRecord<View, AbsolutCoord>{arrayDimsCoord, this->view};
return VirtualRecord<View, AbsolutCoord>{this->view, arrayDimsCoord, dynamicArrayExtents};
}
else
{
LLAMA_FORCE_INLINE_RECURSIVE
return this->view.accessor(arrayDimsCoord, AbsolutCoord{});
return this->view.accessor(arrayDimsCoord, dynamicArrayExtents, AbsolutCoord{});
}
}

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

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

template <
typename ADD = AccessibleRecordDim,
std::enable_if_t<internal::is_unbounded_array_v<ADD>, bool> = true>
LLAMA_FN_HOST_ACC_INLINE auto operator()(std::size_t i) const -> decltype(auto)
{
using AbsolutCoord = Cat<BoundRecordCoord, RecordCoord<dynamic>>;
using ResolvedType = GetType<RecordDim, AbsolutCoord>;
auto newDynamicArrayExtents = push_back(dynamicArrayExtents, i);
if constexpr (isRecord<ResolvedType> || internal::is_unbounded_array_v<ResolvedType>)
{
LLAMA_FORCE_INLINE_RECURSIVE
return VirtualRecord<const View, AbsolutCoord>{this->view, arrayDimsCoord, newDynamicArrayExtents};
}
else
{
LLAMA_FORCE_INLINE_RECURSIVE
return this->view.accessor(arrayDimsCoord, newDynamicArrayExtents, AbsolutCoord{});
}
}

// FIXME(bgruber): remove redundancy
template <
typename ADD = AccessibleRecordDim,
std::enable_if_t<internal::is_unbounded_array_v<ADD>, bool> = true>
LLAMA_FN_HOST_ACC_INLINE auto operator()(std::size_t i) -> decltype(auto)
{
using AbsolutCoord = Cat<BoundRecordCoord, RecordCoord<dynamic>>;
using ResolvedType = GetType<RecordDim, AbsolutCoord>;
auto newDynamicArrayExtents = push_back(dynamicArrayExtents, i);
if constexpr (isRecord<ResolvedType> || internal::is_unbounded_array_v<ResolvedType>)
{
LLAMA_FORCE_INLINE_RECURSIVE
return VirtualRecord<View, AbsolutCoord>{this->view, arrayDimsCoord, newDynamicArrayExtents};
}
else
{
LLAMA_FORCE_INLINE_RECURSIVE
return this->view.accessor(arrayDimsCoord, newDynamicArrayExtents, AbsolutCoord{});
}
}

// we need this one to disable the compiler generated copy assignment
LLAMA_FN_HOST_ACC_INLINE auto operator=(const VirtualRecord& other) -> VirtualRecord&
{
Expand Down
Loading

0 comments on commit 7ab012e

Please sign in to comment.