-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
eb39217
commit ea88f2f
Showing
4 changed files
with
242 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
#pragma once | ||
|
||
#include "fixed_containers/fixed_deque.hpp" | ||
#include "fixed_containers/forward_iterator.hpp" | ||
#include "fixed_containers/integer_range.hpp" | ||
|
||
#include <cstddef> | ||
|
||
namespace fixed_containers | ||
{ | ||
|
||
template <typename IndexType = std::size_t> | ||
class FixedDequeRawView | ||
{ | ||
public: | ||
class ReferenceProvider | ||
{ | ||
friend class FixedDequeRawView; | ||
|
||
private: | ||
const FixedDequeRawView* parent_; | ||
|
||
IndexType current_idx_; | ||
|
||
explicit constexpr ReferenceProvider(const FixedDequeRawView* parent, | ||
const IndexType idx) noexcept | ||
: parent_{parent} | ||
, current_idx_{idx} | ||
{ | ||
} | ||
|
||
public: | ||
constexpr ReferenceProvider() noexcept | ||
: parent_{nullptr} | ||
, current_idx_{0} | ||
{ | ||
} | ||
|
||
constexpr void advance() noexcept { ++current_idx_; } | ||
|
||
[[nodiscard]] constexpr const std::byte* get() const noexcept | ||
{ | ||
return parent_->value_at(current_idx_); | ||
} | ||
|
||
constexpr bool operator==(const ReferenceProvider& other) const noexcept = default; | ||
}; | ||
|
||
private: | ||
const std::byte* data_ptr_; | ||
std::size_t elem_size_bytes_; | ||
std::size_t elem_align_bytes_; | ||
std::size_t max_elem_count_; | ||
|
||
public: | ||
using Iterator = | ||
ForwardIterator<ReferenceProvider, ReferenceProvider, IteratorConstness::CONSTANT_ITERATOR>; | ||
using iterator = Iterator; | ||
using const_iterator = iterator; | ||
|
||
FixedDequeRawView(const void* data_ptr, | ||
std::size_t elem_size_bytes, | ||
std::size_t elem_align_bytes, | ||
std::size_t max_elem_count) | ||
: data_ptr_{static_cast<const std::byte*>(data_ptr)} | ||
, elem_size_bytes_{elem_size_bytes} | ||
, elem_align_bytes_{elem_align_bytes} | ||
, max_elem_count_{max_elem_count} | ||
{ | ||
} | ||
|
||
[[nodiscard]] Iterator begin() const { return Iterator{ReferenceProvider{this, 0}}; } | ||
|
||
[[nodiscard]] Iterator end() const | ||
{ | ||
auto stats = start_and_distance(); | ||
return Iterator{ReferenceProvider{this, stats.distance}}; | ||
} | ||
|
||
[[nodiscard]] StartingIntegerAndDistance start_and_distance() const | ||
{ | ||
// The bookkeeping fields are stored after the data in fixed_deque | ||
return *reinterpret_cast<const StartingIntegerAndDistance*>( | ||
std::next(data_ptr_, value_storage_size())); | ||
} | ||
|
||
[[nodiscard]] size_t size() const { return start_and_distance().distance; } | ||
|
||
public: | ||
[[nodiscard]] constexpr const std::byte* value_at(IndexType index) const noexcept | ||
{ | ||
auto stats = start_and_distance(); | ||
auto starting_offset = | ||
fixed_containers::fixed_deque_detail::FIXED_DEQUE_STARTING_OFFSET % max_elem_count_; | ||
auto real_index = | ||
(stats.start + index - starting_offset + max_elem_count_) % max_elem_count_; | ||
return std::next(value_storage_start(), | ||
static_cast<std::ptrdiff_t>(elem_size_bytes_ * real_index)); | ||
} | ||
|
||
[[nodiscard]] constexpr const std::byte* value_storage_start() const noexcept | ||
{ | ||
return data_ptr_; | ||
} | ||
|
||
[[nodiscard]] constexpr std::ptrdiff_t value_storage_size() const noexcept | ||
{ | ||
auto member_alignment = alignof(StartingIntegerAndDistance); | ||
std::size_t raw_size = max_elem_count_ * elem_size_bytes_; | ||
if (raw_size % member_alignment != 0) | ||
{ | ||
raw_size += member_alignment - (raw_size % member_alignment); | ||
} | ||
return static_cast<std::ptrdiff_t>(raw_size); | ||
} | ||
}; | ||
} // namespace fixed_containers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#include "fixed_containers/fixed_deque_raw_view.hpp" | ||
|
||
#include "mock_testing_types.hpp" | ||
|
||
#include "fixed_containers/fixed_deque.hpp" | ||
|
||
#include <gtest/gtest.h> | ||
|
||
#include <cstddef> | ||
|
||
namespace fixed_containers | ||
{ | ||
namespace | ||
{ | ||
|
||
template <typename T> | ||
T get_from_ptr(const std::byte* ptr) | ||
{ | ||
return *reinterpret_cast<const T*>(ptr); | ||
} | ||
|
||
template <typename Elem> | ||
void test_and_increment(auto& dq_it, auto& view_it) | ||
{ | ||
EXPECT_EQ(*dq_it, get_from_ptr<Elem>(*view_it)); | ||
++dq_it; | ||
++view_it; | ||
} | ||
} // namespace | ||
|
||
TEST(FixedDequeRawView, IntDeque) | ||
{ | ||
auto deque = make_fixed_deque<int>({1, 2, 3, 5, 8}); | ||
EXPECT_EQ(sizeof(deque), 40); | ||
const FixedDequeRawView view{&deque, sizeof(int), alignof(int), deque.max_size()}; | ||
auto stats = view.start_and_distance(); | ||
EXPECT_EQ(stats.start, deque.IMPLEMENTATION_DETAIL_DO_NOT_USE_starting_index_and_size_.start); | ||
EXPECT_EQ(deque.size(), view.size()); | ||
EXPECT_EQ(reinterpret_cast<char*>(&deque), | ||
reinterpret_cast<char*>(&deque.IMPLEMENTATION_DETAIL_DO_NOT_USE_array_)); | ||
char* member = | ||
reinterpret_cast<char*>(&deque.IMPLEMENTATION_DETAIL_DO_NOT_USE_starting_index_and_size_); | ||
char* array = reinterpret_cast<char*>(&deque.IMPLEMENTATION_DETAIL_DO_NOT_USE_array_); | ||
EXPECT_EQ(member - array, view.value_storage_size()); | ||
auto dq_it = deque.begin(); | ||
auto view_it = view.begin(); | ||
for (std::size_t i = 0; i < deque.size(); i++) | ||
{ | ||
test_and_increment<int>(dq_it, view_it); | ||
} | ||
EXPECT_EQ(dq_it, deque.end()); | ||
EXPECT_EQ(view_it, view.end()); | ||
} | ||
|
||
TEST(FixedDequeRawView, StructDeque) | ||
{ | ||
FixedDeque<MockAligned64, 10> deque{}; | ||
deque.push_back({1}); | ||
deque.push_back({2}); | ||
deque.push_back({3}); | ||
deque.push_back({4}); | ||
deque.push_front({5}); | ||
deque.push_front({6}); | ||
deque.push_front({7}); | ||
deque.push_front({8}); | ||
const FixedDequeRawView view{ | ||
&deque, sizeof(MockAligned64), alignof(MockAligned64), deque.max_size()}; | ||
auto stats = view.start_and_distance(); | ||
EXPECT_EQ(stats.start, deque.IMPLEMENTATION_DETAIL_DO_NOT_USE_starting_index_and_size_.start); | ||
EXPECT_EQ(deque.size(), view.size()); | ||
|
||
// Ensure data pointer starts at the beginning of the struct. | ||
EXPECT_EQ(reinterpret_cast<char*>(&deque), | ||
reinterpret_cast<char*>(&deque.IMPLEMENTATION_DETAIL_DO_NOT_USE_array_)); | ||
|
||
// The deque is a struct with two members, an array and another bookkeeping struct. | ||
// value_storage_size() is needed purely to compute where this bookkeeping struct is. | ||
// This is potentially error prone as there may be padding in between the data portion and the | ||
// bookkeeping struct. | ||
char* member = | ||
reinterpret_cast<char*>(&deque.IMPLEMENTATION_DETAIL_DO_NOT_USE_starting_index_and_size_); | ||
char* array = reinterpret_cast<char*>(&deque.IMPLEMENTATION_DETAIL_DO_NOT_USE_array_); | ||
EXPECT_EQ(member - array, view.value_storage_size()); | ||
|
||
auto dq_it = deque.begin(); | ||
auto view_it = view.begin(); | ||
for (std::size_t i = 0; i < deque.size(); i++) | ||
{ | ||
test_and_increment<int>(dq_it, view_it); | ||
} | ||
EXPECT_EQ(dq_it, deque.end()); | ||
EXPECT_EQ(view_it, view.end()); | ||
} | ||
|
||
} // namespace fixed_containers |