Program Listing for File message.hpp
↰ Return to documentation for file (include/ros_babel_fish/messages/message.hpp
)
// Copyright (c) 2021 Stefan Fabian. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef ROS_BABEL_FISH_MESSAGE_HPP
#define ROS_BABEL_FISH_MESSAGE_HPP
#include "ros_babel_fish/exceptions/babel_fish_exception.hpp"
#include "ros_babel_fish/macros.hpp"
#include <builtin_interfaces/msg/duration.hpp>
#include <builtin_interfaces/msg/time.hpp>
#include <rclcpp/macros.hpp>
#include <rclcpp/time.hpp>
#include <memory>
namespace ros_babel_fish
{
class Message
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE( Message )
explicit Message( MessageType type, std::shared_ptr<void> data );
virtual ~Message();
MessageType type() const { return type_; }
template<typename T>
T value() const
{
auto result = std::dynamic_pointer_cast<T>( data_ );
if ( !result )
throw BabelFishException( "Invalid cast!" );
return *result;
}
template<typename T>
T &as()
{
T *result = dynamic_cast<T *>( this );
if ( result == nullptr )
throw BabelFishException( "Tried to cast message to incompatible type!" );
return *result;
}
template<typename T>
const T &as() const
{
const T *result = dynamic_cast<const T *>( this );
if ( result == nullptr )
throw BabelFishException( "Tried to cast message to incompatible type!" );
return *result;
}
bool isTime() const;
bool isDuration() const;
virtual Message &operator[]( const std::string &key );
virtual const Message &operator[]( const std::string &key ) const;
Message &operator=( bool value );
Message &operator=( uint8_t value );
Message &operator=( uint16_t value );
Message &operator=( uint32_t value );
Message &operator=( uint64_t value );
Message &operator=( int8_t value );
Message &operator=( int16_t value );
Message &operator=( int32_t value );
Message &operator=( int64_t value );
Message &operator=( float value );
Message &operator=( double value );
Message &operator=( long double value );
Message &operator=( const char *value );
Message &operator=( const std::string &value );
Message &operator=( const std::wstring &value );
Message &operator=( const builtin_interfaces::msg::Time &value );
Message &operator=( const builtin_interfaces::msg::Duration &value );
Message &operator=( const rclcpp::Time &value );
Message &operator=( const rclcpp::Duration &value );
Message &operator=( const Message &other );
template<typename T>
bool operator==( const T &other ) const;
bool operator==( const Message &other ) const;
bool operator==( const char *c ) const;
bool operator==( const wchar_t *c ) const;
template<typename T>
bool operator!=( const T &other ) const;
protected:
void move( std::shared_ptr<void> new_data )
{
data_ = std::move( new_data );
onMoved();
}
virtual void onMoved() { }
template<typename T, typename U>
void checkValueEqual( const U &other, bool &result ) const;
// Disable copy construction except for subclasses
Message( const Message &other ) = default;
virtual bool _isMessageEqual( const Message &other ) const = 0;
virtual void _assign( const Message &other ) = 0;
unsigned char *data_ptr() { return reinterpret_cast<unsigned char *>( data_.get() ); }
const unsigned char *data_ptr() const
{
return reinterpret_cast<const unsigned char *>( data_.get() );
}
std::shared_ptr<void> data_;
MessageType type_;
friend class CompoundMessage;
template<bool, bool>
friend class CompoundArrayMessage_;
};
template<>
bool Message::value() const;
template<>
uint8_t Message::value() const;
template<>
uint16_t Message::value() const;
template<>
uint32_t Message::value() const;
template<>
uint64_t Message::value() const;
template<>
int8_t Message::value() const;
template<>
int16_t Message::value() const;
template<>
int32_t Message::value() const;
template<>
int64_t Message::value() const;
template<>
float Message::value() const;
template<>
double Message::value() const;
template<>
long double Message::value() const;
template<>
std::string Message::value() const;
template<>
char16_t Message::value() const;
template<>
std::wstring Message::value() const;
// These are now compound messages instead of value messages
template<>
rclcpp::Time Message::value() const;
template<>
rclcpp::Duration Message::value() const;
// Equality comparison needs to come after value specializations
namespace impl
{
template<typename X>
struct PassThrough {
typedef X type;
};
// Make sure we only compile possible comparisons.
// Looks more complicated than it is but the base implementation just makes sure we don't compare signed and unsigned
template<typename T>
struct EqHelper {
template<typename U>
using is_same_sign =
std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value>;
template<typename U>
static typename std::enable_if<std::is_arithmetic<U>::value && is_same_sign<U>::value, void>::type
equal( const Message *m, const U &other, bool &result )
{
result = m->template value<T>() == other;
}
template<typename U>
static typename std::enable_if<
std::is_arithmetic<U>::value && !is_same_sign<U>::value && std::is_signed<U>::value, void>::type
equal( const Message *m, const U &other, bool &result )
{
// Different sign and U signed so T is unsigned
if ( other < 0 ) {
result = false; // T can't be negative so no need to check
return;
}
// We always cast unsigned to signed since the other way is not always possible (e.g. float/double).
using SignedT = typename std::common_type<U, typename std::make_signed<T>::type>::type;
const T &val = m->template value<T>();
// val has to be able to fit into the SignedT type, this may have inaccuracies with some floating point types/values.
result = val <= static_cast<T>( std::numeric_limits<SignedT>::max() ) &&
static_cast<SignedT>( val ) == other;
}
template<typename U>
static typename std::enable_if<
std::is_arithmetic<U>::value && !is_same_sign<U>::value && !std::is_signed<U>::value, void>::type
equal( const Message *m, const U &other, bool &result )
{
// Different sign and U unsigned so T is signed
using SignedU = typename std::make_signed<U>::type;
if ( other > static_cast<U>( std::numeric_limits<SignedU>::max() ) )
result = false;
else
result = m->template value<T>() == static_cast<SignedU>( other );
}
template<typename U>
static typename std::enable_if<!std::is_arithmetic<U>::value, void>::type
equal( const Message *, const U &, bool &result )
{
result = false;
}
};
template<>
struct EqHelper<bool> {
template<typename U>
static typename std::enable_if<std::is_convertible<U, bool>::value, void>::type
equal( const Message *m, const U &other, bool &result )
{
result = m->template value<bool>() == other;
}
template<typename U>
static typename std::enable_if<!std::is_convertible<U, bool>::value, void>::type
equal( const Message *, const U &, bool &result )
{
result = false;
}
};
template<>
struct EqHelper<std::string> {
template<typename U>
static typename std::enable_if<std::is_convertible<U, std::string>::value, void>::type
equal( const Message *m, const U &other, bool &result )
{
result = m->template value<std::string>() == other;
}
template<typename U>
static typename std::enable_if<!std::is_convertible<U, std::string>::value, void>::type
equal( const Message *, const U &, bool &result )
{
result = false;
}
};
template<>
struct EqHelper<std::wstring> {
template<typename U>
static typename std::enable_if<std::is_convertible<U, std::wstring>::value, void>::type
equal( const Message *m, const U &other, bool &result )
{
result = m->template value<std::wstring>() == other;
}
template<typename U>
static typename std::enable_if<!std::is_convertible<U, std::wstring>::value, void>::type
equal( const Message *, const U &, bool &result )
{
result = false;
}
};
template<>
struct EqHelper<CompoundMessage> {
template<typename U>
static typename std::enable_if<std::is_base_of<Message, U>::value, void>::type
equal( const Message *m, const U &other, bool &result )
{
result = *m == other;
}
template<typename U>
static typename std::enable_if<!std::is_base_of<Message, U>::value, void>::type
equal( const Message *m, const U &other, bool &result )
{
result = m->template value<U>() == other;
}
};
template<>
struct EqHelper<ArrayMessageBase> {
template<typename U>
static typename std::enable_if<std::is_base_of<Message, U>::value, void>::type
equal( const Message *m, const U &other, bool &result )
{
result = *m == other;
}
template<typename U>
static typename std::enable_if<!std::is_base_of<Message, U>::value, void>::type
equal( const Message *, const U &, bool &result )
{
result = false;
}
};
} // namespace impl
template<typename T, typename U>
void Message::checkValueEqual( const U &other, bool &result ) const
{
impl::EqHelper<T>::equal( this, other, result );
}
template<typename T>
bool Message::operator==( const T &other ) const
{
bool result = false;
RBF2_TEMPLATE_CALL( checkValueEqual, type_, other, result );
return result;
}
template<typename T>
bool Message::operator!=( const T &other ) const
{
return !( *this == other );
}
} // namespace ros_babel_fish
#endif // ROS_BABEL_FISH_MESSAGE_HPP