PROTON-1288: c++ hide proton::message implementation details Hide extra book-keeping types in extra storage allocated with the pn_message_t. Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/48a5e47a Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/48a5e47a Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/48a5e47a Branch: refs/heads/master Commit: 48a5e47a09268ddb19f925d8f66301718f42b87a Parents: 860b322 Author: Alan Conway Authored: Wed May 17 13:52:13 2017 -0400 Committer: Alan Conway Committed: Wed May 24 14:38:25 2017 -0400 ---------------------------------------------------------------------- .../bindings/cpp/include/proton/message.hpp | 6 +- proton-c/bindings/cpp/src/message.cpp | 74 +++++++++++++------- 2 files changed, 52 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/48a5e47a/proton-c/bindings/cpp/include/proton/message.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/message.hpp b/proton-c/bindings/cpp/include/proton/message.hpp index ff60c99..faf2f29 100644 --- a/proton-c/bindings/cpp/include/proton/message.hpp +++ b/proton-c/bindings/cpp/include/proton/message.hpp @@ -321,13 +321,11 @@ class message { /// @cond INTERNAL private: + struct impl; pn_message_t *pn_msg() const; + struct impl& impl() const; mutable pn_message_t *pn_msg_; - mutable value body_; - mutable property_map application_properties_; - mutable annotation_map message_annotations_; - mutable annotation_map delivery_annotations_; /// Decode the message corresponding to a delivery from a link. void decode(proton::delivery); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/48a5e47a/proton-c/bindings/cpp/src/message.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/message.cpp b/proton-c/bindings/cpp/src/message.cpp index 59f8329..df7fae1 100644 --- a/proton-c/bindings/cpp/src/message.cpp +++ b/proton-c/bindings/cpp/src/message.cpp @@ -41,6 +41,32 @@ namespace proton { +struct message::impl { + value body_; + property_map application_properties_; + annotation_map message_annotations_; + annotation_map delivery_annotations_; + + impl(pn_message_t *msg) { + body_.reset(pn_message_body(msg)); + } + + void clear() { + application_properties_.clear(); + message_annotations_.clear(); + delivery_annotations_.clear(); + } + + friend void swap(impl& x, impl& y) { + using std::swap; + swap(x.body_, y.body_); + swap(x.application_properties_, y.application_properties_); + swap(x.message_annotations_, y.message_annotations_); + swap(x.delivery_annotations_, y.delivery_annotations_); + } +}; + + message::message() : pn_msg_(0) {} message::message(const message &m) : pn_msg_(0) { *this = m; } @@ -55,28 +81,31 @@ message& message::operator=(message&& m) { message::message(const value& x) : pn_msg_(0) { body() = x; } message::~message() { - // Workaround proton bug: Must release all refs to body before calling pn_message_free() - body_.reset(); - pn_message_free(pn_msg_); + if (pn_msg_) { + impl().~impl(); // destroy in-place + pn_message_free(pn_msg_); + } } void swap(message& x, message& y) { using std::swap; swap(x.pn_msg_, y.pn_msg_); - swap(x.body_, y.body_); - swap(x.application_properties_, y.application_properties_); - swap(x.message_annotations_, y.message_annotations_); - swap(x.delivery_annotations_, y.delivery_annotations_); + swap(x.impl(), y.impl()); } pn_message_t *message::pn_msg() const { if (!pn_msg_) { - pn_msg_ = pn_message(); - body_.reset(pn_message_body(pn_msg_)); + pn_msg_ = pn_message_with_extra(sizeof(struct message::impl)); + // Construct impl in extra storage allocated with pn_msg_ + new (pn_message_get_extra(pn_msg_)) struct message::impl(pn_msg_); } return pn_msg_; } +struct message::impl& message::impl() const { + return *(struct message::impl*)pn_message_get_extra(pn_msg()); +} + message& message::operator=(const message& m) { if (&m != this) { // TODO aconway 2015-08-10: more efficient pn_message_copy function @@ -209,8 +238,8 @@ void message::inferred(bool b) { pn_message_set_inferred(pn_msg(), b); } void message::body(const value& x) { body() = x; } -const value& message::body() const { pn_msg(); return body_; } -value& message::body() { pn_msg(); return body_; } +const value& message::body() const { return impl().body_; } +value& message::body() { return impl().body_; } // MAP CACHING: the properties and annotations maps can either be encoded in the // pn_message pn_data_t structures OR decoded as C++ map members of the message @@ -239,35 +268,35 @@ template M& put_map(pn_message_t* msg, F get, M& map) { } message::property_map& message::properties() { - return get_map(pn_msg(), pn_message_properties, application_properties_); + return get_map(pn_msg(), pn_message_properties, impl().application_properties_); } const message::property_map& message::properties() const { - return get_map(pn_msg(), pn_message_properties, application_properties_); + return get_map(pn_msg(), pn_message_properties, impl().application_properties_); } message::annotation_map& message::message_annotations() { - return get_map(pn_msg(), pn_message_annotations, message_annotations_); + return get_map(pn_msg(), pn_message_annotations, impl().message_annotations_); } const message::annotation_map& message::message_annotations() const { - return get_map(pn_msg(), pn_message_annotations, message_annotations_); + return get_map(pn_msg(), pn_message_annotations, impl().message_annotations_); } message::annotation_map& message::delivery_annotations() { - return get_map(pn_msg(), pn_message_instructions, delivery_annotations_); + return get_map(pn_msg(), pn_message_instructions, impl().delivery_annotations_); } const message::annotation_map& message::delivery_annotations() const { - return get_map(pn_msg(), pn_message_instructions, delivery_annotations_); + return get_map(pn_msg(), pn_message_instructions, impl().delivery_annotations_); } void message::encode(std::vector &s) const { - put_map(pn_msg(), pn_message_properties, application_properties_); - put_map(pn_msg(), pn_message_annotations, message_annotations_); - put_map(pn_msg(), pn_message_instructions, delivery_annotations_); + put_map(pn_msg(), pn_message_properties, impl().application_properties_); + put_map(pn_msg(), pn_message_annotations, impl().message_annotations_); + put_map(pn_msg(), pn_message_instructions, impl().delivery_annotations_); size_t sz = std::max(s.capacity(), size_t(512)); while (true) { s.resize(sz); @@ -293,10 +322,7 @@ std::vector message::encode() const { void message::decode(const std::vector &s) { if (s.empty()) throw error("message decode: no data"); - application_properties_.clear(); - message_annotations_.clear(); - delivery_annotations_.clear(); - assert(!s.empty()); + impl().clear(); check(pn_message_decode(pn_msg(), &s[0], s.size())); } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org For additional commands, e-mail: commits-help@qpid.apache.org