Skip to content

Commit 88cee88

Browse files
committed
Change recv and send to return optional types
1 parent bbba565 commit 88cee88

File tree

3 files changed

+126
-73
lines changed

3 files changed

+126
-73
lines changed

tests/socket.cpp

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,12 @@ TEST_CASE("socket sends and receives const buffer", "[socket]")
8686
const char* str = "Hi";
8787

8888
#ifdef ZMQ_CPP11
89-
CHECK(2 == sender.send(zmq::buffer(str, 2)).size);
89+
CHECK(2 == *sender.send(zmq::buffer(str, 2)));
9090
char buf[2];
9191
const auto res = receiver.recv(zmq::buffer(buf));
92-
CHECK(!res.truncated());
93-
CHECK(2 == res.size);
92+
CHECK(res);
93+
CHECK(!res->truncated());
94+
CHECK(2 == res->size);
9495
#else
9596
CHECK(2 == sender.send(str, 2));
9697
char buf[2];
@@ -109,11 +110,11 @@ TEST_CASE("socket send none sndmore", "[socket]")
109110

110111
std::vector<char> buf(4);
111112
auto res = s.send(zmq::buffer(buf), zmq::send_flags::sndmore);
112-
CHECK(res.size == buf.size());
113-
CHECK(res.success);
113+
CHECK(res);
114+
CHECK(*res == buf.size());
114115
res = s.send(zmq::buffer(buf));
115-
CHECK(res.size == buf.size());
116-
CHECK(res.success);
116+
CHECK(res);
117+
CHECK(*res == buf.size());
117118
}
118119

119120
TEST_CASE("socket send dontwait", "[socket]")
@@ -124,17 +125,14 @@ TEST_CASE("socket send dontwait", "[socket]")
124125

125126
std::vector<char> buf(4);
126127
auto res = s.send(zmq::buffer(buf), zmq::send_flags::dontwait);
127-
CHECK(!res.success);
128-
CHECK(res.size == 0);
128+
CHECK(!res);
129129
res = s.send(zmq::buffer(buf),
130130
zmq::send_flags::dontwait | zmq::send_flags::sndmore);
131-
CHECK(!res.success);
132-
CHECK(res.size == 0);
131+
CHECK(!res);
133132

134133
zmq::message_t msg;
135134
auto resm = s.send(msg, zmq::send_flags::dontwait);
136-
CHECK(!resm.success);
137-
CHECK(resm.size == 0);
135+
CHECK(!resm);
138136
CHECK(msg.size() == 0);
139137
}
140138

@@ -158,23 +156,24 @@ TEST_CASE("socket recv none", "[socket]")
158156

159157
std::vector<char> sbuf(4);
160158
const auto res_send = s2.send(zmq::buffer(sbuf));
161-
CHECK(res_send.success);
159+
CHECK(res_send);
160+
CHECK(res_send.has_value());
162161

163162
std::vector<char> buf(2);
164163
const auto res = s.recv(zmq::buffer(buf));
165-
CHECK(res.success);
166-
CHECK(res.truncated());
167-
CHECK(res.untruncated_size == sbuf.size());
168-
CHECK(res.size == buf.size());
164+
CHECK(res.has_value());
165+
CHECK(res->truncated());
166+
CHECK(res->untruncated_size == sbuf.size());
167+
CHECK(res->size == buf.size());
169168

170169
const auto res_send2 = s2.send(zmq::buffer(sbuf));
171-
CHECK(res_send2.success);
170+
CHECK(res_send2.has_value());
172171
std::vector<char> buf2(10);
173172
const auto res2 = s.recv(zmq::buffer(buf2));
174-
CHECK(res2.success);
175-
CHECK(!res2.truncated());
176-
CHECK(res2.untruncated_size == sbuf.size());
177-
CHECK(res2.size == sbuf.size());
173+
CHECK(res2.has_value());
174+
CHECK(!res2->truncated());
175+
CHECK(res2->untruncated_size == sbuf.size());
176+
CHECK(res2->size == sbuf.size());
178177
}
179178

180179
TEST_CASE("socket send recv message_t", "[socket]")
@@ -187,15 +186,16 @@ TEST_CASE("socket send recv message_t", "[socket]")
187186

188187
zmq::message_t smsg(size_t{10});
189188
const auto res_send = s2.send(smsg, zmq::send_flags::none);
190-
CHECK(res_send.success);
191-
CHECK(res_send.size == 10);
189+
CHECK(res_send);
190+
CHECK(*res_send == 10);
192191
CHECK(smsg.size() == 0);
193192

194193
zmq::message_t rmsg;
195194
const auto res = s.recv(rmsg);
196-
CHECK(res.success);
197-
CHECK(res.size == 10);
198-
CHECK(rmsg.size() == res.size);
195+
CHECK(res);
196+
CHECK(*res == 10);
197+
CHECK(res.value() == 10);
198+
CHECK(rmsg.size() == *res);
199199
}
200200

