Skip to content

Commit

Permalink
[eclipse-iceoryx#490] Implement slice loaning in iceoryx2_cxx
Browse files Browse the repository at this point in the history
  • Loading branch information
orecham committed Nov 2, 2024
1 parent 6deb81b commit 1d674ae
Show file tree
Hide file tree
Showing 14 changed files with 553 additions and 93 deletions.
95 changes: 74 additions & 21 deletions iceoryx2-ffi/cxx/include/iox/slice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "iox/assertions_addendum.hpp"

#include <cstdint>
#include <type_traits>

namespace iox {
template <typename T>
Expand All @@ -25,29 +26,81 @@ class Slice {
using ConstIterator = const T*;
using ValueType = T;

auto size() const -> uint64_t {
IOX_TODO();
}
auto operator[](const uint64_t n) const -> const T& {
IOX_TODO();
}
auto operator[](const uint64_t n) -> T& {
IOX_TODO();
}
auto begin() -> Iterator {
IOX_TODO();
}
auto begin() const -> ConstIterator {
IOX_TODO();
}
auto end() -> Iterator {
IOX_TODO();
}
auto end() const -> ConstIterator {
IOX_TODO();
}
Slice(const T* data, uint64_t number_of_elements);

auto number_of_elements() const -> uint64_t;
auto operator[](uint64_t n) const -> const T&;
auto operator[](uint64_t n) -> T&;

auto begin() -> Iterator;
auto begin() const -> ConstIterator;
auto end() -> Iterator;
auto end() const -> ConstIterator;

auto data() -> T*;
auto data() const -> const T*;

private:
T* m_data;
uint64_t m_number_of_elements;
};

template <typename T>
Slice<T>::Slice(const T* data, uint64_t number_of_elements)
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) constness protected by const class specification
: m_data { const_cast<T*>(data) }
, m_number_of_elements { number_of_elements } {
}

template <typename T>
auto Slice<T>::number_of_elements() const -> uint64_t {
return m_number_of_elements;
}

template <typename T>
auto Slice<T>::operator[](const uint64_t n) const -> const T& {
IOX_ASSERT(n < m_number_of_elements, "Index out of bounds");
return *(m_data + n);
}

template <typename T>
auto Slice<T>::operator[](const uint64_t n) -> T& {
IOX_ASSERT(n < m_number_of_elements, "Index out of bounds");
return *(m_data + n);
}

template <typename T>
auto Slice<T>::begin() -> Iterator {
return m_data;
}

template <typename T>
auto Slice<T>::begin() const -> ConstIterator {
return m_data;
}

template <typename T>
auto Slice<T>::end() -> Iterator {
static_assert(!std::is_same_v<T, void>, "Slice<void> is not allowed");
return m_data + m_number_of_elements;
}

template <typename T>
auto Slice<T>::end() const -> ConstIterator {
static_assert(!std::is_same_v<T, void>, "Slice<void> is not allowed");
return m_data + m_number_of_elements;
}

template <typename T>
auto Slice<T>::data() -> T* {
return m_data;
}

template <typename T>
auto Slice<T>::data() const -> const T* {
return m_data;
}

template <typename>
struct IsSlice {
static constexpr bool VALUE = false;
Expand Down
21 changes: 20 additions & 1 deletion iceoryx2-ffi/cxx/include/iox2/port_factory_publisher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,26 @@ PortFactoryPublisher<S, Payload, UserHeader>::create() && -> iox::expected<Publi
iox2_port_factory_publisher_builder_unable_to_deliver_strategy(
&m_handle, static_cast<iox2_unable_to_deliver_strategy_e>(iox::into<int>(value)));
});
m_max_slice_len.and_then([](auto) { IOX_TODO(); });
m_max_slice_len
.and_then([&](auto value) {
// The payload type used by the C API is always a [u8].
// Thus need to convert from N to N * sizeof(payload).
// TODO: Consider alignment... not aligning each element properly will impact performance
if constexpr (iox::IsSlice<Payload>::VALUE) {
iox2_port_factory_publisher_builder_set_max_slice_len(&m_handle,
value * sizeof(typename Payload::ValueType));
} else {
iox2_port_factory_publisher_builder_set_max_slice_len(&m_handle, value * sizeof(Payload));
}
})
.or_else([&]() {
// Assume only one element if not otherwise specified
if constexpr (iox::IsSlice<Payload>::VALUE) {
iox2_port_factory_publisher_builder_set_max_slice_len(&m_handle, sizeof(typename Payload::ValueType));
} else {
iox2_port_factory_publisher_builder_set_max_slice_len(&m_handle, sizeof(Payload));
}
});
m_max_loaned_samples.and_then(
[&](auto value) { iox2_port_factory_publisher_builder_set_max_loaned_samples(&m_handle, value); });

