Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a concept for View #759

Merged
merged 2 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions include/llama/Concepts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,62 @@ namespace llama
ba(std::integral_constant<std::size_t, 16>{}, size)
} -> Blob;
};

template<typename V>
concept AnyView = requires(V v, const V cv) {
typename V::Mapping;
typename V::BlobType;
typename V::ArrayExtents;
typename V::ArrayIndex;
typename V::RecordDim;
typename V::Accessor;

typename V::iterator;
typename V::const_iterator;

{
v.mapping()
} -> std::same_as<typename V::Mapping&>;

{
cv.mapping()
} -> std::same_as<const typename V::Mapping&>;

{
v.accessor()
} -> std::same_as<typename V::Accessor&>;

{
cv.accessor()
} -> std::same_as<const typename V::Accessor&>;

{
cv.extents()
} -> std::same_as<typename V::ArrayExtents>;

{
v.begin()
} -> std::same_as<typename V::iterator>;

{
cv.begin()
} -> std::same_as<typename V::const_iterator>;

{
v.end()
} -> std::same_as<typename V::iterator>;

{
cv.end()
} -> std::same_as<typename V::const_iterator>;

{
v.blobs()
} -> std::same_as<Array<typename V::BlobType, V::Mapping::blobCount>&>;
{
cv.blobs()
} -> std::same_as<const Array<typename V::BlobType, V::Mapping::blobCount>&>;
};
#endif

namespace internal
Expand Down
92 changes: 74 additions & 18 deletions include/llama/View.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,10 @@ namespace llama
}
}

/// 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.
/// \tparam TBlobType The storage type used by the view holding memory.
/// \tparam TAccessor The accessor to use when an access is made through this view.
/// 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. \tparam TBlobType The storage type used by the view holding memory. \tparam
/// TAccessor The accessor to use when an access is made through this view.
#ifdef __cpp_lib_concepts
template<typename TMapping, Blob TBlobType, typename TAccessor = accessor::Default>
#else
Expand All @@ -391,15 +390,19 @@ namespace llama
using Accessor = TAccessor;
using iterator = Iterator<View>;
using const_iterator = Iterator<const View>;

private:
using size_type = typename ArrayExtents::value_type;

public:
static_assert(
std::is_same_v<Mapping, std::decay_t<Mapping>>,
"Mapping must not be const qualified or a reference. Are you using decltype(...) as View template "
"argument?");
static_assert(
std::is_same_v<ArrayExtents, std::decay_t<ArrayExtents>>,
"Mapping::ArrayExtents must not be const qualified or a reference. Are you using decltype(...) as mapping "
"Mapping::ArrayExtents must not be const qualified or a reference. Are you using decltype(...) as "
"mapping "
"template argument?");

/// Performs default initialization of the blob array.
Expand Down Expand Up @@ -429,11 +432,6 @@ namespace llama
return static_cast<const Mapping&>(*this);
}

LLAMA_FN_HOST_ACC_INLINE auto extents() const -> ArrayExtents
{
return mapping().extents();
}

LLAMA_FN_HOST_ACC_INLINE auto accessor() -> Accessor&
{
return static_cast<Accessor&>(*this);
Expand All @@ -444,6 +442,11 @@ namespace llama
return static_cast<const Accessor&>(*this);
}

LLAMA_FN_HOST_ACC_INLINE auto extents() const -> ArrayExtents
{
return mapping().extents();
}

#if !(defined(_MSC_VER) && defined(__NVCC__))
template<typename V>
auto operator()(llama::ArrayIndex<V, ArrayIndex::rank>) const
Expand Down Expand Up @@ -577,11 +580,18 @@ namespace llama
Array<BlobType, Mapping::blobCount> m_blobs;
};

#ifdef __cpp_lib_concepts
template<typename View>
inline constexpr auto isView = AnyView<View>;
#else
template<typename View>
inline constexpr auto isView = false;

// this definition does neither capture SubView nor user defined view's, but the issue resolves itself with a C++20
// upgrade.
template<typename Mapping, typename BlobType, typename Accessor>
inline constexpr auto isView<View<Mapping, BlobType, Accessor>> = true;
#endif

namespace internal
{
Expand Down Expand Up @@ -618,8 +628,8 @@ namespace llama
}
} // namespace internal

