Skip to content

[measurement] Reuse Serializers for High Level Measurement API #2087

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

Merged
merged 15 commits into from
Mar 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
67 changes: 55 additions & 12 deletions contrib/measurement/base/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ========================= eCAL LICENSE =================================
#
# Copyright (C) 2016 - 2019 Continental Corporation
# Copyright (C) 2016 - 2025 Continental Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -16,24 +16,67 @@
#
# ========================= eCAL LICENSE =================================

project(measurement_base)
project(measurement)

set(ecal_message_header
include/ecal/measurement/base/measurement.h
###################################
# Base Measurement common headers #
###################################
add_library(measurement_base INTERFACE)
add_library(eCAL::measurement_base ALIAS measurement_base)

target_sources(measurement_base
INTERFACE
FILE_SET measurement_base_headers
TYPE HEADERS
BASE_DIRS include
FILES
include/ecal/measurement/base/reader.h
include/ecal/measurement/base/types.h
include/ecal/measurement/base/writer.h
)

add_library(${PROJECT_NAME} INTERFACE)
add_library(eCAL::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_compile_features(measurement_base INTERFACE cxx_std_14)

target_include_directories(${PROJECT_NAME} INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
install(
TARGETS measurement_base
EXPORT eCALCoreTargets
ARCHIVE DESTINATION "${eCAL_install_archive_dir}" COMPONENT sdk
LIBRARY DESTINATION "${eCAL_install_lib_dir}" COMPONENT sdk
FILE_SET measurement_base_headers COMPONENT sdk
)

ecal_install_library(${PROJECT_NAME})

install(DIRECTORY
"include/" DESTINATION "${eCAL_install_include_dir}" COMPONENT sdk
###################################
# Measurement library #
###################################
add_library(measurement INTERFACE)
add_library(eCAL::measurement ALIAS measurement)

target_sources(measurement
INTERFACE
FILE_SET measurement_headers
TYPE HEADERS
BASE_DIRS include
FILES
include/ecal/measurement/measurement.h
include/ecal/measurement/imeasurement.h
include/ecal/measurement/omeasurement.h

)

target_compile_features(measurement INTERFACE cxx_std_14)

install(
TARGETS measurement
EXPORT eCALCoreTargets
ARCHIVE DESTINATION "${eCAL_install_archive_dir}" COMPONENT sdk
LIBRARY DESTINATION "${eCAL_install_lib_dir}" COMPONENT sdk
FILE_SET measurement_headers COMPONENT sdk
)

target_link_libraries(measurement
INTERFACE
eCAL::measurement_hdf5
)


165 changes: 40 additions & 125 deletions contrib/measurement/base/include/ecal/measurement/imeasurement.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* ========================= eCAL LICENSE =================================
*
* Copyright (C) 2016 - 2024 Continental Corporation
* Copyright (C) 2016 - 2025 Continental Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,45 +26,51 @@
#include <stdexcept>

#include <ecal/measurement/hdf5/reader.h>
#include <ecal/measurement/base/types.h>
#include <ecal/measurement/measurement.h>

namespace eCAL
{
namespace measurement
{
class IBinaryChannel
class IChannel
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: destructor of 'IChannel' is public and non-virtual [cppcoreguidelines-virtual-class-destructor]

    class IChannel
          ^
Additional context

contrib/measurement/base/include/ecal/measurement/imeasurement.h:35: make it public and virtual

    class IChannel
          ^

{
public:
IBinaryChannel(std::shared_ptr<experimental::measurement::base::Reader> meas_, experimental::measurement::base::Channel channel_)
: channel(channel_)
, meas(meas_)
IChannel(std::shared_ptr<experimental::measurement::base::Reader> meas_, experimental::measurement::base::Channel channel_)
: meas(meas_)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: parameter 'meas_' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

Suggested change
: meas(meas_)
: meas(std::move(meas_))

, channel(channel_)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: parameter 'channel_' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]

Suggested change
, channel(channel_)
, channel(std::move(channel_))

, datatype_info(meas->GetChannelDataTypeInformation(channel))
{
meas->GetEntriesInfo(channel, entry_infos);
}

virtual BinaryFrame operator[](const experimental::measurement::base::EntryInfo& entry)
~IChannel() = default;

IChannel(const IChannel&) = delete;
IChannel& operator=(const IChannel&) = delete;

IChannel(IChannel&& rhs) = default;
IChannel& operator=(IChannel&& rhs) = default;

const std::string& GetName() const
{
size_t message_size;
meas->GetEntryDataSize(entry.ID, message_size);
data.resize(message_size);
meas->GetEntryData(entry.ID, (void*)data.data());
return make_frame( data, entry.SndTimestamp, entry.RcvTimestamp );
return channel.name;
}

std::string name()
const eCAL::experimental::measurement::base::DataTypeInformation& GetDatatypeInformation() const
{
return channel.name;
return datatype_info;
}

class iterator /*: public std::iterator<std::forward_iterator_tag, Entry<T>>*/
{
public:
iterator(IBinaryChannel& owner_)
iterator(IChannel& owner_)
: m_owner(owner_)
, m_entry_iterator(owner_.entry_infos.begin())
{};

iterator(IBinaryChannel& owner_, const experimental::measurement::base::EntryInfoSet::iterator& it)
iterator(IChannel& owner_, const experimental::measurement::base::EntryInfoSet::iterator& it)
: m_owner(owner_)
, m_entry_iterator(it)
{};
Expand Down Expand Up @@ -95,13 +101,13 @@ namespace eCAL
bool operator==(const iterator& rhs) const { return m_owner == rhs.m_owner && m_entry_iterator == rhs.m_entry_iterator; /*return it == rhs.it; */ };
bool operator!=(const iterator& rhs) const { return !(operator==(rhs)); };
private:
IBinaryChannel& m_owner;
IChannel& m_owner;
experimental::measurement::base::EntryInfoSet::iterator m_entry_iterator;
mutable std::string m_msg;
};

bool operator==(const IBinaryChannel& rhs) const { return channel == rhs.channel && meas == rhs.meas; /*return it == rhs.it; */ };
bool operator!=(const IBinaryChannel& rhs) const { return !(operator==(rhs)); /*return it == rhs.it; */ };
bool operator==(const IChannel& rhs) const { return channel == rhs.channel && meas == rhs.meas; /*return it == rhs.it; */ };
bool operator!=(const IChannel& rhs) const { return !(operator==(rhs)); /*return it == rhs.it; */ };

iterator begin()
{
Expand All @@ -114,104 +120,22 @@ namespace eCAL
}

private:
const experimental::measurement::base::Channel channel;
std::shared_ptr<experimental::measurement::base::Reader> meas;
mutable experimental::measurement::base::EntryInfoSet entry_infos;
mutable std::string data;
};


template <typename T>
class IChannel
{
public:
IChannel(std::shared_ptr<experimental::measurement::base::Reader> meas_, const experimental::measurement::base::Channel& channel_)
: binary_channel(meas_, channel_)
{
}

bool operator==(const IChannel& rhs) const { return binary_channel == rhs.binary_channel; }
bool operator!=(const IChannel& rhs) const { return !(operator==(rhs)); }

//virtual Entry<T> operator[](unsigned long long timestamp);
virtual Frame<T> operator[](const experimental::measurement::base::EntryInfo& entry)
BinaryFrame operator[](const experimental::measurement::base::EntryInfo& entry)
{
auto binary_entry = binary_channel[entry];
eCAL::message::Deserialize(binary_entry.message, message);
return make_frame( message, binary_entry.send_timestamp, binary_entry.receive_timestamp );
}

std::string name()
{
return binary_channel.name();
}

//typedef typename Entry<T> value_type;
//typedef typename Alloc::reference reference;
//typedef typename Alloc::const_reference const_reference;
//typedef typename Alloc::difference_type difference_type;
//typedef typename Alloc::size_type size_type;

class iterator /*: public std::iterator<std::forward_iterator_tag, Entry<T>>*/
{
public:
iterator(const iterator& i)
: it(i.it)
{};

iterator(const IBinaryChannel::iterator& i)
: it(i)
{};

~iterator()
{};

iterator& operator=(const iterator& i)
{
it = i.it;
return *this;
};
iterator& operator++()
{
++it;
return *this;
}; //prefix increment
iterator& operator--()
{
--it;
return *this;
}; //prefix decrement
//reference operator*() const

virtual Frame<T> operator*() const
{
// return m_owner[*m_entry_iterator];
BinaryFrame e = *it;
eCAL::message::Deserialize(e.message, message);
return make_frame(message, e.send_timestamp, e.receive_timestamp);
};
//friend void swap(iterator& lhs, iterator& rhs); //C++11 I think
bool operator==(const iterator& rhs) const { return it == rhs.it; };
bool operator!=(const iterator& rhs) const { return it != rhs.it; };

protected:
IBinaryChannel::iterator it;
mutable T message;
};

iterator begin()
{
return iterator(binary_channel.begin());
size_t message_size;
meas->GetEntryDataSize(entry.ID, message_size);
data.resize(message_size);
meas->GetEntryData(entry.ID, (void*)data.data());
return make_frame(data, entry.SndTimestamp, entry.RcvTimestamp);
}

iterator end()
{
return iterator(binary_channel.end());
}
std::shared_ptr<experimental::measurement::base::Reader> meas;

const experimental::measurement::base::Channel channel;
const experimental::measurement::base::DataTypeInformation datatype_info;

protected:
IBinaryChannel binary_channel;
mutable T message;
mutable experimental::measurement::base::EntryInfoSet entry_infos;
mutable std::string data;
};

class IMeasurement
Expand All @@ -222,8 +146,7 @@ namespace eCAL
ChannelSet Channels() const;
ChannelSet Channels(const std::string& channel_name) const;

template<typename T>
IChannel<T> Get(const experimental::measurement::base::Channel& channel) const;
IChannel Get(const experimental::measurement::base::Channel& channel) const;

private:
std::shared_ptr<experimental::measurement::base::Reader> meas;
Expand Down Expand Up @@ -253,12 +176,7 @@ namespace eCAL
return channels_filtered_by_name;
}

// This will return a nullptr if channel name and
// This will throw an exception if
// a) channel does not exist in the IMeasurement
// b) the registered type does not match with the descriptor in the chanenel
template<typename T>
inline IChannel<T> IMeasurement::Get(const experimental::measurement::base::Channel& channel) const
inline IChannel IMeasurement::Get(const experimental::measurement::base::Channel& channel) const
{
// Assert that the channel is in the IMeasurement
auto channels = Channels();
Expand All @@ -268,11 +186,8 @@ namespace eCAL
throw std::out_of_range("The channel {" + channel.name + ", " + std::to_string(channel.id) + "} does not exist in this measurement");
}

// Assert that the channel type is compatible with the requested type

// Construct a channel based
return IChannel<T>{meas, channel};
// Construct a binary Channel
return IChannel{meas, channel};
}

}
}
19 changes: 8 additions & 11 deletions contrib/measurement/base/include/ecal/measurement/measurement.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* ========================= eCAL LICENSE =================================
*
* Copyright (C) 2016 - 2024 Continental Corporation
* Copyright (C) 2016 - 2025 Continental Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,6 +21,7 @@

#include <set>
#include <string>
#include <ecal/measurement/base/types.h>

/*
Please note, the API of eCAL::measurement is not yet stable. It might be subject to API changes in future eCAL versions.
Expand All @@ -32,33 +33,29 @@ namespace eCAL
{
using ChannelSet = std::set<eCAL::experimental::measurement::base::Channel>;

struct SenderID
{
long long ID;
};


// A frame is only a leightweight wrapper around a datatype, which also contains send / receive timestamp
// It is non-owning and should be treated as a view.
template<class T>
struct Frame
{
T& message;
const T& message;
long long send_timestamp;
long long receive_timestamp;
};

template<typename T>
Frame<T> make_frame(T& message, long long send_timestamp, long long receive_timestamp)
Frame<T> make_frame(const T& message, long long send_timestamp, long long receive_timestamp)
{
return { message, send_timestamp, receive_timestamp };
}

template<typename T>
Frame<T> make_frame(T& message, long long timestamp)
Frame<T> make_frame(const T& message, long long timestamp)
{
return { message, timestamp, timestamp };
}

// This is a frame that holds binary data.
using BinaryFrame = Frame<std::string>;

}
}
Loading
Loading