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 Shared Memory for incoming data. #350

Merged
merged 5 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_executable(quicr_benchmark
time_queue.cpp
uintvar.cpp
hash.cpp
shared_memory.cpp
)

target_link_libraries(quicr_benchmark PRIVATE quicr benchmark::benchmark_main)
Expand Down
32 changes: 32 additions & 0 deletions benchmark/shared_memory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: Copyright (c) 2024 Cisco Systems
// SPDX-License-Identifier: BSD-2-Clause

#include <quicr/shared_memory.h>
#include <quicr/detail/uintvar.h>

#include <benchmark/benchmark.h>

static void
SharedMemory_Construct(benchmark::State& state)
{
for ([[maybe_unused]] const auto& _ : state) {
auto buffer = quicr::SharedMemory::Create();
benchmark::DoNotOptimize(buffer);
benchmark::ClobberMemory();
}
}

static void
SharedMemory_Push(benchmark::State& state)
{
auto buffer = quicr::SharedMemory::Create();
uint64_t value = 0;
auto bytes = quicr::AsBytes(value);

for ([[maybe_unused]] const auto& _ : state) {
buffer->Push(bytes);
}
}

BENCHMARK(SharedMemory_Construct);
BENCHMARK(SharedMemory_Push);
108 changes: 108 additions & 0 deletions include/quicr/shared_memory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-FileCopyrightText: Copyright (c) 2024 Cisco Systems
// SPDX-License-Identifier: BSD-2-Clause

#pragma once

#include "detail/span.h"

#include <cstdint>
#include <memory>
#include <optional>
#include <vector>

namespace quicr {
template<class T, std::enable_if_t<std::is_standard_layout_v<T>, bool> = true>
inline Span<const uint8_t> AsBytes(const T& value)
{
return Span{ reinterpret_cast<const std::uint8_t*>(&value), sizeof(T) };
}

class SharedMemory
{
template<class T>
struct IsRange
{
static constexpr bool kValue = noexcept(std::declval<T>().begin()) && noexcept(std::declval<T>().end());
};

template<class It, class SpanIt>
class IteratorImpl
{
public:
constexpr IteratorImpl() noexcept = default;
constexpr IteratorImpl(const It& it, const It& end_it) noexcept
: it_(it)
, end_it_(end_it)
, span_it_(it == end_it_ ? std::nullopt : std::optional<SpanIt>{ (*it_)->begin() })
{
}

constexpr IteratorImpl(const IteratorImpl&) = default;

IteratorImpl& operator=(const IteratorImpl&) = default;

constexpr const std::uint8_t& operator*() const noexcept { return **span_it_; }
constexpr const std::uint8_t* operator->() const noexcept { return span_it_->operator->(); }

constexpr IteratorImpl& operator++() noexcept
{
if (++*span_it_ == (*it_)->end()) {
span_it_ = ++it_ == end_it_ ? std::nullopt : std::optional<SpanIt>{ (*it_)->begin() };
}

return *this;
}

friend constexpr bool operator==(const IteratorImpl& lhs, const IteratorImpl& rhs)
{
return lhs.it_ == rhs.it_ && lhs.span_it_ == rhs.span_it_;
}

friend constexpr bool operator!=(const IteratorImpl& lhs, const IteratorImpl& rhs) { return !(lhs == rhs); }

private:
It it_;
It end_it_;
std::optional<SpanIt> span_it_;
};

using MemoryType = std::shared_ptr<std::vector<uint8_t>>;
GhostofCookie marked this conversation as resolved.
Show resolved Hide resolved
using BufferType = std::vector<MemoryType>;

SharedMemory() = default;

public:
static std::shared_ptr<SharedMemory> Create() noexcept
{
return std::shared_ptr<SharedMemory>(new SharedMemory());
}

void Push(Span<const uint8_t> bytes)
{
auto memory = std::make_shared<std::vector<uint8_t>>();
GhostofCookie marked this conversation as resolved.
Show resolved Hide resolved
memory->assign(bytes.begin(), bytes.end());
GhostofCookie marked this conversation as resolved.
Show resolved Hide resolved

buffer_.push_back(std::move(memory));
GhostofCookie marked this conversation as resolved.
Show resolved Hide resolved
}

friend SharedMemory& operator<<(SharedMemory& buffer, Span<const uint8_t> value)
{
buffer.Push(value);
return buffer;
}

// NOLINTBEGIN(readability-identifier-naming)
using iterator = IteratorImpl<BufferType::iterator, std::vector<uint8_t>::iterator>;
using const_iterator = IteratorImpl<BufferType::const_iterator, std::vector<uint8_t>::iterator>;

iterator begin() noexcept { return iterator(buffer_.begin(), buffer_.end()); }
iterator end() noexcept { return iterator(buffer_.end(), buffer_.end()); }
const_iterator begin() const noexcept { return const_iterator(buffer_.begin(), buffer_.end()); }
const_iterator end() const noexcept { return const_iterator(buffer_.end(), buffer_.end()); }
// NOLINTEND(readability-identifier-naming)

private:
BufferType buffer_;
};
}

1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ add_executable(quicr_test
client.cpp
tick_service.cpp
track_namespace.cpp
shared_memory.cpp
)
target_include_directories(quicr_test PRIVATE ${PROJECT_SOURCE_DIR}/src)

Expand Down
11 changes: 0 additions & 11 deletions test/cache_buffer.cpp

This file was deleted.

38 changes: 38 additions & 0 deletions test/shared_memory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: Copyright (c) 2024 Cisco Systems
// SPDX-License-Identifier: BSD-2-Clause

#include <doctest/doctest.h>

#include "quicr/shared_memory.h"

GhostofCookie marked this conversation as resolved.
Show resolved Hide resolved
TEST_CASE("SharedMemory Construct")
{
CHECK_NOTHROW(quicr::SharedMemory::Create());
}

TEST_CASE("SharedMemory Push")
{
auto buffer = quicr::SharedMemory::Create();

uint64_t value = 0;
auto bytes = quicr::AsBytes(value);
CHECK_NOTHROW(buffer->Push(bytes));
}

TEST_CASE("SharedMemory Read")
{
auto buffer = quicr::SharedMemory::Create();

uint64_t value = 0x0102030405060708;
auto bytes = quicr::AsBytes(value);
CHECK_NOTHROW(buffer->Push(bytes));

std::vector<uint8_t> v;
for (auto value : *buffer)
{
v.push_back(value);
}

CHECK_EQ(v.size(), 8);
CHECK_EQ(v, std::vector<uint8_t>{0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01});
}
Loading