You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2017/01/03 22:02:46 UTC

[14/30] qpid-proton git commit: PROTON-1372: [C++ binding] Pimpl event_loop - To make sure that we maintain C++03/C++11 cross compatibility.

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 <as...@apache.org>
Authored: Thu Dec 8 03:25:57 2016 -0500
Committer: Andrew Stitcher <as...@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-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org