/// Applies the given transformation to the blobs of a view and creates a new view with the transformed blobs and
/// the same mapping and accessor as the old view.
/// Applies the given transformation to the blobs of a view and creates a new view with the transformed blobs
/// and the same mapping and accessor as the old view.
template<typename ViewFwd, typename TransformBlobFunc, typename = std::enable_if_t<isView<std::decay_t<ViewFwd>>>>
LLAMA_FN_HOST_ACC_INLINE auto transformBlobs(ViewFwd&& view, const TransformBlobFunc& transformBlob)
{
Expand Down Expand Up @@ -695,12 +705,20 @@ namespace llama
{
using StoredParentView = TStoredParentView;
using ParentView = std::remove_const_t<std::remove_reference_t<StoredParentView>>; ///< type of the parent view
using Mapping = typename ParentView::Mapping; ///< mapping of the parent view
using ArrayExtents = typename Mapping::ArrayExtents; ///< array extents of the parent view
using ArrayIndex = typename ArrayExtents::Index; ///< array index of the parent view

using Mapping = typename ParentView::Mapping;
using ArrayExtents = typename ParentView::ArrayExtents;
using ArrayIndex = typename ParentView::ArrayIndex;
using BlobType = typename ParentView::BlobType;
using RecordDim = typename ParentView::RecordDim;
using Accessor = typename ParentView::Accessor;
using iterator = typename ParentView::iterator;
using const_iterator = typename ParentView::const_iterator;

private:
using size_type = typename ArrayExtents::value_type;

public:
/// Creates a SubView given a parent \ref View and offset.
template<typename StoredParentViewFwd>
LLAMA_FN_HOST_ACC_INLINE SubView(StoredParentViewFwd&& parentView, ArrayIndex offset)
Expand All @@ -709,6 +727,31 @@ namespace llama
{
}

LLAMA_FN_HOST_ACC_INLINE auto mapping() -> Mapping&
{
return parentView.mapping();
}

LLAMA_FN_HOST_ACC_INLINE auto mapping() const -> const Mapping&
{
return parentView.mapping();
}

LLAMA_FN_HOST_ACC_INLINE auto accessor() -> Accessor&
{
return parentView.accessor();
}

LLAMA_FN_HOST_ACC_INLINE auto accessor() const -> const Accessor&
{
return parentView.accessor();
}

LLAMA_FN_HOST_ACC_INLINE auto extents() const -> ArrayExtents
{
return parentView.extents();
}

/// Same as \ref View::operator()(ArrayIndex), but shifted by the offset of this \ref SubView.
LLAMA_FN_HOST_ACC_INLINE auto operator()(ArrayIndex ai) const -> decltype(auto)
{
Expand Down Expand Up @@ -759,9 +802,22 @@ namespace llama
return parentView(ArrayIndex{} + offset, rc);
}

// TODO(bgruber): implement iterators. Those would be transform iterators on top of the parent view's
// iterators, applying the offset on access.

LLAMA_FN_HOST_ACC_INLINE auto blobs() -> Array<BlobType, Mapping::blobCount>&
{
return parentView.blobs();
}

LLAMA_FN_HOST_ACC_INLINE auto blobs() const -> const Array<BlobType, Mapping::blobCount>&
{
return parentView.blobs();
}

StoredParentView parentView;
const ArrayIndex offset; ///< offset by which this view's \ref ArrayIndex indices are shifted when passed to
///< the parent view.
const ArrayIndex offset; ///< offset by which this view's \ref ArrayIndex indices are shifted when passed
///< to the parent view.
};

/// SubView vview(view); will store a reference to view.
Expand Down
26 changes: 25 additions & 1 deletion tests/view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ namespace tag

using RecordDimJustInt = llama::Record<llama::Field<tag::Value, int>>;

TEST_CASE("view.concept")
{
#ifdef __cpp_lib_concepts
using ArrayExtents = llama::ArrayExtentsDynamic<std::size_t, 2>;
using View = llama::View<llama::mapping::AlignedAoS<ArrayExtents, RecordDimJustInt>, std::byte*>;
STATIC_REQUIRE(llama::AnyView<View>);
// TODO(bgruber): finish SubView iterators and reenable this check
// using SubView = llama::SubView<View>;
// STATIC_REQUIRE(llama::AnyView<SubView>);
#endif
}

TEST_CASE("view.default-ctor")
{
using ArrayExtents = llama::ArrayExtentsDynamic<std::size_t, 2>;
Expand All @@ -31,7 +43,19 @@ TEST_CASE("view.default-ctor")
View<llama::mapping::tree::Mapping<ArrayExtents, RecordDimJustInt, llama::Tuple<>>, std::byte*>
view7{};
}
//

TEST_CASE("view.observers")
{
using Mapping = llama::mapping::SoA<llama::ArrayExtentsDynamic<std::size_t, 1>, Particle>;
using Accessor = llama::accessor::Restrict;
auto view = llama::allocView(Mapping{{16}}, llama::bloballoc::SharedPtr{}, Accessor{});

STATIC_REQUIRE(std::is_same_v<decltype(view.mapping()), Mapping&>);
STATIC_REQUIRE(std::is_same_v<decltype(view.accessor()), Accessor&>);
STATIC_REQUIRE(std::is_same_v<decltype(view.blobs()), llama::Array<typename decltype(view)::BlobType, 11>&>);
CHECK(view.extents() == llama::ArrayExtentsDynamic<std::size_t, 1>{16});
}

// TEST_CASE("view.trivial")
//{
// using ArrayExtents = llama::ArrayExtents<std::size_t, 2, llama::dyn>;
Expand Down