Skip to content

Added comparison operators for properties. #906

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 2 commits into from
Nov 29, 2021
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
45 changes: 41 additions & 4 deletions include/mqtt/property.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <boost/asio/buffer.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/container/static_vector.hpp>
#include <boost/operators.hpp>

#include <mqtt/namespace.hpp>
#include <mqtt/optional.hpp>
Expand Down Expand Up @@ -52,7 +53,7 @@ enum class ostream_format {
};

template <std::size_t N>
struct n_bytes_property {
struct n_bytes_property : private boost::totally_ordered<n_bytes_property<N>> {
explicit n_bytes_property(property::id id)
:id_(id) {}

Expand Down Expand Up @@ -110,12 +111,20 @@ struct n_bytes_property {
return 2;
}

friend bool operator<(n_bytes_property<N> const& lhs, n_bytes_property<N> const& rhs) {
return std::tie(lhs.id_, lhs.buf_) < std::tie(rhs.id_, rhs.buf_);
}

friend bool operator==(n_bytes_property<N> const& lhs, n_bytes_property<N> const& rhs) {
return std::tie(lhs.id_, lhs.buf_) == std::tie(rhs.id_, rhs.buf_);
}

static constexpr ostream_format const of_ = ostream_format::direct;
property::id id_;
boost::container::static_vector<char, N> buf_;
};

struct binary_property {
struct binary_property : private boost::totally_ordered<binary_property> {
binary_property(property::id id, buffer buf)
:id_(id),
buf_(force_move(buf)),
Expand Down Expand Up @@ -179,6 +188,14 @@ struct binary_property {
return buf_;
}

friend bool operator<(binary_property const& lhs, binary_property const& rhs) {
return std::tie(lhs.id_, lhs.buf_) < std::tie(rhs.id_, rhs.buf_);
}

friend bool operator==(binary_property const& lhs, binary_property const& rhs) {
return std::tie(lhs.id_, lhs.buf_) == std::tie(rhs.id_, rhs.buf_);
}

static constexpr ostream_format const of_ = ostream_format::json_like;
property::id id_;
buffer buf_;
Expand All @@ -195,7 +212,7 @@ struct string_property : binary_property {
}
};

struct variable_property {
struct variable_property : private boost::totally_ordered<variable_property> {
variable_property(property::id id, std::size_t value)
:id_(id) {
variable_push(value_, value);
Expand Down Expand Up @@ -252,6 +269,18 @@ struct variable_property {
return std::get<0>(variable_length(value_));
}

friend bool operator<(variable_property const& lhs, variable_property const& rhs) {
auto const& lval = lhs.val();
auto const& rval = rhs.val();
return std::tie(lhs.id_, lval) < std::tie(rhs.id_, rval);
}

friend bool operator==(variable_property const& lhs, variable_property const& rhs) {
auto const& lval = lhs.val();
auto const& rval = rhs.val();
return std::tie(lhs.id_, lval) == std::tie(rhs.id_, rval);
}

static constexpr ostream_format const of_ = ostream_format::direct;
property::id id_;
boost::container::static_vector<char, 4> value_;
Expand Down Expand Up @@ -534,7 +563,7 @@ class retain_available : public detail::n_bytes_property<1> {
};


class user_property {
class user_property : private boost::totally_ordered<user_property> {
public:
user_property(buffer key, buffer val, bool key_already_checked = false, bool val_already_checked = false)
: key_(force_move(key), key_already_checked), val_(force_move(val), val_already_checked) {}
Expand Down Expand Up @@ -614,6 +643,14 @@ class user_property {
return val_.buf;
}

friend bool operator<(user_property const& lhs, user_property const& rhs) {
return std::tie(lhs.id_, lhs.key_.buf, lhs.val_.buf) < std::tie(rhs.id_, rhs.key_.buf, rhs.val_.buf);
}

friend bool operator==(user_property const& lhs, user_property const& rhs) {
return std::tie(lhs.id_, lhs.key_.buf, lhs.val_.buf) == std::tie(rhs.id_, rhs.key_.buf, rhs.val_.buf);
}

static constexpr detail::ostream_format const of_ = detail::ostream_format::key_val;

private:
Expand Down
49 changes: 49 additions & 0 deletions include/mqtt/property_variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,55 @@ inline void fill(property_variant const& pv, Iterator b, Iterator e) {
MQTT_NS::visit(vis, pv);
}

struct less_than_visitor {
template <typename T>
bool operator()(T const& lhs, T const& rhs) const {
return lhs < rhs;
}
template <typename T, typename U>
bool operator()(T const& lhs, U const& rhs) const {
return lhs.id() < rhs.id();
}
};

inline
bool operator<(property_variant const& lhs, property_variant const& rhs) {
return MQTT_NS::visit(
less_than_visitor(),
lhs,
rhs
);
}

struct equal_visitor {
template <typename T>
bool operator()(T const& lhs, T const& rhs) const {
return lhs == rhs;
}
template <typename T, typename U>
bool operator()(T const&, U const&) const {
return false;
}
};

inline
bool operator==(property_variant const& lhs, property_variant const& rhs) {
return MQTT_NS::visit(
equal_visitor(),
lhs,
rhs
);
}

inline
bool operator!=(property_variant const& lhs, property_variant const& rhs) {
return !MQTT_NS::visit(
equal_visitor(),
lhs,
rhs
);
}

template <typename... Visitors>
inline
void
Expand Down
204 changes: 204 additions & 0 deletions test/unit/ut_property.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include <mqtt/optional.hpp>
#include <mqtt/property.hpp>
#include <mqtt/property_variant.hpp>

BOOST_AUTO_TEST_SUITE(ut_property)

Expand Down Expand Up @@ -176,4 +177,207 @@ BOOST_AUTO_TEST_CASE( user_property ) {
BOOST_TEST(boost::lexical_cast<std::string>(v1) == "abc:def");
}

BOOST_AUTO_TEST_CASE(comparison) {
{
MQTT_NS::v5::property::payload_format_indicator v1 { MQTT_NS::v5::property::payload_format_indicator::binary };
MQTT_NS::v5::property::payload_format_indicator v2 { MQTT_NS::v5::property::payload_format_indicator::string };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::message_expiry_interval v1 { 1234 };
MQTT_NS::v5::property::message_expiry_interval v2 { 5678 };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::subscription_identifier v1 { 1234 };
MQTT_NS::v5::property::subscription_identifier v2 { 5678 };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::session_expiry_interval v1 { 1234 };
MQTT_NS::v5::property::session_expiry_interval v2 { 5678 };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::server_keep_alive v1 { 1234 };
MQTT_NS::v5::property::server_keep_alive v2 { 5678 };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::request_problem_information v1 { false };
MQTT_NS::v5::property::request_problem_information v2 { true };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::will_delay_interval v1 { 1234 };
MQTT_NS::v5::property::will_delay_interval v2 { 5678 };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::request_response_information v1 { false };
MQTT_NS::v5::property::request_response_information v2 { true };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::receive_maximum v1 { 1234 };
MQTT_NS::v5::property::receive_maximum v2 { 5678 };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::topic_alias_maximum v1 { 1234 };
MQTT_NS::v5::property::topic_alias_maximum v2 { 5678 };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::topic_alias v1 { 1234 };
MQTT_NS::v5::property::topic_alias v2 { 5678 };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::maximum_qos v1 { MQTT_NS::qos::at_most_once };
MQTT_NS::v5::property::maximum_qos v2 { MQTT_NS::qos::at_least_once };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::retain_available v1 { false };
MQTT_NS::v5::property::retain_available v2 { true };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::maximum_packet_size v1 { 1234 };
MQTT_NS::v5::property::maximum_packet_size v2 { 5678 };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::wildcard_subscription_available v1 { false };
MQTT_NS::v5::property::wildcard_subscription_available v2 { true };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::subscription_identifier_available v1 { false };
MQTT_NS::v5::property::subscription_identifier_available v2 { true };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::shared_subscription_available v1 { false };
MQTT_NS::v5::property::shared_subscription_available v2 { true };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::content_type v1 { "abc"_mb };
MQTT_NS::v5::property::content_type v2 { "def"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::response_topic v1 { "abc"_mb };
MQTT_NS::v5::property::response_topic v2 { "def"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::correlation_data v1 { "ab\0c"_mb };
MQTT_NS::v5::property::correlation_data v2 { "ab\0f"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::assigned_client_identifier v1 { "abc"_mb };
MQTT_NS::v5::property::assigned_client_identifier v2 { "def"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::authentication_method v1 { "abc"_mb };
MQTT_NS::v5::property::authentication_method v2 { "def"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::authentication_data v1 { "abc"_mb };
MQTT_NS::v5::property::authentication_data v2 { "def"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::response_information v1 { "abc"_mb };
MQTT_NS::v5::property::response_information v2 { "def"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::server_reference v1 { "abc"_mb };
MQTT_NS::v5::property::server_reference v2 { "def"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::reason_string v1 { "abc"_mb };
MQTT_NS::v5::property::reason_string v2 { "def"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}
{
MQTT_NS::v5::property::user_property v1 { "abc"_mb, "def"_mb };
MQTT_NS::v5::property::user_property v2 { "abc"_mb, "ghi"_mb };
BOOST_TEST(v1 == v1);
BOOST_TEST(v1 != v2);
BOOST_TEST(v1 < v2);
}

{
MQTT_NS::v5::property::user_property v1 { "abc"_mb, "def"_mb };
MQTT_NS::v5::property::user_property v2 { "abc"_mb, "ghi"_mb };

MQTT_NS::v5::properties ps1 { v1, v2 };
MQTT_NS::v5::properties ps2 { v2, v1 };
BOOST_TEST(ps1 == ps1);
BOOST_TEST(ps1 != ps2);
BOOST_TEST(ps1 < ps2);
}
}

BOOST_AUTO_TEST_SUITE_END()