Expand Down
47 changes: 44 additions & 3 deletions iceoryx2-ffi/cxx/include/iox2/publisher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class Publisher {
/// since the [`Subscriber`]s buffer is full.
auto unable_to_deliver_strategy() const -> UnableToDeliverStrategy;

/// Returns the maximum number of elements that can be loaned in a slice.
auto max_slice_len() const -> uint64_t;

/// Copies the input `value` into a [`SampleMut`] and delivers it.
/// On success it returns the number of [`Subscriber`]s that received
/// the data, otherwise a [`PublisherSendError`] describing the failure.
Expand All @@ -56,13 +59,15 @@ class Publisher {
/// The user has to initialize the payload before it can be sent.
///
/// On failure it returns [`PublisherLoanError`] describing the failure.
template <typename T = Payload, typename = std::enable_if_t<!iox::IsSlice<T>::VALUE, void>>
auto loan_uninit() -> iox::expected<SampleMutUninit<S, Payload, UserHeader>, PublisherLoanError>;

/// Loans/allocates a [`SampleMut`] from the underlying data segment of the [`Publisher`]
/// and initialize it with the default value. This can be a performance hit and [`Publisher::loan_uninit`]
/// can be used to loan an uninitalized [`SampleMut`].
///
/// On failure it returns [`PublisherLoanError`] describing the failure.
template <typename T = Payload, typename = std::enable_if_t<!iox::IsSlice<T>::VALUE, void>>
auto loan() -> iox::expected<SampleMut<S, Payload, UserHeader>, PublisherLoanError>;

/// Loans/allocates a [`SampleMut`] from the underlying data segment of the [`Publisher`]
Expand Down Expand Up @@ -139,6 +144,20 @@ inline auto Publisher<S, Payload, UserHeader>::unable_to_deliver_strategy() cons
return iox::into<UnableToDeliverStrategy>(static_cast<int>(iox2_publisher_unable_to_deliver_strategy(&m_handle)));
}


template <ServiceType S, typename Payload, typename UserHeader>
inline auto Publisher<S, Payload, UserHeader>::max_slice_len() const -> uint64_t {
// NOTE: The C API always uses a [u8] payload, therefore the max length returned is the number of bytes.
// Dividing by the size gives the number of slice elements available to the C++ API.
//
// NOTE: For non-slice types, the number of slice elements is always 1.
if constexpr (iox::IsSlice<Payload>::VALUE) {
return iox2_publisher_max_slice_len(&m_handle) / sizeof(typename Payload::ValueType);
} else {
return iox2_publisher_max_slice_len(&m_handle) / sizeof(Payload);
}
}

template <ServiceType S, typename Payload, typename UserHeader>
inline auto Publisher<S, Payload, UserHeader>::id() const -> UniquePublisherId {
iox2_unique_publisher_id_h id_handle = nullptr;
Expand All @@ -164,11 +183,12 @@ inline auto Publisher<S, Payload, UserHeader>::send_copy(const Payload& payload)
}

template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto Publisher<S, Payload, UserHeader>::loan_uninit()
-> iox::expected<SampleMutUninit<S, Payload, UserHeader>, PublisherLoanError> {
SampleMutUninit<S, Payload, UserHeader> sample;

auto result = iox2_publisher_loan(&m_handle, &sample.m_sample.m_sample, &sample.m_sample.m_handle);
auto result = iox2_publisher_loan_slice_uninit(&m_handle, &sample.m_sample.m_sample, &sample.m_sample.m_handle, 1);

if (result == IOX2_OK) {
return iox::ok(std::move(sample));
Expand All @@ -178,6 +198,7 @@ inline auto Publisher<S, Payload, UserHeader>::loan_uninit()
}

template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto
Publisher<S, Payload, UserHeader>::loan() -> iox::expected<SampleMut<S, Payload, UserHeader>, PublisherLoanError> {
auto sample = loan_uninit();
Expand All @@ -195,14 +216,34 @@ template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto Publisher<S, Payload, UserHeader>::loan_slice(const uint64_t number_of_elements)
-> iox::expected<SampleMut<S, T, UserHeader>, PublisherLoanError> {
IOX_TODO();
auto sample_uninit = loan_slice_uninit(number_of_elements);

if (sample_uninit.has_error()) {
return iox::err(sample_uninit.error());
}
auto sample_init = std::move(sample_uninit.value());

for (auto& item : sample_init.payload_slice()) {
new (&item) typename T::ValueType();
}

return iox::ok(assume_init(std::move(sample_init)));
}

template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto Publisher<S, Payload, UserHeader>::loan_slice_uninit(const uint64_t number_of_elements)
-> iox::expected<SampleMutUninit<S, T, UserHeader>, PublisherLoanError> {
IOX_TODO();
SampleMutUninit<S, Payload, UserHeader> sample;

auto result = iox2_publisher_loan_slice_uninit(
&m_handle, &sample.m_sample.m_sample, &sample.m_sample.m_handle, number_of_elements);

if (result == IOX2_OK) {
return iox::ok(std::move(sample));
}

return iox::err(iox::into<PublisherLoanError>(result));
}

template <ServiceType S, typename Payload, typename UserHeader>
Expand Down
27 changes: 21 additions & 6 deletions iceoryx2-ffi/cxx/include/iox2/sample.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define IOX2_SAMPLE_HPP

#include "iox/assertions_addendum.hpp"
#include "iox/slice.hpp"
#include "iox2/header_publish_subscribe.hpp"
#include "iox2/internal/iceoryx2.hpp"
#include "iox2/service_type.hpp"
Expand Down Expand Up @@ -49,8 +50,13 @@ class Sample {
auto operator->() const -> const Payload*;

/// Returns a reference to the payload of the [`Sample`]
template <typename T = Payload, typename = std::enable_if_t<!iox::IsSlice<T>::VALUE, void>>
auto payload() const -> const Payload&;

/// Returns a slice to navigate the payload of the [`Sample`]
template <typename T = Payload, typename = std::enable_if_t<iox::IsSlice<T>::VALUE, void>>
auto payload_slice() const -> Payload;

/// Returns a reference to the user_header of the [`Sample`]
template <typename T = UserHeader, typename = std::enable_if_t<!std::is_same_v<void, UserHeader>, T>>
auto user_header() const -> const T&;
Expand Down Expand Up @@ -121,14 +127,24 @@ inline auto Sample<S, Payload, UserHeader>::operator->() const -> const Payload*
}

template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto Sample<S, Payload, UserHeader>::payload() const -> const Payload& {
const void* payload_ptr = nullptr;
size_t payload_len = 0;
const void* ptr = nullptr;

iox2_sample_payload(&m_handle, &payload_ptr, &payload_len);
IOX_ASSERT(sizeof(Payload) <= payload_len, "");
iox2_sample_payload(&m_handle, &ptr, nullptr);

return *static_cast<const Payload*>(payload_ptr);
return *static_cast<const Payload*>(ptr);
}

template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto Sample<S, Payload, UserHeader>::payload_slice() const -> Payload {
const void* ptr = nullptr;
size_t number_of_elements = 0;

iox2_sample_payload(&m_handle, &ptr, &number_of_elements);

return Payload(static_cast<const typename Payload::ValueType*>(ptr), number_of_elements);
}

template <ServiceType S, typename Payload, typename UserHeader>
Expand All @@ -154,7 +170,6 @@ inline auto Sample<S, Payload, UserHeader>::origin() const -> UniquePublisherId
return header().publisher_id();
}


} // namespace iox2

#endif
40 changes: 34 additions & 6 deletions iceoryx2-ffi/cxx/include/iox2/sample_mut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,19 @@ class SampleMut {
auto user_header_mut() -> T&;

/// Returns a reference to the const payload of the sample.
template <typename T = Payload, typename = std::enable_if_t<!iox::IsSlice<T>::VALUE, void>>
auto payload() const -> const Payload&;

/// Returns a reference to the payload of the sample.
template <typename T = Payload, typename = std::enable_if_t<!iox::IsSlice<T>::VALUE, void>>
auto payload_mut() -> Payload&;

template <typename T = Payload, typename = std::enable_if_t<iox::IsSlice<T>::VALUE, void>>
auto payload_slice() const -> const Payload;

template <typename T = Payload, typename = std::enable_if_t<iox::IsSlice<T>::VALUE, void>>
auto payload_slice_mut() -> Payload;

private:
template <ServiceType, typename, typename>
friend class Publisher;
Expand Down Expand Up @@ -186,27 +194,47 @@ inline auto SampleMut<S, Payload, UserHeader>::user_header_mut() -> T& {
}

template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto SampleMut<S, Payload, UserHeader>::payload() const -> const Payload& {
const void* ptr = nullptr;
size_t payload_len = 0;

iox2_sample_mut_payload(&m_handle, &ptr, &payload_len);
IOX_ASSERT(sizeof(Payload) <= payload_len, "");
iox2_sample_mut_payload(&m_handle, &ptr, nullptr);

return *static_cast<const Payload*>(ptr);
}

template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto SampleMut<S, Payload, UserHeader>::payload_mut() -> Payload& {
void* ptr = nullptr;
size_t payload_len = 0;

iox2_sample_mut_payload_mut(&m_handle, &ptr, &payload_len);
IOX_ASSERT(sizeof(Payload) <= payload_len, "");
iox2_sample_mut_payload_mut(&m_handle, &ptr, nullptr);

return *static_cast<Payload*>(ptr);
}

template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto SampleMut<S, Payload, UserHeader>::payload_slice() const -> const Payload {
const void* ptr = nullptr;
size_t number_of_elements = 0;

iox2_sample_mut_payload(&m_handle, &ptr, &number_of_elements);

return Payload(static_cast<typename Payload::ValueType*>(const_cast<void*>(ptr)), number_of_elements);
}

template <ServiceType S, typename Payload, typename UserHeader>
template <typename T, typename>
inline auto SampleMut<S, Payload, UserHeader>::payload_slice_mut() -> Payload {
void* ptr = nullptr;
size_t number_of_elements = 0;

iox2_sample_mut_payload_mut(&m_handle, &ptr, &number_of_elements);

return Payload(static_cast<typename Payload::ValueType*>(const_cast<void*>(ptr)), number_of_elements);
}

template <ServiceType S, typename Payload, typename UserHeader>
inline auto send(SampleMut<S, Payload, UserHeader>&& sample) -> iox::expected<size_t, PublisherSendError> {
size_t number_of_recipients = 0;
Expand Down
Loading

0 comments on commit 1d674ae

Please sign in to comment.