Skip to content
Open
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
21 changes: 21 additions & 0 deletions tests/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ static_assert(std::is_nothrow_swappable<zmq::context_t>::value,
"context_t should be nothrow swappable");
#endif

#ifdef ZMQ_CPP11
constexpr zmq::recv_buffer_size truncated_size{0u, 1u};
constexpr zmq::recv_buffer_size full_size{1u, 1u};
static_assert(
truncated_size.truncated(),
"recv_buffer_size::truncated should be constexpr for truncated buffers");
static_assert(!full_size.truncated(),
"recv_buffer_size::truncated should be constexpr for full buffers");

#if !CPPZMQ_HAS_OPTIONAL
constexpr zmq::detail::trivial_optional<size_t> empty_optional;
constexpr zmq::detail::trivial_optional<size_t> value_optional(42u);
static_assert(!empty_optional.has_value(),
"trivial_optional::has_value should be constexpr for empty state");
static_assert(value_optional.has_value(),
"trivial_optional::has_value should be constexpr for value state");
static_assert(static_cast<bool>(value_optional),
"trivial_optional::operator bool should be constexpr");
#endif
#endif

TEST_CASE("context construct default and destroy", "[context]")
{
zmq::context_t context;
Expand Down
9 changes: 9 additions & 0 deletions tests/socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ TEST_CASE("socket default ctor", "[socket]")
zmq::socket_t socket;
}

#if defined(ZMQ_CPP11) && defined(ZMQ_CONSTEXPR_FN)
TEST_CASE("socket_base constexpr init", "[socket]")
{
constexpr zmq::detail::socket_base sb;
static_assert(sb.handle() == nullptr, "socket_base handle should be constexpr");
static_assert(!sb, "socket_base bool conversion should be constexpr");
}
#endif

TEST_CASE("socket create destroy", "[socket]")
{
zmq::context_t context;
Expand Down
10 changes: 10 additions & 0 deletions tests/socket_ref.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ TEST_CASE("socket_ref default init", "[socket_ref]")
CHECK(sr.handle() == nullptr);
}

#if defined(ZMQ_CPP11) && defined(ZMQ_CONSTEXPR_FN)
TEST_CASE("socket_ref constexpr init", "[socket_ref]")
{
constexpr zmq::socket_ref sr;
static_assert(sr.handle() == nullptr, "socket_ref handle should be constexpr");
static_assert(sr == nullptr,
"socket_ref nullptr comparison should be constexpr");
}
#endif

TEST_CASE("socket_ref create from nullptr", "[socket_ref]")
{
zmq::socket_ref sr = nullptr;
Expand Down
116 changes: 88 additions & 28 deletions zmq.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
#endif
#if defined(ZMQ_CPP14) && (!defined(_MSC_VER) || _MSC_VER > 1900) \
&& (!defined(__GNUC__) || __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 3))
#define ZMQ_EXTENDED_CONSTEXPR
#define ZMQ_EXTENDED_CONSTEXPR constexpr
#endif
#if defined(ZMQ_CPP17)
#define ZMQ_INLINE_VAR inline
Expand Down Expand Up @@ -308,7 +308,7 @@ class error_t : public std::exception
{
return zmq_strerror(errnum);
}
int num() const ZMQ_NOTHROW { return errnum; }
ZMQ_CONSTEXPR_FN int num() const ZMQ_NOTHROW { return errnum; }

private:
int errnum;
Expand Down Expand Up @@ -751,8 +751,18 @@ class message_t
std::swap(msg, other.msg);
}

#ifdef ZMQ_EXTENDED_CONSTEXPR
ZMQ_NODISCARD ZMQ_EXTENDED_CONSTEXPR zmq_msg_t *handle() ZMQ_NOTHROW
{
return &msg;
}
#else
ZMQ_NODISCARD zmq_msg_t *handle() ZMQ_NOTHROW { return &msg; }
ZMQ_NODISCARD const zmq_msg_t *handle() const ZMQ_NOTHROW { return &msg; }
#endif
ZMQ_NODISCARD ZMQ_CONSTEXPR_FN const zmq_msg_t *handle() const ZMQ_NOTHROW
{
return &msg;
}

