Skip to content

Commit

Permalink
run field constructors when views are allocated
Browse files Browse the repository at this point in the history
* allocView will run field constructors
* add allocViewUninitialized to still have uninitialized views
* add constructFields
* remove isAllowedFieldType
* add tree::Mapping::arrayDims()
* enable many unit tests relying on fields being initialized
* add tests for uninitialized views and for explicit construction
  • Loading branch information
bernhardmgruber committed Sep 21, 2021
1 parent 55ec371 commit 381a033
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 108 deletions.
4 changes: 4 additions & 0 deletions docs/pages/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Array dimensions
.. doxygenstruct:: llama::ArrayDimsIndexRange
:members:

.. doxygenfunction:: llama::forEachADCoord

Record dimension
----------------

Expand Down Expand Up @@ -77,6 +79,8 @@ View creation

.. _label-api-allocView:
.. doxygenfunction:: llama::allocView
.. doxygenfunction:: llama::constructFields
.. doxygenfunction:: llama::allocViewUninitialized
.. doxygenfunction:: llama::allocViewStack
.. doxygentypedef:: llama::One
.. doxygenfunction:: llama::copyVirtualRecordStack
Expand Down
13 changes: 5 additions & 8 deletions include/llama/Core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ namespace llama
/// @brief Tells whether the given type is allowed as a field type in LLAMA. Such types need to be trivially
/// constructible and trivially destructible.
template<typename T>
inline constexpr bool isAllowedFieldType
= std::is_trivially_default_constructible_v<T>&& std::is_trivially_destructible_v<T>;
inline constexpr bool isAllowedFieldType = std::is_trivially_destructible_v<T>;

/// Record dimension tree node which may either be a leaf or refer to a child tree presented as another \ref
/// Record.
Expand Down Expand Up @@ -555,13 +554,11 @@ namespace llama
template<std::size_t Dim, typename Func, typename... OuterIndices>
LLAMA_FN_HOST_ACC_INLINE void forEachADCoord(ArrayDims<Dim> adSize, Func&& func, OuterIndices... outerIndices)
{
for(std::size_t i = 0; i < adSize[0]; i++)
{
if constexpr(Dim > 1)
if constexpr(Dim > 0)
for(std::size_t i = 0; i < adSize[0]; i++)
forEachADCoord(ArrayDims<Dim - 1>{pop_front(adSize)}, std::forward<Func>(func), outerIndices..., i);
else
std::forward<Func>(func)(ArrayDims<sizeof...(outerIndices) + 1>{outerIndices..., i});
}
else
std::forward<Func>(func)(ArrayDims<sizeof...(outerIndices)>{outerIndices...});
}

namespace internal
Expand Down
83 changes: 61 additions & 22 deletions include/llama/View.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,66 @@ namespace llama
}
} // namespace internal

/// Same as \ref allocView but does not run field constructors.
#ifdef __cpp_lib_concepts
template<typename Mapping, BlobAllocator Allocator = bloballoc::Vector>
#else
template<typename Mapping, typename Allocator = bloballoc::Vector>
#endif
LLAMA_FN_HOST_ACC_INLINE auto allocViewUninitialized(Mapping mapping = {}, const Allocator& alloc = {})
-> View<Mapping, internal::AllocatorBlobType<Allocator, typename Mapping::RecordDim>>
{
auto blobs = internal::makeBlobArray(alloc, mapping, std::make_index_sequence<Mapping::blobCount>{});
return {std::move(mapping), std::move(blobs)};
}

namespace internal
{
template<typename Mapping, typename RecordCoord, typename = void>
struct IsComputed : std::false_type
{
};

template<typename Mapping, typename RecordCoord>
struct IsComputed<Mapping, RecordCoord, std::void_t<decltype(Mapping::isComputed(RecordCoord{}))>>
: std::bool_constant<Mapping::isComputed(RecordCoord{})>
{
};
} // namespace internal

/// Returns true if the field accessed via the given mapping and record coordinate is a computed value.
template<typename Mapping, typename RecordCoord>
inline constexpr bool isComputed = internal::IsComputed<Mapping, RecordCoord>::value;

/// Runs the constructor of all fields reachable through the given view. Computed fields are not constructed.
template<typename Mapping, typename BlobType>
LLAMA_FN_HOST_ACC_INLINE void constructFields(View<Mapping, BlobType>& view)
{
using View = View<Mapping, BlobType>;
using RecordDim = typename View::RecordDim;
forEachADCoord(
view.mapping().arrayDims(),
[&](typename View::ArrayDims ad)
{
if constexpr(isRecord<RecordDim> || internal::IsBoundedArray<RecordDim>::value)
forEachLeaf<RecordDim>(
[&](auto coord)
{
// TODO(bgruber): we could initialize computed fields if we can write to those. We could
// test if the returned value can be cast to a T& and then attempt to write.
if constexpr(!isComputed<Mapping, decltype(coord)>)
new(&view(ad)(coord)) GetType<RecordDim, decltype(coord)>;
});
else if constexpr(!isComputed<Mapping, RecordCoord<>>)
new(&view(ad)) RecordDim;
});
}

