mirror of
https://github.com/zeromq/cppzmq.git
synced 2025-06-09 07:40:17 +02:00
Change recv and send to return optional types
This commit is contained in:
parent
bbba565797
commit
88cee88d08
@ -86,11 +86,12 @@ TEST_CASE("socket sends and receives const buffer", "[socket]")
|
|||||||
const char* str = "Hi";
|
const char* str = "Hi";
|
||||||
|
|
||||||
#ifdef ZMQ_CPP11
|
#ifdef ZMQ_CPP11
|
||||||
CHECK(2 == sender.send(zmq::buffer(str, 2)).size);
|
CHECK(2 == *sender.send(zmq::buffer(str, 2)));
|
||||||
char buf[2];
|
char buf[2];
|
||||||
const auto res = receiver.recv(zmq::buffer(buf));
|
const auto res = receiver.recv(zmq::buffer(buf));
|
||||||
CHECK(!res.truncated());
|
CHECK(res);
|
||||||
CHECK(2 == res.size);
|
CHECK(!res->truncated());
|
||||||
|
CHECK(2 == res->size);
|
||||||
#else
|
#else
|
||||||
CHECK(2 == sender.send(str, 2));
|
CHECK(2 == sender.send(str, 2));
|
||||||
char buf[2];
|
char buf[2];
|
||||||
@ -109,11 +110,11 @@ TEST_CASE("socket send none sndmore", "[socket]")
|
|||||||
|
|
||||||
std::vector<char> buf(4);
|
std::vector<char> buf(4);
|
||||||
auto res = s.send(zmq::buffer(buf), zmq::send_flags::sndmore);
|
auto res = s.send(zmq::buffer(buf), zmq::send_flags::sndmore);
|
||||||
CHECK(res.size == buf.size());
|
CHECK(res);
|
||||||
CHECK(res.success);
|
CHECK(*res == buf.size());
|
||||||
res = s.send(zmq::buffer(buf));
|
res = s.send(zmq::buffer(buf));
|
||||||
CHECK(res.size == buf.size());
|
CHECK(res);
|
||||||
CHECK(res.success);
|
CHECK(*res == buf.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("socket send dontwait", "[socket]")
|
TEST_CASE("socket send dontwait", "[socket]")
|
||||||
@ -124,17 +125,14 @@ TEST_CASE("socket send dontwait", "[socket]")
|
|||||||
|
|
||||||
std::vector<char> buf(4);
|
std::vector<char> buf(4);
|
||||||
auto res = s.send(zmq::buffer(buf), zmq::send_flags::dontwait);
|
auto res = s.send(zmq::buffer(buf), zmq::send_flags::dontwait);
|
||||||
CHECK(!res.success);
|
CHECK(!res);
|
||||||
CHECK(res.size == 0);
|
|
||||||
res = s.send(zmq::buffer(buf),
|
res = s.send(zmq::buffer(buf),
|
||||||
zmq::send_flags::dontwait | zmq::send_flags::sndmore);
|
zmq::send_flags::dontwait | zmq::send_flags::sndmore);
|
||||||
CHECK(!res.success);
|
CHECK(!res);
|
||||||
CHECK(res.size == 0);
|
|
||||||
|
|
||||||
zmq::message_t msg;
|
zmq::message_t msg;
|
||||||
auto resm = s.send(msg, zmq::send_flags::dontwait);
|
auto resm = s.send(msg, zmq::send_flags::dontwait);
|
||||||
CHECK(!resm.success);
|
CHECK(!resm);
|
||||||
CHECK(resm.size == 0);
|
|
||||||
CHECK(msg.size() == 0);
|
CHECK(msg.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,23 +156,24 @@ TEST_CASE("socket recv none", "[socket]")
|
|||||||
|
|
||||||
std::vector<char> sbuf(4);
|
std::vector<char> sbuf(4);
|
||||||
const auto res_send = s2.send(zmq::buffer(sbuf));
|
const auto res_send = s2.send(zmq::buffer(sbuf));
|
||||||
CHECK(res_send.success);
|
CHECK(res_send);
|
||||||
|
CHECK(res_send.has_value());
|
||||||
|
|
||||||
std::vector<char> buf(2);
|
std::vector<char> buf(2);
|
||||||
const auto res = s.recv(zmq::buffer(buf));
|
const auto res = s.recv(zmq::buffer(buf));
|
||||||
CHECK(res.success);
|
CHECK(res.has_value());
|
||||||
CHECK(res.truncated());
|
CHECK(res->truncated());
|
||||||
CHECK(res.untruncated_size == sbuf.size());
|
CHECK(res->untruncated_size == sbuf.size());
|
||||||
CHECK(res.size == buf.size());
|
CHECK(res->size == buf.size());
|
||||||
|
|
||||||
const auto res_send2 = s2.send(zmq::buffer(sbuf));
|
const auto res_send2 = s2.send(zmq::buffer(sbuf));
|
||||||
CHECK(res_send2.success);
|
CHECK(res_send2.has_value());
|
||||||
std::vector<char> buf2(10);
|
std::vector<char> buf2(10);
|
||||||
const auto res2 = s.recv(zmq::buffer(buf2));
|
const auto res2 = s.recv(zmq::buffer(buf2));
|
||||||
CHECK(res2.success);
|
CHECK(res2.has_value());
|
||||||
CHECK(!res2.truncated());
|
CHECK(!res2->truncated());
|
||||||
CHECK(res2.untruncated_size == sbuf.size());
|
CHECK(res2->untruncated_size == sbuf.size());
|
||||||
CHECK(res2.size == sbuf.size());
|
CHECK(res2->size == sbuf.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("socket send recv message_t", "[socket]")
|
TEST_CASE("socket send recv message_t", "[socket]")
|
||||||
@ -187,15 +186,16 @@ TEST_CASE("socket send recv message_t", "[socket]")
|
|||||||
|
|
||||||
zmq::message_t smsg(size_t{10});
|
zmq::message_t smsg(size_t{10});
|
||||||
const auto res_send = s2.send(smsg, zmq::send_flags::none);
|
const auto res_send = s2.send(smsg, zmq::send_flags::none);
|
||||||
CHECK(res_send.success);
|
CHECK(res_send);
|
||||||
CHECK(res_send.size == 10);
|
CHECK(*res_send == 10);
|
||||||
CHECK(smsg.size() == 0);
|
CHECK(smsg.size() == 0);
|
||||||
|
|
||||||
zmq::message_t rmsg;
|
zmq::message_t rmsg;
|
||||||
const auto res = s.recv(rmsg);
|
const auto res = s.recv(rmsg);
|
||||||
CHECK(res.success);
|
CHECK(res);
|
||||||
CHECK(res.size == 10);
|
CHECK(*res == 10);
|
||||||
CHECK(rmsg.size() == res.size);
|
CHECK(res.value() == 10);
|
||||||
|
CHECK(rmsg.size() == *res);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("socket recv dontwait", "[socket]")
|
TEST_CASE("socket recv dontwait", "[socket]")
|
||||||
@ -207,13 +207,12 @@ TEST_CASE("socket recv dontwait", "[socket]")
|
|||||||
std::vector<char> buf(4);
|
std::vector<char> buf(4);
|
||||||
constexpr auto flags = zmq::recv_flags::none | zmq::recv_flags::dontwait;
|
constexpr auto flags = zmq::recv_flags::none | zmq::recv_flags::dontwait;
|
||||||
auto res = s.recv(zmq::buffer(buf), flags);
|
auto res = s.recv(zmq::buffer(buf), flags);
|
||||||
CHECK(!res.success);
|
CHECK(!res);
|
||||||
CHECK(res.size == 0);
|
|
||||||
|
|
||||||
zmq::message_t msg;
|
zmq::message_t msg;
|
||||||
auto resm = s.recv(msg, flags);
|
auto resm = s.recv(msg, flags);
|
||||||
CHECK(!resm.success);
|
CHECK(!resm);
|
||||||
CHECK(resm.size == 0);
|
CHECK_THROWS_AS(resm.value(), const std::exception &);
|
||||||
CHECK(msg.size() == 0);
|
CHECK(msg.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
132
zmq.hpp
132
zmq.hpp
@ -72,16 +72,21 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#ifdef ZMQ_CPP11
|
|
||||||
#include <array>
|
|
||||||
#endif
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iterator>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#ifdef ZMQ_CPP11
|
||||||
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
|
#include <tuple>
|
||||||
|
#include <memory>
|
||||||
|
#endif
|
||||||
|
#ifdef ZMQ_CPP17
|
||||||
|
#include <optional>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Version macros for compile-time API version detection */
|
/* Version macros for compile-time API version detection */
|
||||||
#define CPPZMQ_VERSION_MAJOR 4
|
#define CPPZMQ_VERSION_MAJOR 4
|
||||||
@ -92,12 +97,6 @@
|
|||||||
ZMQ_MAKE_VERSION(CPPZMQ_VERSION_MAJOR, CPPZMQ_VERSION_MINOR, \
|
ZMQ_MAKE_VERSION(CPPZMQ_VERSION_MAJOR, CPPZMQ_VERSION_MINOR, \
|
||||||
CPPZMQ_VERSION_PATCH)
|
CPPZMQ_VERSION_PATCH)
|
||||||
|
|
||||||
#ifdef ZMQ_CPP11
|
|
||||||
#include <chrono>
|
|
||||||
#include <tuple>
|
|
||||||
#include <memory>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Detect whether the compiler supports C++11 rvalue references.
|
// Detect whether the compiler supports C++11 rvalue references.
|
||||||
#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) \
|
#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) \
|
||||||
&& defined(__GXX_EXPERIMENTAL_CXX0X__))
|
&& defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||||
@ -621,23 +620,11 @@ inline void swap(context_t &a, context_t &b) ZMQ_NOTHROW {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ZMQ_CPP11
|
#ifdef ZMQ_CPP11
|
||||||
struct send_result
|
|
||||||
{
|
|
||||||
size_t size; // message size in bytes
|
|
||||||
bool success;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct recv_result
|
struct recv_buffer_size
|
||||||
{
|
|
||||||
size_t size; // message size in bytes
|
|
||||||
bool success;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct recv_buffer_result
|
|
||||||
{
|
{
|
||||||
size_t size; // number of bytes written to buffer
|
size_t size; // number of bytes written to buffer
|
||||||
size_t untruncated_size; // untruncated message size in bytes
|
size_t untruncated_size; // untruncated message size in bytes
|
||||||
bool success;
|
|
||||||
|
|
||||||
ZMQ_NODISCARD bool truncated() const noexcept
|
ZMQ_NODISCARD bool truncated() const noexcept
|
||||||
{
|
{
|
||||||
@ -647,6 +634,71 @@ struct recv_buffer_result
|
|||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef ZMQ_CPP17
|
||||||
|
using send_result_t = std::optional<size_t>;
|
||||||
|
using recv_result_t = std::optional<size_t>;
|
||||||
|
using recv_buffer_result_t = std::optional<recv_buffer_size>;
|
||||||
|
#else
|
||||||
|
// A C++11 type emulating the most basic
|
||||||
|
// operations of std::optional for trivial types
|
||||||
|
template<class T> class trivial_optional
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static_assert(std::is_trivial<T>::value, "T must be trivial");
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
trivial_optional() = default;
|
||||||
|
trivial_optional(T value) noexcept : _value(value), _has_value(true) {}
|
||||||
|
|
||||||
|
const T *operator->() const noexcept
|
||||||
|
{
|
||||||
|
assert(_has_value);
|
||||||
|
return &_value;
|
||||||
|
}
|
||||||
|
T *operator->() noexcept
|
||||||
|
{
|
||||||
|
assert(_has_value);
|
||||||
|
return &_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &operator*() const noexcept
|
||||||
|
{
|
||||||
|
assert(_has_value);
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
T &operator*() noexcept
|
||||||
|
{
|
||||||
|
assert(_has_value);
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
T &value()
|
||||||
|
{
|
||||||
|
if (!_has_value)
|
||||||
|
throw std::exception();
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
const T &value() const
|
||||||
|
{
|
||||||
|
if (!_has_value)
|
||||||
|
throw std::exception();
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const noexcept { return _has_value; }
|
||||||
|
bool has_value() const noexcept { return _has_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T _value{};
|
||||||
|
bool _has_value{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
using send_result_t = trivial_optional<size_t>;
|
||||||
|
using recv_result_t = trivial_optional<size_t>;
|
||||||
|
using recv_buffer_result_t = trivial_optional<recv_buffer_size>;
|
||||||
|
#endif
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
constexpr T enum_bit_or(T a, T b) noexcept
|
constexpr T enum_bit_or(T a, T b) noexcept
|
||||||
{
|
{
|
||||||
@ -1111,7 +1163,7 @@ public:
|
|||||||
int flags_ = 0) // default until removed
|
int flags_ = 0) // default until removed
|
||||||
{
|
{
|
||||||
#ifdef ZMQ_CPP11
|
#ifdef ZMQ_CPP11
|
||||||
return send(msg_, static_cast<send_flags>(flags_)).success;
|
return send(msg_, static_cast<send_flags>(flags_)).has_value();
|
||||||
#else
|
#else
|
||||||
return send(msg_, flags_);
|
return send(msg_, flags_);
|
||||||
#endif
|
#endif
|
||||||
@ -1119,28 +1171,28 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ZMQ_CPP11
|
#ifdef ZMQ_CPP11
|
||||||
send_result send(const_buffer buf, send_flags flags = send_flags::none)
|
detail::send_result_t send(const_buffer buf, send_flags flags = send_flags::none)
|
||||||
{
|
{
|
||||||
const int nbytes =
|
const int nbytes =
|
||||||
zmq_send(_handle, buf.data(), buf.size(), static_cast<int>(flags));
|
zmq_send(_handle, buf.data(), buf.size(), static_cast<int>(flags));
|
||||||
if (nbytes >= 0)
|
if (nbytes >= 0)
|
||||||
return {static_cast<size_t>(nbytes), true};
|
return static_cast<size_t>(nbytes);
|
||||||
if (zmq_errno() == EAGAIN)
|
if (zmq_errno() == EAGAIN)
|
||||||
return {size_t{0}, false};
|
return {};
|
||||||
throw error_t();
|
throw error_t();
|
||||||
}
|
}
|
||||||
|
|
||||||
send_result send(message_t &msg, send_flags flags)
|
detail::send_result_t send(message_t &msg, send_flags flags)
|
||||||
{
|
{
|
||||||
int nbytes = zmq_msg_send(msg.handle(), _handle, static_cast<int>(flags));
|
int nbytes = zmq_msg_send(msg.handle(), _handle, static_cast<int>(flags));
|
||||||
if (nbytes >= 0)
|
if (nbytes >= 0)
|
||||||
return {static_cast<size_t>(nbytes), true};
|
return static_cast<size_t>(nbytes);
|
||||||
if (zmq_errno() == EAGAIN)
|
if (zmq_errno() == EAGAIN)
|
||||||
return {size_t{0}, false};
|
return {};
|
||||||
throw error_t();
|
throw error_t();
|
||||||
}
|
}
|
||||||
|
|
||||||
send_result send(message_t &&msg, send_flags flags)
|
detail::send_result_t send(message_t &&msg, send_flags flags)
|
||||||
{
|
{
|
||||||
return send(msg, flags);
|
return send(msg, flags);
|
||||||
}
|
}
|
||||||
@ -1177,27 +1229,29 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ZMQ_CPP11
|
#ifdef ZMQ_CPP11
|
||||||
recv_buffer_result recv(mutable_buffer buf, recv_flags flags = recv_flags::none)
|
detail::recv_buffer_result_t recv(mutable_buffer buf,
|
||||||
|
recv_flags flags = recv_flags::none)
|
||||||
{
|
{
|
||||||
const int nbytes =
|
const int nbytes =
|
||||||
zmq_recv(_handle, buf.data(), buf.size(), static_cast<int>(flags));
|
zmq_recv(_handle, buf.data(), buf.size(), static_cast<int>(flags));
|
||||||
if (nbytes >= 0)
|
if (nbytes >= 0) {
|
||||||
return {(std::min)(static_cast<size_t>(nbytes), buf.size()),
|
return recv_buffer_size{(std::min)(static_cast<size_t>(nbytes), buf.size()),
|
||||||
static_cast<size_t>(nbytes), true};
|
static_cast<size_t>(nbytes)};
|
||||||
|
}
|
||||||
if (zmq_errno() == EAGAIN)
|
if (zmq_errno() == EAGAIN)
|
||||||
return {size_t{0}, size_t{0}, false};
|
return {};
|
||||||
throw error_t();
|
throw error_t();
|
||||||
}
|
}
|
||||||
|
|
||||||
recv_result recv(message_t &msg, recv_flags flags = recv_flags::none)
|
detail::recv_result_t recv(message_t &msg, recv_flags flags = recv_flags::none)
|
||||||
{
|
{
|
||||||
const int nbytes = zmq_msg_recv(msg.handle(), _handle, static_cast<int>(flags));
|
const int nbytes = zmq_msg_recv(msg.handle(), _handle, static_cast<int>(flags));
|
||||||
if (nbytes >= 0) {
|
if (nbytes >= 0) {
|
||||||
assert(msg.size() == static_cast<size_t>(nbytes));
|
assert(msg.size() == static_cast<size_t>(nbytes));
|
||||||
return {static_cast<size_t>(nbytes), true};
|
return static_cast<size_t>(nbytes);
|
||||||
}
|
}
|
||||||
if (zmq_errno() == EAGAIN)
|
if (zmq_errno() == EAGAIN)
|
||||||
return {size_t{0}, false};
|
return {};
|
||||||
throw error_t();
|
throw error_t();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -131,7 +131,7 @@ class multipart_t
|
|||||||
while (more) {
|
while (more) {
|
||||||
message_t message;
|
message_t message;
|
||||||
#ifdef ZMQ_CPP11
|
#ifdef ZMQ_CPP11
|
||||||
if (!socket.recv(message, static_cast<recv_flags>(flags)).success)
|
if (!socket.recv(message, static_cast<recv_flags>(flags)))
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
if (!socket.recv(&message, flags))
|
if (!socket.recv(&message, flags))
|
||||||
@ -153,7 +153,7 @@ class multipart_t
|
|||||||
more = size() > 0;
|
more = size() > 0;
|
||||||
#ifdef ZMQ_CPP11
|
#ifdef ZMQ_CPP11
|
||||||
if (!socket.send(message,
|
if (!socket.send(message,
|
||||||
static_cast<send_flags>((more ? ZMQ_SNDMORE : 0) | flags)).success)
|
static_cast<send_flags>((more ? ZMQ_SNDMORE : 0) | flags)))
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
if (!socket.send(message, (more ? ZMQ_SNDMORE : 0) | flags))
|
if (!socket.send(message, (more ? ZMQ_SNDMORE : 0) | flags))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user