Skip to content

Commit

Permalink
Introduce ContiguousRangeSubStructView
Browse files Browse the repository at this point in the history
  • Loading branch information
alexkaratarakis committed Jul 6, 2024
1 parent 3a7f21c commit 828a6d8
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 0 deletions.
4 changes: 4 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -778,9 +778,12 @@ cc_library(
hdrs = ["include/fixed_containers/sub_struct_view.hpp"],
includes = ["include"],
deps = [
":assert_or_abort",
":fixed_map",
":iterator_utils",
":memory",
":out",
":random_access_iterator",
":reflection",
],
copts = ["-std=c++20"],
Expand Down Expand Up @@ -1529,6 +1532,7 @@ cc_test(
name = "sub_struct_view_test",
srcs = ["test/sub_struct_view_test.cpp"],
deps = [
":fixed_vector",
":out",
":sub_struct_view",
"@com_google_googletest//:gtest",
Expand Down
146 changes: 146 additions & 0 deletions include/fixed_containers/sub_struct_view.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#pragma once

#include "fixed_containers/assert_or_abort.hpp"
#include "fixed_containers/fixed_map.hpp"
#include "fixed_containers/iterator_utils.hpp"
#include "fixed_containers/memory.hpp"
#include "fixed_containers/out.hpp"
#include "fixed_containers/random_access_iterator.hpp"
#include "fixed_containers/reflection.hpp"

#include <cstddef>
Expand Down Expand Up @@ -80,4 +83,147 @@ void sub_struct_view_of(Super& super_struct,
sub_struct_field_properties);
}

template <typename SubStruct>
class ContiguousRangeSubStructView
{
struct AccessingInfo
{
FieldPropertiesMap<SubStruct> sub_struct_field_properties{};
FieldPropertiesMap<SubStruct> super_struct_field_properties{};
std::byte* base_array_super_struct_ptr{};
std::size_t stride{};
std::size_t size{};
};

static SubStruct create_view_at_offset(const AccessingInfo& accessing_info, const std::size_t i)
{
assert_or_abort(i < accessing_info.size);
SubStruct instance{};
std::byte* base_of_ith_entry =
std::next(accessing_info.base_array_super_struct_ptr,
static_cast<std::ptrdiff_t>(i * accessing_info.stride));
sub_struct_view::sub_struct_view_of(base_of_ith_entry,
accessing_info.super_struct_field_properties,
memory::addressof_as_mutable_byte_ptr(instance),
accessing_info.sub_struct_field_properties);
return instance;
}

using ReferenceType = SubStruct;

class ReferenceProvider
{
private:
const AccessingInfo* accessing_info_;
std::size_t current_index_;

public:
constexpr ReferenceProvider() noexcept
: ReferenceProvider{nullptr, 0}
{
}

constexpr ReferenceProvider(const AccessingInfo& accessing_info,
const std::size_t& current_index) noexcept
: accessing_info_{&accessing_info}
, current_index_{current_index}
{
}

constexpr void advance(const std::size_t n) noexcept { current_index_ += n; }
constexpr void recede(const std::size_t n) noexcept { current_index_ -= n; }

[[nodiscard]] constexpr ReferenceType get() const noexcept
{
return create_view_at_offset(*accessing_info_, current_index_);
}

constexpr bool operator==(const ReferenceProvider& other) const noexcept
{
assert_or_abort(accessing_info_ == other.accessing_info_);
return current_index_ == other.current_index_;
}
constexpr auto operator<=>(const ReferenceProvider& other) const noexcept
{
assert_or_abort(accessing_info_ == other.accessing_info_);
return current_index_ <=> other.current_index_;
}

constexpr std::ptrdiff_t operator-(const ReferenceProvider& other) const noexcept
{
assert_or_abort(accessing_info_ == other.accessing_info_);
return static_cast<std::ptrdiff_t>(current_index_ - other.current_index_);
}
};

using IteratorType = RandomAccessIterator<ReferenceProvider,
ReferenceProvider,
IteratorConstness::CONSTANT_ITERATOR,
IteratorDirection::FORWARD>;

public:
using const_reference = ReferenceType;
using const_iterator = IteratorType;

private:
AccessingInfo accessing_info_;

public:
ContiguousRangeSubStructView()
: accessing_info_{}
{
}

template <typename SuperStructContainer>
ContiguousRangeSubStructView(SuperStructContainer& super_struct_container)
: accessing_info_{
.sub_struct_field_properties = extract_field_properties_of<SubStruct>(),
.super_struct_field_properties = {},
.base_array_super_struct_ptr =
memory::addressof_as_mutable_byte_ptr(*super_struct_container.data()),
.stride = {},
.size = super_struct_container.size(),
}

{
using SuperStruct = typename SuperStructContainer::value_type;
auto super_struct_field_properties_all = extract_field_properties_of<SuperStruct>();
for (const auto& [name, _] : accessing_info_.sub_struct_field_properties)
{
accessing_info_.super_struct_field_properties[name] =
super_struct_field_properties_all.at(name);
}

accessing_info_.stride = sizeof(SuperStruct);
}

[[nodiscard]] const_reference at(const std::size_t i) const
{
return create_view_at_offset(accessing_info_, i);
}

[[nodiscard]] std::size_t size() const { return accessing_info_.size; }

constexpr const_iterator begin() noexcept { return cbegin(); }
[[nodiscard]] constexpr const_iterator begin() const noexcept { return cbegin(); }
[[nodiscard]] constexpr const_iterator cbegin() const noexcept
{
return create_const_iterator(0);
}

constexpr const_iterator end() noexcept { return cend(); }
[[nodiscard]] constexpr const_iterator end() const noexcept { return cend(); }
[[nodiscard]] constexpr const_iterator cend() const noexcept
{
return create_const_iterator(accessing_info_.size);
}

private:
[[nodiscard]] constexpr const_iterator create_const_iterator(
const std::size_t offset_from_start) const noexcept
{
return const_iterator{ReferenceProvider{accessing_info_, offset_from_start}};
}
};

} // namespace fixed_containers::sub_struct_view
123 changes: 123 additions & 0 deletions test/sub_struct_view_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

#include "fixed_containers/sub_struct_view.hpp"

#include "fixed_containers/fixed_vector.hpp"
#include "fixed_containers/out.hpp"

#include <gtest/gtest.h>

#include <array>
#include <cstddef>

namespace fixed_containers::sub_struct_view
{
namespace
Expand Down Expand Up @@ -75,6 +79,125 @@ TEST(SubStructView, SubStructViewOf)
ASSERT_EQ(flat_sub_struct_1.retain1, &flat_super_struct_1.retain1);
ASSERT_EQ(flat_sub_struct_1.retain2, &flat_super_struct_1.retain2);
}

namespace
{
struct PointXYZ
{
double x{};
double y{};
double z{};
};

struct FlatSuperStruct2
{
int ignore1{};
std::array<PointXYZ, 3> retain_array_1{};
FixedVector<PointXYZ, 3> retain_vec_2{};
float ignore2{};
};

struct PointXZ
{
const double* z{};
const double* x{};
};

struct FlatSubStruct2
{
ContiguousRangeSubStructView<PointXZ> retain_array_1{};
ContiguousRangeSubStructView<PointXZ> retain_vec_2{};
};

} // namespace

TEST(ContiguousRangeSubStructView, OperatorAt)
{
FlatSuperStruct2 flat_super_struct_2{};
FlatSubStruct2 flat_sub_struct_2{};
flat_super_struct_2.retain_vec_2.resize(3);

flat_sub_struct_2.retain_array_1 = flat_super_struct_2.retain_array_1;
flat_sub_struct_2.retain_vec_2 = flat_super_struct_2.retain_vec_2;

{
ASSERT_EQ(3, flat_sub_struct_2.retain_array_1.size());

ASSERT_EQ(flat_sub_struct_2.retain_array_1.at(0).x,
&flat_super_struct_2.retain_array_1.at(0).x);
ASSERT_EQ(flat_sub_struct_2.retain_array_1.at(0).z,
&flat_super_struct_2.retain_array_1.at(0).z);

ASSERT_EQ(flat_sub_struct_2.retain_array_1.at(1).x,
&flat_super_struct_2.retain_array_1.at(1).x);
ASSERT_EQ(flat_sub_struct_2.retain_array_1.at(1).z,
&flat_super_struct_2.retain_array_1.at(1).z);

ASSERT_EQ(flat_sub_struct_2.retain_array_1.at(2).x,
&flat_super_struct_2.retain_array_1.at(2).x);
ASSERT_EQ(flat_sub_struct_2.retain_array_1.at(2).z,
&flat_super_struct_2.retain_array_1.at(2).z);

ASSERT_DEATH((void)flat_sub_struct_2.retain_array_1.at(3), "");
}

{
ASSERT_EQ(3, flat_sub_struct_2.retain_vec_2.size());

ASSERT_EQ(flat_sub_struct_2.retain_vec_2.at(0).x,
&flat_super_struct_2.retain_vec_2.at(0).x);
ASSERT_EQ(flat_sub_struct_2.retain_vec_2.at(0).z,
&flat_super_struct_2.retain_vec_2.at(0).z);

ASSERT_EQ(flat_sub_struct_2.retain_vec_2.at(1).x,
&flat_super_struct_2.retain_vec_2.at(1).x);
ASSERT_EQ(flat_sub_struct_2.retain_vec_2.at(1).z,
&flat_super_struct_2.retain_vec_2.at(1).z);

ASSERT_EQ(flat_sub_struct_2.retain_vec_2.at(2).x,
&flat_super_struct_2.retain_vec_2.at(2).x);
ASSERT_EQ(flat_sub_struct_2.retain_vec_2.at(2).z,
&flat_super_struct_2.retain_vec_2.at(2).z);

ASSERT_DEATH((void)flat_sub_struct_2.retain_vec_2.at(3), "");
}
}

TEST(ContiguousRangeSubStructView, Iteration)
{
FlatSuperStruct2 flat_super_struct_2{};
FlatSubStruct2 flat_sub_struct_2{};
flat_super_struct_2.retain_vec_2.resize(3);

flat_sub_struct_2.retain_array_1 = flat_super_struct_2.retain_array_1;
flat_sub_struct_2.retain_vec_2 = flat_super_struct_2.retain_vec_2;

{
ASSERT_EQ(3, flat_sub_struct_2.retain_array_1.size());

std::size_t counter = 0;
for (auto&& sub_struct : flat_sub_struct_2.retain_array_1)
{
ASSERT_EQ(sub_struct.x, &flat_super_struct_2.retain_array_1.at(counter).x);
ASSERT_EQ(sub_struct.z, &flat_super_struct_2.retain_array_1.at(counter).z);
counter++;
}
ASSERT_EQ(3, counter);
}
{
ASSERT_EQ(3, flat_sub_struct_2.retain_vec_2.size());

std::size_t counter = 0;
for (auto&& sub_struct : flat_sub_struct_2.retain_vec_2)
{
ASSERT_EQ(sub_struct.x, &flat_super_struct_2.retain_vec_2.at(counter).x);
ASSERT_EQ(sub_struct.z, &flat_super_struct_2.retain_vec_2.at(counter).z);
counter++;
}
ASSERT_EQ(3, counter);
}
}

} // namespace fixed_containers::sub_struct_view

#endif

0 comments on commit 828a6d8

Please sign in to comment.