Skip to content

Commit

Permalink
extend sizeOf<> and offsetOf<> to support alignment and padding
Browse files Browse the repository at this point in the history
  • Loading branch information
bernhardmgruber committed Feb 26, 2021
1 parent 448f7b4 commit 8c6fe6c
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 39 deletions.
98 changes: 59 additions & 39 deletions include/llama/Core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,45 +126,6 @@ namespace llama
template <typename DatumElement>
using GetDatumElementType = boost::mp11::mp_second<DatumElement>;

template <typename T>
static constexpr auto sizeOf = sizeof(T);

/// The size a datum domain if it would be a normal struct.
template <typename... DatumElements>
static constexpr auto sizeOf<DatumStruct<DatumElements...>> = (sizeOf<GetDatumElementType<DatumElements>> + ...);

namespace internal
{
template <typename T>
constexpr auto offsetOfImpl(T*, DatumCoord<>)
{
return 0;
}

template <typename... DatumElements, std::size_t FirstCoord, std::size_t... Coords>
constexpr auto offsetOfImpl(DatumStruct<DatumElements...>*, DatumCoord<FirstCoord, Coords...>)
{
std::size_t acc = 0;
boost::mp11::mp_for_each<boost::mp11::mp_iota_c<FirstCoord>>([&](auto i) constexpr {
constexpr auto index = decltype(i)::value;
using Element = boost::mp11::mp_at_c<DatumStruct<DatumElements...>, index>;
acc += sizeOf<GetDatumElementType<Element>>;
});

using Element = boost::mp11::mp_at_c<DatumStruct<DatumElements...>, FirstCoord>;
acc += offsetOfImpl((GetDatumElementType<Element>*) nullptr, DatumCoord<Coords...>{});

return acc;
}
} // namespace internal

/// The byte offset of an element in a datum domain if it would be a normal
/// struct.
/// \tparam DatumDomain Datum domain tree.
/// \tparam DatumCoord Datum coordinate of an element indatum domain tree.
template <typename DatumDomain, typename DatumCoord>
inline constexpr std::size_t offsetOf = internal::offsetOfImpl((DatumDomain*) nullptr, DatumCoord{});

template <typename T>
inline constexpr auto isDatumStruct = false;

Expand Down Expand Up @@ -396,6 +357,65 @@ namespace llama
}
();

template <typename T, bool Align = false>
static constexpr auto sizeOf = sizeof(T);

/// The size a datum domain if it would be a normal struct.
template <typename... DatumElements, bool Align>
static constexpr auto sizeOf<DatumStruct<DatumElements...>, Align> = []() constexpr
{
if constexpr (Align)
return sizeof(boost::mp11::mp_rename<
boost::mp11::mp_reverse<FlattenDatumDomain<DatumStruct<DatumElements...>>>,
std::tuple>{});
else
return (sizeOf<GetDatumElementType<DatumElements>, Align> + ...);
}
();

namespace internal
{
template <bool Align, typename T>
constexpr auto offsetOfImpl(T*, DatumCoord<>)
{
return 0;
}

template <bool Align, typename... DatumElements, std::size_t FirstCoord, std::size_t... Coords>
constexpr auto offsetOfImpl(DatumStruct<DatumElements...>*, DatumCoord<FirstCoord, Coords...>)
{
std::size_t acc = 0;
boost::mp11::mp_for_each<boost::mp11::mp_take_c<DatumStruct<DatumElements...>, FirstCoord>>([&](
auto element) constexpr { acc += sizeOf<GetDatumElementType<decltype(element)>>; });

using Element = boost::mp11::mp_at_c<DatumStruct<DatumElements...>, FirstCoord>;
acc += offsetOfImpl<Align>((GetDatumElementType<Element>*) nullptr, DatumCoord<Coords...>{});

return acc;
}
} // namespace internal

/// The byte offset of an element in a datum domain if it would be a normal
/// struct.
/// \tparam DatumDomain Datum domain tree.
/// \tparam DatumCoord Datum coordinate of an element indatum domain tree.
template <typename DatumDomain, typename DatumCoord, bool Align = false>
inline constexpr std::size_t offsetOf = []() constexpr
{
if constexpr (Align)
{
constexpr auto i = flatDatumCoord<DatumDomain, DatumCoord>;
using Tuple = boost::mp11::mp_rename<boost::mp11::mp_reverse<FlattenDatumDomain<DatumDomain>>, std::tuple>;
constexpr auto n = boost::mp11::mp_size<Tuple>::value;
Tuple t;
return (std::intptr_t) std::addressof(std::get<n - 1 - i>(t)) - (std::intptr_t) std::addressof(t);
}
else
return internal::offsetOfImpl<Align>((DatumDomain*) nullptr, DatumCoord{});
}
();


template <typename S>
auto structName(S) -> std::string
{
Expand Down
44 changes: 44 additions & 0 deletions tests/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ TEST_CASE("sizeOf")
{
STATIC_REQUIRE(llama::sizeOf<Particle> == 52);
}

TEST_CASE("sizeOf.Align")
{
STATIC_REQUIRE(llama::sizeOf<Particle, true> == 56);
}

TEST_CASE("offsetOf")
{
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<>> == 0);
Expand All @@ -138,6 +144,44 @@ TEST_CASE("offsetOf")
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<4, 3>> == 51);
}

TEST_CASE("offsetOf.Align")
{
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<>, true> == 0);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<0>, true> == 0);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<0, 0>, true> == 0);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<0, 1>, true> == 8);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<0, 2>, true> == 16);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<1>, true> == 24);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<2>, true> == 28);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<3>, true> == 32);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<3, 0>, true> == 32);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<3, 1>, true> == 40);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<4>, true> == 48);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<4, 0>, true> == 48);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<4, 1>, true> == 49);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<4, 2>, true> == 50);
STATIC_REQUIRE(llama::offsetOf<Particle, llama::DatumCoord<4, 3>, true> == 51);
}

TEST_CASE("alignment")
{
using DD = llama::DS<llama::DE<tag::X, float>, llama::DE<tag::Y, double>, llama::DE<tag::Z, bool>, llama::DE<tag::Weight, std::uint16_t>>;

STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<>, false> == 0);
STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<0>, false> == 0);
STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<1>, false> == 4);
STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<2>, false> == 12);
STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<3>, false> == 13);
STATIC_REQUIRE(llama::sizeOf<DD, false> == 15);

STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<>, true> == 0);
STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<0>, true> == 0);
STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<1>, true> == 8); // aligned
STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<2>, true> == 16);
STATIC_REQUIRE(llama::offsetOf<DD, llama::DatumCoord<3>, true> == 18); // aligned
STATIC_REQUIRE(llama::sizeOf<DD, true> == 24);
}

TEST_CASE("GetCoordFromTags")
{
using namespace llama::literals;
Expand Down

0 comments on commit 8c6fe6c

Please sign in to comment.