PROTON-1372: [C++ binding] Pimpl event_loop - To make sure that we maintain C++03/C++11 cross compatibility.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/f89d24d8 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/f89d24d8 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/f89d24d8 Branch: refs/heads/go1 Commit: f89d24d855fe684d97ef640235a04afdbb08c885 Parents: bea6173 Author: Andrew Stitcher <astitc...@apache.org> Authored: Thu Dec 8 03:25:57 2016 -0500 Committer: Andrew Stitcher <astitc...@apache.org> Committed: Thu Dec 8 03:49:58 2016 -0500 ---------------------------------------------------------------------- .../bindings/cpp/include/proton/event_loop.hpp | 38 ++++++++++++++----- .../cpp/include/proton/internal/config.hpp | 4 ++ .../cpp/include/proton/internal/object.hpp | 2 +- .../cpp/include/proton/io/connection_driver.hpp | 5 ++- .../bindings/cpp/include/proton/thread_safe.hpp | 23 ++++++------ proton-c/bindings/cpp/src/container_impl.cpp | 27 ++++++-------- proton-c/bindings/cpp/src/event_loop.cpp | 28 +++++++++++--- proton-c/bindings/cpp/src/include/contexts.hpp | 2 +- .../cpp/src/include/event_loop_impl.hpp | 39 ++++++++++++++++++++ .../bindings/cpp/src/io/connection_driver.cpp | 12 +++++- proton-c/bindings/cpp/src/thread_safe_test.cpp | 4 +- 11 files changed, 135 insertions(+), 49 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/include/proton/event_loop.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/event_loop.hpp b/proton-c/bindings/cpp/include/proton/event_loop.hpp index d43ba4f..f49d211 100644 --- a/proton-c/bindings/cpp/include/proton/event_loop.hpp +++ b/proton-c/bindings/cpp/include/proton/event_loop.hpp @@ -25,6 +25,7 @@ #include "./fwd.hpp" #include "./internal/config.hpp" #include "./internal/export.hpp" +#include "./internal/pn_unique_ptr.hpp" #include <functional> @@ -41,31 +42,48 @@ namespace proton { /// and have it executed in the same sequence. /// class PN_CPP_CLASS_EXTERN event_loop { + /// @cond internal + class impl; + event_loop& operator=(impl* i); + /// @endcond + public: - virtual ~event_loop() {} + /// Create event_loop + PN_CPP_EXTERN event_loop(); + + PN_CPP_EXTERN ~event_loop(); + +#if PN_CPP_HAS_EXPLICIT_CONVERSIONS + /// When using C++11 (or later) you can use event_loop in a bool context + /// to indicate if there is an event loop set. + PN_CPP_EXTERN explicit operator bool() const { return bool(impl_); } +#endif + + /// No event loop set. + PN_CPP_EXTERN bool operator !() const { return !impl_; } /// Arrange to have f() called in the event_loop's sequence: possibly /// deferred, possibly in another thread. /// /// @return true if f() has or will be called, false if the event_loop is ended /// and f() cannot be injected. - virtual bool inject(void_function0& f) = 0; + PN_CPP_EXTERN bool inject(void_function0& f); #if PN_CPP_HAS_STD_FUNCTION /// @copydoc inject(void_function0&) - virtual bool inject(std::function<void()> f) = 0; + PN_CPP_EXTERN bool inject(std::function<void()> f); #endif - protected: - event_loop() {} - private: - PN_CPP_EXTERN static event_loop* get(pn_connection_t*); - PN_CPP_EXTERN static event_loop* get(pn_session_t*); - PN_CPP_EXTERN static event_loop* get(pn_link_t*); + PN_CPP_EXTERN static event_loop& get(pn_connection_t*); + PN_CPP_EXTERN static event_loop& get(pn_session_t*); + PN_CPP_EXTERN static event_loop& get(pn_link_t*); + + internal::pn_unique_ptr<impl> impl_; /// @cond INTERNAL - friend class connection; + friend class container; + friend class io::connection_driver; template <class T> friend class thread_safe; /// @endcond }; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/include/proton/internal/config.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/internal/config.hpp b/proton-c/bindings/cpp/include/proton/internal/config.hpp index 612e1e3..563a304 100644 --- a/proton-c/bindings/cpp/include/proton/internal/config.hpp +++ b/proton-c/bindings/cpp/include/proton/internal/config.hpp @@ -87,6 +87,10 @@ #define PN_CPP_HAS_STD_FUNCTION PN_CPP_HAS_CPP11 #endif +#ifndef PN_CPP_HAS_STD_BIND +#define PN_CPP_HAS_STD_BIND PN_CPP_HAS_CPP11 +#endif + #ifndef PN_CPP_HAS_CHRONO #define PN_CPP_HAS_CHRONO PN_CPP_HAS_CPP11 #endif http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/include/proton/internal/object.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/internal/object.hpp b/proton-c/bindings/cpp/include/proton/internal/object.hpp index 78a990c..d492b80 100644 --- a/proton-c/bindings/cpp/include/proton/internal/object.hpp +++ b/proton-c/bindings/cpp/include/proton/internal/object.hpp @@ -101,7 +101,7 @@ template <class T> class object : private comparable<object<T> > { friend bool operator==(const object& a, const object& b) { return a.object_ == b.object_; } friend bool operator<(const object& a, const object& b) { return a.object_ < b.object_; } friend std::ostream& operator<<(std::ostream& o, const object& a) { o << a.object_.inspect(); return o; } - template <class U> friend class proton::thread_safe; + template <class U> friend class proton::thread_safe; }; /// Factory class used internally to make wrappers and extract proton objects http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp index d5da718..4a0efe9 100644 --- a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp +++ b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp @@ -111,7 +111,10 @@ PN_CPP_CLASS_EXTERN connection_driver { /// the user pins it in memory using the proton::thread_safe<> template. /// The event_loop is deleted when, and only when, the proton::connection is. /// - PN_CPP_EXTERN connection_driver(proton::container&, event_loop* loop = 0); + PN_CPP_EXTERN connection_driver(proton::container&); +#if PN_CPP_HAS_RVALUE_REFERENCES + PN_CPP_EXTERN connection_driver(proton::container&, event_loop&& loop); +#endif PN_CPP_EXTERN ~connection_driver(); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/include/proton/thread_safe.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/thread_safe.hpp b/proton-c/bindings/cpp/include/proton/thread_safe.hpp index 28aa3a6..608a1ca 100644 --- a/proton-c/bindings/cpp/include/proton/thread_safe.hpp +++ b/proton-c/bindings/cpp/include/proton/thread_safe.hpp @@ -43,8 +43,6 @@ template<> struct endpoint_traits<sender> {}; template<> struct endpoint_traits<receiver> {}; } -template <class T> class returned; - /// **Experimental** - A thread-safe object wrapper. /// /// The proton::object subclasses (proton::connection, proton::sender etc.) are @@ -78,11 +76,11 @@ class thread_safe : private internal::pn_ptr_base, private internal::endpoint_tr ~thread_safe() { if (ptr()) { - if (event_loop()) { -#if PN_CPP_HAS_CPP11 - event_loop()->inject(std::bind(&decref, ptr())); + if (!!event_loop()) { +#if PN_CPP_HAS_STD_BIND + event_loop().inject(std::bind(&decref, ptr())); #else - event_loop()->inject(*new inject_decref(ptr())); + event_loop().inject(*new inject_decref(ptr())); #endif } else { decref(ptr()); @@ -91,7 +89,7 @@ class thread_safe : private internal::pn_ptr_base, private internal::endpoint_tr } /// Get the event loop for this object. - class event_loop* event_loop() { return event_loop::get(ptr()); } + class event_loop& event_loop() { return event_loop::get(ptr()); } /// Get the thread-unsafe proton object wrapped by this thread_safe<T> T unsafe() { return T(ptr()); } @@ -140,12 +138,13 @@ class returned : private internal::endpoint_traits<T> /// Implicit conversion to target, usable only in a safe context. operator T() { return ptr_->unsafe(); } -#if PN_CPP_HAS_CPP11 +#if PN_CPP_HAS_SHARED_PTR /// Release to a std::shared_ptr operator std::shared_ptr<thread_safe<T> >() { return std::shared_ptr<thread_safe<T> >(release()); } - +#endif +#if PN_CPP_HAS_UNIQUE_PTR /// Release to a std::unique_ptr operator std::unique_ptr<thread_safe<T> >() { return std::unique_ptr<thread_safe<T> >(release()); @@ -160,13 +159,13 @@ class returned : private internal::endpoint_traits<T> /// Make a thread-safe wrapper for `obj`. template <class T> returned<T> make_thread_safe(const T& obj) { return returned<T>(obj); } -#if PN_CPP_HAS_CPP11 - +#if PN_CPP_HAS_SHARED_PTR /// Create a thread-safe shared_ptr to `obj`. template <class T> std::shared_ptr<thread_safe<T> > make_shared_thread_safe(const T& obj) { return make_thread_safe(obj); } - +#endif +#if PN_CPP_HAS_UNIQUE_PTR /// Create a thread-safe unique_ptr to `obj`. template <class T> std::unique_ptr<thread_safe<T> > make_unique_thread_safe(const T& obj) { return make_thread_safe(obj); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/src/container_impl.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/container_impl.cpp b/proton-c/bindings/cpp/src/container_impl.cpp index 5f13b82..9cec831 100644 --- a/proton-c/bindings/cpp/src/container_impl.cpp +++ b/proton-c/bindings/cpp/src/container_impl.cpp @@ -38,6 +38,7 @@ #include "connector.hpp" #include "container_impl.hpp" #include "contexts.hpp" +#include "event_loop_impl.hpp" #include "messaging_adapter.hpp" #include "msg.hpp" #include "proton_bits.hpp" @@ -160,24 +161,20 @@ container::impl::~impl() { close_acceptor(i->second); } -namespace { // FIXME aconway 2016-06-07: this is not thread safe. It is sufficient for using // default_container::schedule() inside a handler but not for inject() from // another thread. -struct immediate_event_loop : public event_loop { - virtual bool inject(void_function0& f) PN_CPP_OVERRIDE { - try { f(); } catch(...) {} - return true; - } +bool event_loop::impl::inject(void_function0& f) { + try { f(); } catch(...) {} + return true; +} -#if PN_CPP_HAS_CPP11 - virtual bool inject(std::function<void()> f) PN_CPP_OVERRIDE { - try { f(); } catch(...) {} - return true; - } -#endif -}; +#if PN_CPP_HAS_STD_FUNCTION +bool event_loop::impl::inject(std::function<void()> f) { + try { f(); } catch(...) {} + return true; } +#endif returned<connection> container::impl::connect(const std::string &urlstr, const connection_options &user_opts) { connection_options opts = client_connection_options(); // Defaults @@ -195,7 +192,7 @@ returned<connection> container::impl::connect(const std::string &urlstr, const c internal::pn_unique_ptr<connector> ctor(new connector(conn, opts, url)); connection_context& cc(connection_context::get(conn)); cc.handler.reset(ctor.release()); - cc.event_loop.reset(new immediate_event_loop); + cc.event_loop_ = new event_loop::impl; pn_connection_t *pnc = unwrap(conn); pn_connection_set_container(pnc, id_.c_str()); @@ -347,7 +344,7 @@ void container::impl::configure_server_connection(connection &c) { pn_record_t *record = pn_connection_attachments(unwrap(c)); pn_record_set_handler(record, chandler.get()); } - connection_context::get(c).event_loop.reset(new immediate_event_loop); + connection_context::get(c).event_loop_ = new event_loop::impl; } void container::impl::run() { http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/src/event_loop.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/event_loop.cpp b/proton-c/bindings/cpp/src/event_loop.cpp index 3d373c4..ea4ee71 100644 --- a/proton-c/bindings/cpp/src/event_loop.cpp +++ b/proton-c/bindings/cpp/src/event_loop.cpp @@ -17,24 +17,40 @@ * under the License. */ +#include "proton/event_loop.hpp" + #include "contexts.hpp" +#include "event_loop_impl.hpp" #include <proton/session.h> #include <proton/link.h> -#include "proton/event_loop.hpp" - namespace proton { -event_loop* event_loop::get(pn_connection_t* c) { - return connection_context::get(c).event_loop.get(); +event_loop::event_loop() {} +event_loop::~event_loop() {} + +event_loop& event_loop::operator=(impl* i) { impl_.reset(i); return *this; } + +bool event_loop::inject(void_function0& f) { + return impl_->inject(f); +} + +#if PN_CPP_HAS_STD_FUNCTION +bool event_loop::inject(std::function<void()> f) { + return impl_->inject(f); +} +#endif + +event_loop& event_loop::get(pn_connection_t* c) { + return connection_context::get(c).event_loop_; } -event_loop* event_loop::get(pn_session_t* s) { +event_loop& event_loop::get(pn_session_t* s) { return get(pn_session_connection(s)); } -event_loop* event_loop::get(pn_link_t* l) { +event_loop& event_loop::get(pn_link_t* l) { return get(pn_link_session(l)); } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/src/include/contexts.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/include/contexts.hpp b/proton-c/bindings/cpp/src/include/contexts.hpp index 4306489..e80c434 100644 --- a/proton-c/bindings/cpp/src/include/contexts.hpp +++ b/proton-c/bindings/cpp/src/include/contexts.hpp @@ -93,7 +93,7 @@ class connection_context : public context { io::link_namer* link_gen; // Link name generator. internal::pn_unique_ptr<proton_handler> handler; - internal::pn_unique_ptr<class event_loop> event_loop; + event_loop event_loop_; static connection_context& get(pn_connection_t *c) { return ref<connection_context>(id(c)); } static connection_context& get(const connection& c) { return ref<connection_context>(id(c)); } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/src/include/event_loop_impl.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/include/event_loop_impl.hpp b/proton-c/bindings/cpp/src/include/event_loop_impl.hpp new file mode 100644 index 0000000..b34a981 --- /dev/null +++ b/proton-c/bindings/cpp/src/include/event_loop_impl.hpp @@ -0,0 +1,39 @@ +#ifndef PROTON_CPP_EVENT_LOOP_IMPL_HPP +#define PROTON_CPP_EVENT_LOOP_IMPL_HPP + +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include "proton/fwd.hpp" + +namespace proton { + +class event_loop::impl { + public: + bool inject(void_function0& f); +#if PN_CPP_HAS_CPP11 + bool inject(std::function<void()> f); +#endif +}; + +} + +#endif // PROTON_CPP_EVENT_LOOP_IMPL_HPP http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/src/io/connection_driver.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/io/connection_driver.cpp b/proton-c/bindings/cpp/src/io/connection_driver.cpp index ca9f68e..148a00b 100644 --- a/proton-c/bindings/cpp/src/io/connection_driver.cpp +++ b/proton-c/bindings/cpp/src/io/connection_driver.cpp @@ -49,13 +49,21 @@ void connection_driver::init() { connection_driver::connection_driver() : handler_(0), container_(0) { init(); } -connection_driver::connection_driver(class container& cont, event_loop* loop) : handler_(0), container_(&cont) { +connection_driver::connection_driver(class container& cont) : handler_(0), container_(&cont) { init(); connection_context& ctx = connection_context::get(connection()); ctx.container = container_; - ctx.event_loop.reset(loop); } +#if PN_CPP_HAS_RVALUE_REFERENCES +connection_driver::connection_driver(class container& cont, event_loop&& loop) : handler_(0), container_(&cont) { + init(); + connection_context& ctx = connection_context::get(connection()); + ctx.container = container_; + ctx.event_loop_ = loop.impl_.get(); +} +#endif + connection_driver::~connection_driver() { pn_connection_driver_destroy(&driver_); } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f89d24d8/proton-c/bindings/cpp/src/thread_safe_test.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/thread_safe_test.cpp b/proton-c/bindings/cpp/src/thread_safe_test.cpp index 5b5d487..3a72f7f 100644 --- a/proton-c/bindings/cpp/src/thread_safe_test.cpp +++ b/proton-c/bindings/cpp/src/thread_safe_test.cpp @@ -50,7 +50,7 @@ void test_new() { ASSERT_EQUAL(1, pn_refcount(c)); // Engine gone, thread_safe keeping c alive. delete p; -#if PN_CPP_HAS_CPP11 +#if PN_CPP_HAS_SHARED_PTR { std::shared_ptr<thread_safe<connection> > sp; { @@ -60,6 +60,8 @@ void test_new() { } ASSERT_EQUAL(1, pn_refcount(c)); // Engine gone, sp keeping c alive. } +#endif +#if PN_CPP_HAS_UNIQUE_PTR { std::unique_ptr<thread_safe<connection> > up; { --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org