Skip to content

Commit

Permalink
Add FixedMapRawView
Browse files Browse the repository at this point in the history
  • Loading branch information
Cyril Sharma committed Dec 6, 2024
1 parent a05959b commit d4b1c5f
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 38 deletions.
23 changes: 23 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,19 @@ cc_library(
copts = ["-std=c++20"],
)

cc_library(
name = "fixed_map_raw_view",
hdrs = ["include/fixed_containers/fixed_map_raw_view.hpp",],
includes = includes_config(),
strip_include_prefix = strip_include_prefix_config(),
deps = [
":fixed_red_black_tree",
":map_entry_raw_view",

],
copts = ["-std=c++20"],
)

cc_library(
name = "wyhash",
hdrs = ["include/fixed_containers/wyhash.hpp"],
Expand Down Expand Up @@ -409,6 +422,15 @@ cc_library(
]
)

cc_library(
name = "fixed_map_raw_view",
hdrs = ["include/fixed_containers/map_entry_raw_view.hpp",],
includes = includes_config(),
strip_include_prefix = strip_include_prefix_config(),
deps = [],
copts = ["-std=c++20"],
)

cc_library(
name = "fixed_unordered_map_raw_view",
hdrs = ["include/fixed_containers/fixed_unordered_map_raw_view.hpp"],
Expand All @@ -417,6 +439,7 @@ cc_library(
deps = [
":fixed_doubly_linked_list_raw_view",
":forward_iterator",
":fixed_map_raw_view"
],
copts = ["-std=c++20"],
)
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ if(BUILD_TESTS)
add_test_dependencies(fixed_list_test)
add_executable(fixed_map_test test/fixed_map_test.cpp)
add_test_dependencies(fixed_map_test)
add_executable(fixed_map_raw_view_test test/fixed_map_raw_view_test.cpp)
add_test_dependencies(fixed_map_raw_view_test)
add_executable(fixed_map_perf_test test/fixed_map_perf_test.cpp)
add_test_dependencies(fixed_map_perf_test)
add_executable(fixed_red_black_tree_test test/fixed_red_black_tree_test.cpp)
Expand Down
164 changes: 164 additions & 0 deletions include/fixed_containers/fixed_map_raw_view.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#pragma once

#include "fixed_containers/fixed_red_black_tree_nodes.hpp"
#include "fixed_containers/fixed_red_black_tree_types.hpp"
#include "fixed_containers/fixed_red_black_tree_view.hpp"
#include "fixed_containers/map_entry_raw_view.hpp"

#include <iterator>
#include <type_traits>

namespace fixed_containers
{

class FixedMapRawView {
using Compactness = fixed_red_black_tree_detail::RedBlackTreeNodeColorCompactness;
using StorageType = fixed_red_black_tree_detail::RedBlackTreeStorageType;
using NodeIndex = fixed_red_black_tree_detail::NodeIndex;

public:
class Iterator
{
private:
FixedRedBlackTreeRawView::Iterator base_iterator_;
std::ptrdiff_t value_offset_;

// We need this constructor to avoid default initializing the base_iterator_.
Iterator(MapEntryRawView map_entry,
const std::byte* ptr,
std::size_t value_size_bytes,
std::size_t max_size_bytes,
Compactness compactness,
StorageType storage_type,
bool end = false) noexcept :
base_iterator_(
ptr,
static_cast<size_t>(map_entry.value_offset()) + value_size_bytes,
max_size_bytes, compactness, storage_type, end
),
value_offset_(map_entry.value_offset()) {}

public:
// Define iterator traits
using value_type = const std::byte*;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator_category = std::forward_iterator_tag;

// Constructor that initializes the base iterator
Iterator(const std::byte* ptr,
std::size_t key_size_bytes,
std::size_t key_align_bytes,
std::size_t value_size_bytes,
std::size_t value_align_bytes,
std::size_t max_size_bytes,
Compactness compactness,
StorageType storage_type,
bool end = false) noexcept :
Iterator(
MapEntryRawView(ptr, key_size_bytes, key_align_bytes, value_size_bytes, value_align_bytes),
ptr, key_size_bytes, max_size_bytes,
compactness, storage_type, end) {}

Iterator() noexcept: base_iterator_(), value_offset_(0) {}
Iterator(const Iterator&) noexcept = default;
Iterator(Iterator&&) noexcept = default;
Iterator& operator=(const Iterator&) noexcept = default;
Iterator& operator=(Iterator&&) noexcept = default;

Iterator& operator++()
{
++base_iterator_;
return *this;
}

Iterator operator++(int) & noexcept
{
Iterator tmp = *this;
++base_iterator_;
return tmp;
}

const_reference operator*() const
{
return *base_iterator_;
}

const_pointer operator->() const
{
return base_iterator_.operator->();
}

bool operator==(const Iterator& other) const
{
return base_iterator_ == other.base_iterator_;
}

bool operator!=(const Iterator& other) const
{
return !(*this == other);
}

[[nodiscard]] const std::byte* key() const { return *base_iterator_; }

[[nodiscard]] const std::byte* value() const { return std::next(*base_iterator_, value_offset_); }

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

private:
const std::byte* tree_ptr_;
const std::size_t key_size_bytes_;
const std::size_t key_align_bytes_;
const std::size_t value_size_bytes_;
const std::size_t value_align_bytes_;
const std::size_t max_size_bytes_;
const Compactness compactness_;
const StorageType storage_type_;

public:
FixedMapRawView(const void* tree_ptr,
std::size_t key_size_bytes,
std::size_t key_align_bytes,
std::size_t value_size_bytes,
std::size_t value_align_bytes,
std::size_t max_size_bytes,
Compactness compactness,
StorageType storage_type):
tree_ptr_{reinterpret_cast<const std::byte*>(tree_ptr)}
, key_size_bytes_{key_size_bytes}
, key_align_bytes_{key_align_bytes}
, value_size_bytes_{value_size_bytes}
, value_align_bytes_{value_align_bytes}
, max_size_bytes_{max_size_bytes}
, compactness_{compactness}
, storage_type_{storage_type}
{
}

[[nodiscard]] Iterator begin() const
{
return Iterator(
tree_ptr_,
key_size_bytes_, key_align_bytes_, value_size_bytes_, value_align_bytes_,
max_size_bytes_, compactness_, storage_type_
);
}

[[nodiscard]] Iterator end() const
{
return Iterator(
tree_ptr_,
key_size_bytes_, key_align_bytes_, value_size_bytes_, value_align_bytes_,
max_size_bytes_, compactness_, storage_type_,
true
);
}

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

} // namespace fixed_containers
39 changes: 1 addition & 38 deletions include/fixed_containers/fixed_unordered_map_raw_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,12 @@

#include "fixed_containers/fixed_doubly_linked_list_raw_view.hpp"
#include "fixed_containers/forward_iterator.hpp"

#include "fixed_containers/map_entry_raw_view.hpp"
#include <cstddef>

namespace fixed_containers
{

class MapEntryRawView
{
private:
const std::byte* base_ptr_;
const std::ptrdiff_t value_offs_;

public:
static constexpr std::ptrdiff_t get_value_offs(std::size_t key_size,
std::size_t /*key_alignment*/,
std::size_t /*value_size*/,
std::size_t value_alignment)
{
std::size_t value_offs = key_size;
// align the value start addr to the correct alignment
if (value_offs % value_alignment != 0)
{
value_offs += value_alignment - value_offs % value_alignment;
}
return static_cast<std::ptrdiff_t>(value_offs);
}

public:
MapEntryRawView(const void* ptr,
std::size_t key_size,
std::size_t key_alignment,
std::size_t value_size,
std::size_t value_alignment)
: base_ptr_{reinterpret_cast<const std::byte*>(ptr)}
, value_offs_{get_value_offs(key_size, key_alignment, value_size, value_alignment)}
{
}

[[nodiscard]] const std::byte* key() const { return base_ptr_; }

[[nodiscard]] const std::byte* value() const { return std::next(base_ptr_, value_offs_); }
};

class FixedUnorderedMapRawView
{
private:
Expand Down
41 changes: 41 additions & 0 deletions include/fixed_containers/map_entry_raw_view.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <cstddef>
class MapEntryRawView
{
private:
const std::byte* base_ptr_;
const std::ptrdiff_t value_offs_;

public:
static constexpr std::ptrdiff_t get_value_offs(std::size_t key_size,
std::size_t /*key_alignment*/,
std::size_t /*value_size*/,
std::size_t value_alignment)
{
std::size_t value_offs = key_size;
// align the value start addr to the correct alignment
if (value_offs % value_alignment != 0)
{
value_offs += value_alignment - value_offs % value_alignment;
}
return static_cast<std::ptrdiff_t>(value_offs);
}

public:
MapEntryRawView(const void* ptr,
std::size_t key_size,
std::size_t key_alignment,
std::size_t value_size,
std::size_t value_alignment)
: base_ptr_{reinterpret_cast<const std::byte*>(ptr)}
, value_offs_{get_value_offs(key_size, key_alignment, value_size, value_alignment)}
{
}

[[nodiscard]] const std::byte* key() const { return base_ptr_; }

[[nodiscard]] const std::byte* value() const { return std::next(base_ptr_, value_offs_); }

[[nodiscard]] std::ptrdiff_t value_offset() const { return value_offs_; }


};
87 changes: 87 additions & 0 deletions test/fixed_map_raw_view_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "fixed_containers/fixed_map_raw_view.hpp"

#include "mock_testing_types.hpp"
#include "test_utilities_common.hpp"
#include "fixed_containers/fixed_map.hpp"
#include <gtest/gtest.h>

#include <array>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <ranges>

namespace fixed_containers
{
namespace
{

static_assert(std::forward_iterator<FixedMapRawView::Iterator>);
static_assert(std::ranges::forward_range<FixedMapRawView>);

template <typename T>
T get_from_ptr(const std::byte* ptr)
{
return *reinterpret_cast<const T*>(ptr);
}

template <typename Key, typename Value>
void test_and_increment(auto& map_it, auto& view_it)
{
EXPECT_EQ(map_it->first, get_from_ptr<Key>(view_it.key()));
EXPECT_EQ(map_it->second, get_from_ptr<Value>(view_it.value()));
++map_it;
++view_it;
}

template <typename Map>
FixedMapRawView get_view_of_map(const Map& map)
{
return FixedMapRawView(&map,
sizeof(typename Map::key_type),
alignof(typename Map::key_type),
sizeof(typename Map::mapped_type),
alignof(typename Map::mapped_type),
map.max_size(),
// Ideally we'd grab these from the map too.
fixed_red_black_tree_detail::RedBlackTreeNodeColorCompactness::EMBEDDED_COLOR,
fixed_red_black_tree_detail::RedBlackTreeStorageType::FIXED_INDEX_POOL);
}


TEST(FixedMapRawView, IntIntMap)
{
const auto map = make_fixed_map<int, int>({{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0}});
const FixedMapRawView view = get_view_of_map(map);
EXPECT_EQ(map.size(), view.size());
auto map_it = map.begin();
FixedMapRawView::Iterator view_it = view.begin();
for (std::size_t i = 0; i < map.size(); i++)
{
test_and_increment<int, int>(map_it, view_it);
}
EXPECT_EQ(map_it, map.end());
EXPECT_EQ(view_it, view.end());
}

TEST(FixedMapRawView, CharCharMap)
{
FixedMap<char, char, 10> map{};
map['a'] = 'A';
map['b'] = 'B';
map['c'] = 'C';
map['z'] = 'Z';

const FixedMapRawView view = get_view_of_map(map);
EXPECT_EQ(map.size(), view.size());
auto map_it = map.begin();
auto view_it = view.begin();
for (std::size_t i = 0; i < map.size(); i++)
{
test_and_increment<char, char>(map_it, view_it);
}
EXPECT_EQ(map_it, map.end());
EXPECT_EQ(view_it, view.end());
}
}
} // namespace fixed_containers

0 comments on commit d4b1c5f

Please sign in to comment.