201201
TEST_CASE("socket recv dontwait", "[socket]")
@@ -207,13 +207,12 @@ TEST_CASE("socket recv dontwait", "[socket]")
207207
std::vector<char> buf(4);
208208
constexpr auto flags = zmq::recv_flags::none | zmq::recv_flags::dontwait;
209209
auto res = s.recv(zmq::buffer(buf), flags);
210-
CHECK(!res.success);
211-
CHECK(res.size == 0);
210+
CHECK(!res);
212211

213212
zmq::message_t msg;
214213
auto resm = s.recv(msg, flags);
215-
CHECK(!resm.success);
216-
CHECK(resm.size == 0);
214+
CHECK(!resm);
215+
CHECK_THROWS_AS(resm.value(), const std::exception &);
217216
CHECK(msg.size() == 0);
218217
}
219218

zmq.hpp

Lines changed: 93 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,21 @@
7272
#include <cassert>
7373
#include <cstring>
7474

75-
#ifdef ZMQ_CPP11
76-
#include <array>
77-
#endif
7875
#include <algorithm>
7976
#include <exception>
8077
#include <iomanip>
81-
#include <iterator>
8278
#include <sstream>
8379
#include <string>
8480
#include <vector>
81+
#ifdef ZMQ_CPP11
82+
#include <array>
83+
#include <chrono>
84+
#include <tuple>
85+
#include <memory>
86+
#endif
87+
#ifdef ZMQ_CPP17
88+
#include <optional>
89+
#endif
8590

8691
/* Version macros for compile-time API version detection */
8792
#define CPPZMQ_VERSION_MAJOR 4
@@ -92,12 +97,6 @@
9297
ZMQ_MAKE_VERSION(CPPZMQ_VERSION_MAJOR, CPPZMQ_VERSION_MINOR, \
9398
CPPZMQ_VERSION_PATCH)
9499

95-
#ifdef ZMQ_CPP11
96-
#include <chrono>
97-
#include <tuple>
98-
#include <memory>
99-
#endif
100-
101100
// Detect whether the compiler supports C++11 rvalue references.
102101
#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) \
103102
&& defined(__GXX_EXPERIMENTAL_CXX0X__))
@@ -621,23 +620,11 @@ inline void swap(context_t &a, context_t &b) ZMQ_NOTHROW {
621620
}
622621

623622
#ifdef ZMQ_CPP11
624-
struct send_result
625-
{
626-
size_t size; // message size in bytes
627-
bool success;
628-
};
629-
630-
struct recv_result
631-
{
632-
size_t size; // message size in bytes
633-
bool success;
634-
};
635623