/// Creates a view based on the given mapping, e.g. \ref AoS or \ref :SoA. For allocating the view's underlying
/// memory, the specified allocator callable is used (or the default one, which is \ref bloballoc::Vector). The
/// allocator callable is called with the size of bytes to allocate for each blob of the mapping. This function is
/// the preferred way to create a \ref View.
/// allocator callable is called with the alignment and size of bytes to allocate for each blob of the mapping.
/// The constructors are run for all fields by calling \ref constructFields. This function is the preferred way to
/// create a \ref View. See also \ref allocViewUninitialized.
#ifdef __cpp_lib_concepts
template<typename Mapping, BlobAllocator Allocator = bloballoc::Vector>
#else
Expand All @@ -53,8 +109,9 @@ namespace llama
LLAMA_FN_HOST_ACC_INLINE auto allocView(Mapping mapping = {}, const Allocator& alloc = {})
-> View<Mapping, internal::AllocatorBlobType<Allocator, typename Mapping::RecordDim>>
{
auto blobs = internal::makeBlobArray(alloc, mapping, std::make_index_sequence<Mapping::blobCount>{});
return {std::move(mapping), std::move(blobs)};
auto view = allocViewUninitialized(std::move(mapping), alloc);
constructFields(view);
return view;
}

/// Allocates a \ref View holding a single record backed by stack memory (\ref bloballoc::Stack).
Expand Down Expand Up @@ -216,24 +273,6 @@ namespace llama
View* view;
};

namespace internal
{
template<typename Mapping, typename RecordCoord, typename = void>
struct IsComputed : std::false_type
{
};

template<typename Mapping, typename RecordCoord>
struct IsComputed<Mapping, RecordCoord, std::void_t<decltype(Mapping::isComputed(RecordCoord{}))>>
: std::bool_constant<Mapping::isComputed(RecordCoord{})>
{
};
} // namespace internal

/// Returns true if the field accessed via the given mapping and record coordinate is a computed value.
template<typename Mapping, typename RecordCoord>
inline constexpr bool isComputed = internal::IsComputed<Mapping, RecordCoord>::value;

/// Central LLAMA class holding memory for storage and giving access to values stored there defined by a mapping. A
/// view should be created using \ref allocView.
/// \tparam TMapping The mapping used by the view to map accesses into memory.
Expand Down
5 changes: 3 additions & 2 deletions include/llama/mapping/One.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ namespace llama::mapping
{
// TODO(bgruber): not sure if this is the right approach, since we take any ArrayDims in the ctor
ArrayDims ad;
for(auto i = 0; i < ArrayDims::rank; i++)
ad[i] = 1;
if constexpr(ArrayDims::rank > 0)
for(auto i = 0; i < ArrayDims::rank; i++)
ad[i] = 1;
return ad;
}

Expand Down
5 changes: 5 additions & 0 deletions include/llama/mapping/tree/Mapping.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ namespace llama::mapping::tree
{
}

LLAMA_FN_HOST_ACC_INLINE auto arrayDims() const
{
return arrayDimsSize;
}

LLAMA_FN_HOST_ACC_INLINE
auto blobSize(std::size_t const) const -> std::size_t
{
Expand Down
18 changes: 14 additions & 4 deletions tests/computedprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ namespace
{
}

auto arrayDims() const
{
return ArrayDims{};
}

template<std::size_t... RecordCoords>
static constexpr auto isComputed(llama::RecordCoord<RecordCoords...>)
{
Expand All @@ -142,14 +147,14 @@ namespace
TEST_CASE("fully_computed_mapping")
{
auto arrayDims = llama::ArrayDims<3>{10, 10, 10};
auto mapping = ComputedMapping<decltype(arrayDims), Triangle>{arrayDims};
auto mapping = ComputedMapping<decltype(arrayDims), int>{arrayDims};

auto view = llama::allocView(mapping);

using namespace tag;
CHECK(view(0u, 1u, 2u)(A{}, X{}) == 0);
CHECK(view(2u, 1u, 2u)(A{}, Y{}) == 4);
CHECK(view(2u, 5u, 2u)(A{}, Z{}) == 20);
CHECK(view(0u, 1u, 2u) == 0);
CHECK(view(2u, 1u, 2u) == 4);
CHECK(view(2u, 5u, 2u) == 20);
}

namespace
Expand All @@ -170,6 +175,11 @@ namespace
{
}

auto arrayDims() const
{
return arrayDimsSize;
}

using Word = std::uint64_t;

struct BoolRef
Expand Down
Loading

0 comments on commit 381a033

Please sign in to comment.