private:
// The underlying message
Expand Down Expand Up @@ -910,14 +920,25 @@ class context_t
// Be careful with this, it's probably only useful for
// using the C api together with an existing C++ api.
// Normally you should never need to use this.
#ifdef ZMQ_EXTENDED_CONSTEXPR
ZMQ_EXPLICIT ZMQ_EXTENDED_CONSTEXPR operator void *() ZMQ_NOTHROW { return ptr; }
#else
ZMQ_EXPLICIT operator void *() ZMQ_NOTHROW { return ptr; }
#endif

ZMQ_EXPLICIT operator void const *() const ZMQ_NOTHROW { return ptr; }
ZMQ_EXPLICIT ZMQ_CONSTEXPR_FN operator void const *() const ZMQ_NOTHROW
{
return ptr;
}

#ifdef ZMQ_EXTENDED_CONSTEXPR
ZMQ_NODISCARD ZMQ_EXTENDED_CONSTEXPR void *handle() ZMQ_NOTHROW { return ptr; }
#else
ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return ptr; }
#endif

ZMQ_DEPRECATED("from 4.7.0, use handle() != nullptr instead")
operator bool() const ZMQ_NOTHROW { return ptr != ZMQ_NULLPTR; }
ZMQ_CONSTEXPR_FN operator bool() const ZMQ_NOTHROW { return ptr != ZMQ_NULLPTR; }

void swap(context_t &other) ZMQ_NOTHROW { std::swap(ptr, other.ptr); }

Expand All @@ -940,7 +961,7 @@ struct recv_buffer_size
size_t size; // number of bytes written to buffer
size_t untruncated_size; // untruncated message size in bytes

ZMQ_NODISCARD bool truncated() const noexcept
ZMQ_NODISCARD ZMQ_CONSTEXPR_FN bool truncated() const noexcept
{
return size != untruncated_size;
}
Expand All @@ -965,7 +986,10 @@ template<class T> class trivial_optional
using value_type = T;

trivial_optional() = default;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ZMQ_CONSTEXPR_FN also?

trivial_optional(T value) noexcept : _value(value), _has_value(true) {}
ZMQ_CONSTEXPR_FN trivial_optional(T value) noexcept :
_value(value), _has_value(true)
{
}

const T *operator->() const noexcept
{
Expand Down Expand Up @@ -1002,8 +1026,8 @@ template<class T> class trivial_optional
return _value;
}

explicit operator bool() const noexcept { return _has_value; }
bool has_value() const noexcept { return _has_value; }
ZMQ_CONSTEXPR_FN explicit operator bool() const noexcept { return _has_value; }
ZMQ_CONSTEXPR_FN bool has_value() const noexcept { return _has_value; }

private:
T _value{};
Expand Down Expand Up @@ -1765,8 +1789,11 @@ namespace detail
class socket_base
{
public:
socket_base() ZMQ_NOTHROW : _handle(ZMQ_NULLPTR) {}
ZMQ_EXPLICIT socket_base(void *handle) ZMQ_NOTHROW : _handle(handle) {}
ZMQ_CONSTEXPR_FN socket_base() ZMQ_NOTHROW : _handle(ZMQ_NULLPTR) {}
ZMQ_EXPLICIT ZMQ_CONSTEXPR_FN socket_base(void *handle) ZMQ_NOTHROW
: _handle(handle)
{
}

template<typename T>
ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt")
Expand Down Expand Up @@ -1948,7 +1975,10 @@ class socket_base
}

ZMQ_DEPRECATED("from 4.7.1, use handle() != nullptr or operator bool")
bool connected() const ZMQ_NOTHROW { return (_handle != ZMQ_NULLPTR); }
ZMQ_CONSTEXPR_FN bool connected() const ZMQ_NOTHROW
{
return (_handle != ZMQ_NULLPTR);
}

ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking a const_buffer and send_flags")
size_t send(const void *buf_, size_t len_, int flags_ = 0)
Expand Down Expand Up @@ -2120,13 +2150,33 @@ class socket_base
}
#endif

#ifdef ZMQ_EXTENDED_CONSTEXPR
ZMQ_NODISCARD ZMQ_EXTENDED_CONSTEXPR void *handle() ZMQ_NOTHROW
{
return _handle;
}
#else
ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return _handle; }
ZMQ_NODISCARD const void *handle() const ZMQ_NOTHROW { return _handle; }
#endif
ZMQ_NODISCARD ZMQ_CONSTEXPR_FN const void *handle() const ZMQ_NOTHROW
{
return _handle;
}