636-
struct recv_buffer_result
624+
struct recv_buffer_size
637625
{
638626
size_t size; // number of bytes written to buffer
639627
size_t untruncated_size; // untruncated message size in bytes
640-
bool success;
641628

642629
ZMQ_NODISCARD bool truncated() const noexcept
643630
{
@@ -647,6 +634,71 @@ struct recv_buffer_result
647634

648635
namespace detail
649636
{
637+
638+
#ifdef ZMQ_CPP17
639+
using send_result_t = std::optional<size_t>;
640+
using recv_result_t = std::optional<size_t>;
641+
using recv_buffer_result_t = std::optional<recv_buffer_size>;
642+
#else
643+
// A C++11 type emulating the most basic
644+
// operations of std::optional for trivial types
645+
template<class T> class trivial_optional
646+
{
647+
public:
648+
static_assert(std::is_trivial<T>::value, "T must be trivial");
649+
using value_type = T;
650+
651+
trivial_optional() = default;
652+
trivial_optional(T value) noexcept : _value(value), _has_value(true) {}
653+
654+
const T *operator->() const noexcept
655+
{
656+
assert(_has_value);
657+
return &_value;
658+
}
659+
T *operator->() noexcept
660+
{
661+
assert(_has_value);
662+
return &_value;
663+
}
664+
665+
const T &operator*() const noexcept
666+
{
667+
assert(_has_value);
668+
return _value;
669+
}
670+
T &operator*() noexcept
671+
{
672+
assert(_has_value);
673+
return _value;
674+
}
675+
676+
T &value()
677+
{
678+
if (!_has_value)
679+
throw std::exception();
680+
return _value;
681+
}
682+
const T &value() const
683+
{
684+
if (!_has_value)
685+
throw std::exception();
686+
return _value;
687+
}
688+
689+
explicit operator bool() const noexcept { return _has_value; }
690+
bool has_value() const noexcept { return _has_value; }
691+
692+
private:
693+
T _value{};
694+
bool _has_value{false};
695+
};
696+
697+
using send_result_t = trivial_optional<size_t>;
698+
using recv_result_t = trivial_optional<size_t>;
699+
using recv_buffer_result_t = trivial_optional<recv_buffer_size>;
700+
#endif
701+
650702
template<class T>
651703
constexpr T enum_bit_or(T a, T b) noexcept
652704
{
@@ -1111,36 +1163,36 @@ class socket_base
11111163
int flags_ = 0) // default until removed
11121164
{
11131165
#ifdef ZMQ_CPP11
1114-
return send(msg_, static_cast<send_flags>(flags_)).success;
1166+
return send(msg_, static_cast<send_flags>(flags_)).has_value();
11151167
#else
11161168
return send(msg_, flags_);
11171169
#endif
11181170
}
11191171
#endif
11201172

11211173
#ifdef ZMQ_CPP11
1122-
send_result send(const_buffer buf, send_flags flags = send_flags::none)
1174+
detail::send_result_t send(const_buffer buf, send_flags flags = send_flags::none)
11231175
{
11241176
const int nbytes =
11251177
zmq_send(_handle, buf.data(), buf.size(), static_cast<int>(flags));
11261178
if (nbytes >= 0)
1127-
return {static_cast<size_t>(nbytes), true};
1179+
return static_cast<size_t>(nbytes);
11281180
if (zmq_errno() == EAGAIN)
1129-
return {size_t{0}, false};
1181+
return {};
11301182
throw error_t();
11311183
}
11321184

1133-
send_result send(message_t &msg, send_flags flags)
1185+
detail::send_result_t send(message_t &msg, send_flags flags)
11341186
{
11351187
int nbytes = zmq_msg_send(msg.handle(), _handle, static_cast<int>(flags));
11361188
if (nbytes >= 0)
1137-
return {static_cast<size_t>(nbytes), true};
1189+
return static_cast<size_t>(nbytes);
11381190
if (zmq_errno() == EAGAIN)
1139-
return {size_t{0}, false};
1191+
return {};
11401192
throw error_t();
11411193
}
11421194

1143-
send_result send(message_t &&msg, send_flags flags)
1195+
detail::send_result_t send(message_t &&msg, send_flags flags)
11441196
{
11451197
return send(msg, flags);
11461198
}
@@ -1177,27 +1229,29 @@ class socket_base
11771229
}
11781230

11791231
#ifdef ZMQ_CPP11
1180-
recv_buffer_result recv(mutable_buffer buf, recv_flags flags = recv_flags::none)
1232+
detail::recv_buffer_result_t recv(mutable_buffer buf,
1233+
recv_flags flags = recv_flags::none)
11811234
{
11821235
const int nbytes =
11831236
zmq_recv(_handle, buf.data(), buf.size(), static_cast<int>(flags));
1184-
if (nbytes >= 0)
1185-
return {(std::min)(static_cast<size_t>(nbytes), buf.size()),
1186-
static_cast<size_t>(nbytes), true};
1237+
if (nbytes >= 0) {
1238+
return recv_buffer_size{(std::min)(static_cast<size_t>(nbytes), buf.size()),
1239+
static_cast<size_t>(nbytes)};
1240+
}
11871241
if (zmq_errno() == EAGAIN)
1188-
return {size_t{0}, size_t{0}, false};
1242+
return {};
11891243
throw error_t();
11901244
}
11911245

1192-
recv_result recv(message_t &msg, recv_flags flags = recv_flags::none)
1246+
detail::recv_result_t recv(message_t &msg, recv_flags flags = recv_flags::none)
11931247
{
11941248
const int nbytes = zmq_msg_recv(msg.handle(), _handle, static_cast<int>(flags));
11951249
if (nbytes >= 0) {
11961250
assert(msg.size() == static_cast<size_t>(nbytes));
1197-
return {static_cast<size_t>(nbytes), true};
1251+
return static_cast<size_t>(nbytes);
11981252
}
11991253
if (zmq_errno() == EAGAIN)
1200-
return {size_t{0}, false};
1254+
return {};
12011255
throw error_t();
12021256
}
12031257
#endif

zmq_addon.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ class multipart_t
131131
while (more) {
132132
message_t message;
133133
#ifdef ZMQ_CPP11
134-
if (!socket.recv(message, static_cast<recv_flags>(flags)).success)
134+
if (!socket.recv(message, static_cast<recv_flags>(flags)))
135135
return false;
136136
#else
137137
if (!socket.recv(&message, flags))
@@ -153,7 +153,7 @@ class multipart_t
153153
more = size() > 0;
154154
#ifdef ZMQ_CPP11
155155
if (!socket.send(message,
156-
static_cast<send_flags>((more ? ZMQ_SNDMORE : 0) | flags)).success)
156+
static_cast<send_flags>((more ? ZMQ_SNDMORE : 0) | flags)))
157157
return false;
158158
#else
159159
if (!socket.send(message, (more ? ZMQ_SNDMORE : 0) | flags))

0 commit comments

Comments
 (0)