ZMQ_EXPLICIT operator bool() const ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; }
ZMQ_EXPLICIT ZMQ_CONSTEXPR_FN operator bool() const ZMQ_NOTHROW
{
return _handle != ZMQ_NULLPTR;
}
// note: non-const operator bool can be removed once
// operator void* is removed from socket_t
ZMQ_EXPLICIT operator bool() ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; }
#ifdef ZMQ_EXTENDED_CONSTEXPR
ZMQ_EXPLICIT ZMQ_EXTENDED_CONSTEXPR operator bool() ZMQ_NOTHROW
#else
ZMQ_EXPLICIT operator bool() ZMQ_NOTHROW
#endif
{
return _handle != ZMQ_NULLPTR;
}

protected:
void *_handle;
Expand Down Expand Up @@ -2164,42 +2214,48 @@ ZMQ_CONSTEXPR_VAR from_handle_t from_handle =
class socket_ref : public detail::socket_base
{
public:
socket_ref() ZMQ_NOTHROW : detail::socket_base() {}
ZMQ_CONSTEXPR_FN socket_ref() ZMQ_NOTHROW : detail::socket_base() {}
#ifdef ZMQ_CPP11
socket_ref(std::nullptr_t) ZMQ_NOTHROW : detail::socket_base() {}
ZMQ_CONSTEXPR_FN socket_ref(std::nullptr_t) ZMQ_NOTHROW : detail::socket_base()
{
}
#endif
socket_ref(from_handle_t /*fh*/, void *handle) ZMQ_NOTHROW
ZMQ_CONSTEXPR_FN socket_ref(from_handle_t /*fh*/, void *handle) ZMQ_NOTHROW
: detail::socket_base(handle)
{
}
};

#ifdef ZMQ_CPP11
inline bool operator==(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW
inline ZMQ_CONSTEXPR_FN bool operator==(const socket_ref sr,
std::nullptr_t /*p*/) ZMQ_NOTHROW
{
return sr.handle() == nullptr;
}
inline bool operator==(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW
inline ZMQ_CONSTEXPR_FN bool operator==(std::nullptr_t /*p*/,
const socket_ref sr) ZMQ_NOTHROW
{
return sr.handle() == nullptr;
}
inline bool operator!=(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW
inline ZMQ_CONSTEXPR_FN bool operator!=(const socket_ref sr,
std::nullptr_t /*p*/) ZMQ_NOTHROW
{
return !(sr == nullptr);
}
inline bool operator!=(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW
inline ZMQ_CONSTEXPR_FN bool operator!=(std::nullptr_t /*p*/,
const socket_ref sr) ZMQ_NOTHROW
{
return !(sr == nullptr);
}
#endif

inline bool operator==(const detail::socket_base &a,
const detail::socket_base &b) ZMQ_NOTHROW
inline ZMQ_CONSTEXPR_FN bool operator==(const detail::socket_base &a,
const detail::socket_base &b) ZMQ_NOTHROW
{
return std::equal_to<const void *>()(a.handle(), b.handle());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

keep this to avoid UB

return a.handle() == b.handle();
}
inline bool operator!=(const detail::socket_base &a,
const detail::socket_base &b) ZMQ_NOTHROW
inline ZMQ_CONSTEXPR_FN bool operator!=(const detail::socket_base &a,
const detail::socket_base &b) ZMQ_NOTHROW
{
return !(a == b);
}
Expand Down Expand Up @@ -2281,9 +2337,13 @@ class socket_t : public detail::socket_base

~socket_t() ZMQ_NOTHROW { close(); }

#ifdef ZMQ_EXTENDED_CONSTEXPR
ZMQ_EXTENDED_CONSTEXPR operator void *() ZMQ_NOTHROW { return _handle; }
#else
operator void *() ZMQ_NOTHROW { return _handle; }
#endif

operator void const *() const ZMQ_NOTHROW { return _handle; }
ZMQ_CONSTEXPR_FN operator void const *() const ZMQ_NOTHROW { return _handle; }

void close() ZMQ_NOTHROW
{
Expand Down
Loading