moar CRTP to minimize copypasta for inbound/outbound handlers
authorJames Sedgwick <jsedgwick@fb.com>
Thu, 30 Apr 2015 00:56:02 +0000 (17:56 -0700)
committerPraveen Kumar Ramakrishnan <praveenr@fb.com>
Tue, 12 May 2015 00:01:01 +0000 (17:01 -0700)
Summary:
I think this is the best I can do to minimize whjat must be copied for InboundHandler, InboundHandlerContext, InboundContextImpl, outbound equivalents, etc

Test Plan: unit

Reviewed By: davejwatson@fb.com

Subscribers: fugalh, folly-diffs@, jsedgwick, yfeldblum, chalfant

FB internal diff: D2025612

Tasks: 6836580

Signature: t1:2025612:1430346200:bc06162711bbc52b17574297a3569736f7973a7c

folly/wangle/channel/Handler.h
folly/wangle/channel/HandlerContext.h
folly/wangle/channel/Pipeline.h

index 05632e3609b256b67e3b0f581a987ce5ee279448..73d59a641e2942bcc021df9d8957b92bac0c314d 100644 (file)
@@ -43,7 +43,7 @@ class HandlerBase {
   }
 
  private:
-  friend detail::HandlerContextBase<Context>;
+  friend PipelineContext;
   uint64_t attachCount_{0};
   Context* ctx_{nullptr};
 };
index 77762d8cf08b8401dac082fa77aa8e1c5119d598..4bd79f5f05ed8811871ced06015c5ae5dc7a1b6c 100644 (file)
 
 namespace folly { namespace wangle {
 
-namespace detail {
-
-template <class HandlerContext>
-class HandlerContextBase {
- protected:
-  template <class H>
-  void attachContext(H* handler, HandlerContext* ctx) {
-    if (++handler->attachCount_ == 1) {
-      handler->ctx_ = ctx;
-    } else {
-      handler->ctx_ = nullptr;
-    }
-  }
-};
-
-} // detail
-
 template <class In, class Out>
-class HandlerContext
-  : public detail::HandlerContextBase<HandlerContext<In, Out>> {
+class HandlerContext {
  public:
   virtual ~HandlerContext() {}
 
@@ -83,6 +65,15 @@ class PipelineContext {
   virtual void attachTransport() = 0;
   virtual void detachTransport() = 0;
 
+  template <class H, class HandlerContext>
+  void attachContext(H* handler, HandlerContext* ctx) {
+    if (++handler->attachCount_ == 1) {
+      handler->ctx_ = ctx;
+    } else {
+      handler->ctx_ = nullptr;
+    }
+  }
+
   void link(PipelineContext* other) {
     setNextIn(other);
     other->setNextOut(this);
@@ -94,68 +85,62 @@ class PipelineContext {
 };
 
 template <class In>
-class InboundHandlerContext {
+class InboundLink {
  public:
-  virtual ~InboundHandlerContext() {}
+  virtual ~InboundLink() {}
   virtual void read(In msg) = 0;
   virtual void readEOF() = 0;
   virtual void readException(exception_wrapper e) = 0;
 };
 
 template <class Out>
-class OutboundHandlerContext {
+class OutboundLink {
  public:
-  virtual ~OutboundHandlerContext() {}
+  virtual ~OutboundLink() {}
   virtual Future<void> write(Out msg) = 0;
   virtual Future<void> close() = 0;
 };
 
-template <class P, class H>
-class ContextImpl : public HandlerContext<typename H::rout,
-                                                 typename H::wout>,
-                    public InboundHandlerContext<typename H::rin>,
-                    public OutboundHandlerContext<typename H::win>,
-                    public PipelineContext {
+template <class P, class H, class Context>
+class ContextImplBase : public PipelineContext {
  public:
-  typedef typename H::rin Rin;
-  typedef typename H::rout Rout;
-  typedef typename H::win Win;
-  typedef typename H::wout Wout;
+  ~ContextImplBase() {}
 
-  explicit ContextImpl(P* pipeline, std::shared_ptr<H> handler) {
-    initialize(pipeline, std::move(handler));
+  H* getHandler() {
+    return handler_.get();
   }
 
-  // For StaticPipeline
-  ContextImpl() {}
-
-  ~ContextImpl() {}
-
   void initialize(P* pipeline, std::shared_ptr<H> handler) {
     pipeline_ = pipeline;
     handler_ = std::move(handler);
   }
 
-  H* getHandler() {
-    return handler_.get();
-  }
-
   // PipelineContext overrides
   void attachPipeline() override {
     if (!attached_) {
-      this->attachContext(handler_.get(), this);
-      handler_->attachPipeline(this);
+      this->attachContext(handler_.get(), impl_);
+      handler_->attachPipeline(impl_);
       attached_ = true;
     }
   }
 
   void detachPipeline() override {
-    handler_->detachPipeline(this);
+    handler_->detachPipeline(impl_);
     attached_ = false;
   }
 
+  void attachTransport() override {
+    DestructorGuard dg(pipeline_);
+    handler_->attachTransport(impl_);
+  }
+
+  void detachTransport() override {
+    DestructorGuard dg(pipeline_);
+    handler_->detachTransport(impl_);
+  }
+
   void setNextIn(PipelineContext* ctx) override {
-    auto nextIn = dynamic_cast<InboundHandlerContext<Rout>*>(ctx);
+    auto nextIn = dynamic_cast<InboundLink<typename H::rout>*>(ctx);
     if (nextIn) {
       nextIn_ = nextIn;
     } else {
@@ -164,7 +149,7 @@ class ContextImpl : public HandlerContext<typename H::rout,
   }
 
   void setNextOut(PipelineContext* ctx) override {
-    auto nextOut = dynamic_cast<OutboundHandlerContext<Wout>*>(ctx);
+    auto nextOut = dynamic_cast<OutboundLink<typename H::wout>*>(ctx);
     if (nextOut) {
       nextOut_ = nextOut;
     } else {
@@ -172,48 +157,74 @@ class ContextImpl : public HandlerContext<typename H::rout,
     }
   }
 
-  void attachTransport() override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    handler_->attachTransport(this);
+ protected:
+  Context* impl_;
+  P* pipeline_;
+  std::shared_ptr<H> handler_;
+  InboundLink<typename H::rout>* nextIn_{nullptr};
+  OutboundLink<typename H::wout>* nextOut_{nullptr};
+
+ private:
+  bool attached_{false};
+  using DestructorGuard = typename P::DestructorGuard;
+};
+
+template <class P, class H>
+class ContextImpl : public HandlerContext<typename H::rout,
+                                                 typename H::wout>,
+                    public InboundLink<typename H::rin>,
+                    public OutboundLink<typename H::win>,
+                    public ContextImplBase<P, H, HandlerContext<typename H::rout, typename H::wout>> {
+ public:
+  typedef typename H::rin Rin;
+  typedef typename H::rout Rout;
+  typedef typename H::win Win;
+  typedef typename H::wout Wout;
+
+  explicit ContextImpl(P* pipeline, std::shared_ptr<H> handler) {
+    this->impl_ = this;
+    this->initialize(pipeline, std::move(handler));
   }
 
-  void detachTransport() override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    handler_->detachTransport(this);
+  // For StaticPipeline
+  ContextImpl() {
+    this->impl_ = this;
   }
 
+  ~ContextImpl() {}
+
   // HandlerContext overrides
   void fireRead(Rout msg) override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    if (nextIn_) {
-      nextIn_->read(std::forward<Rout>(msg));
+    DestructorGuard dg(this->pipeline_);
+    if (this->nextIn_) {
+      this->nextIn_->read(std::forward<Rout>(msg));
     } else {
       LOG(WARNING) << "read reached end of pipeline";
     }
   }
 
   void fireReadEOF() override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    if (nextIn_) {
-      nextIn_->readEOF();
+    DestructorGuard dg(this->pipeline_);
+    if (this->nextIn_) {
+      this->nextIn_->readEOF();
     } else {
       LOG(WARNING) << "readEOF reached end of pipeline";
     }
   }
 
   void fireReadException(exception_wrapper e) override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    if (nextIn_) {
-      nextIn_->readException(std::move(e));
+    DestructorGuard dg(this->pipeline_);
+    if (this->nextIn_) {
+      this->nextIn_->readException(std::move(e));
     } else {
       LOG(WARNING) << "readException reached end of pipeline";
     }
   }
 
   Future<void> fireWrite(Wout msg) override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    if (nextOut_) {
-      return nextOut_->write(std::forward<Wout>(msg));
+    DestructorGuard dg(this->pipeline_);
+    if (this->nextOut_) {
+      return this->nextOut_->write(std::forward<Wout>(msg));
     } else {
       LOG(WARNING) << "write reached end of pipeline";
       return makeFuture();
@@ -221,9 +232,9 @@ class ContextImpl : public HandlerContext<typename H::rout,
   }
 
   Future<void> fireClose() override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    if (nextOut_) {
-      return nextOut_->close();
+    DestructorGuard dg(this->pipeline_);
+    if (this->nextOut_) {
+      return this->nextOut_->close();
     } else {
       LOG(WARNING) << "close reached end of pipeline";
       return makeFuture();
@@ -231,60 +242,56 @@ class ContextImpl : public HandlerContext<typename H::rout,
   }
 
   std::shared_ptr<AsyncTransport> getTransport() override {
-    return pipeline_->getTransport();
+    return this->pipeline_->getTransport();
   }
 
   void setWriteFlags(WriteFlags flags) override {
-    pipeline_->setWriteFlags(flags);
+    this->pipeline_->setWriteFlags(flags);
   }
 
   WriteFlags getWriteFlags() override {
-    return pipeline_->getWriteFlags();
+    return this->pipeline_->getWriteFlags();
   }
 
   void setReadBufferSettings(
       uint64_t minAvailable,
       uint64_t allocationSize) override {
-    pipeline_->setReadBufferSettings(minAvailable, allocationSize);
+    this->pipeline_->setReadBufferSettings(minAvailable, allocationSize);
   }
 
   std::pair<uint64_t, uint64_t> getReadBufferSettings() override {
-    return pipeline_->getReadBufferSettings();
+    return this->pipeline_->getReadBufferSettings();
   }
 
-  // InboundHandlerContext overrides
+  // InboundLink overrides
   void read(Rin msg) override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    handler_->read(this, std::forward<Rin>(msg));
+    DestructorGuard dg(this->pipeline_);
+    this->handler_->read(this, std::forward<Rin>(msg));
   }
 
   void readEOF() override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    handler_->readEOF(this);
+    DestructorGuard dg(this->pipeline_);
+    this->handler_->readEOF(this);
   }
 
   void readException(exception_wrapper e) override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    handler_->readException(this, std::move(e));
+    DestructorGuard dg(this->pipeline_);
+    this->handler_->readException(this, std::move(e));
   }
 
-  // OutboundHandlerContext overrides
+  // OutboundLink overrides
   Future<void> write(Win msg) override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    return handler_->write(this, std::forward<Win>(msg));
+    DestructorGuard dg(this->pipeline_);
+    return this->handler_->write(this, std::forward<Win>(msg));
   }
 
   Future<void> close() override {
-    typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_));
-    return handler_->close(this);
+    DestructorGuard dg(this->pipeline_);
+    return this->handler_->close(this);
   }
 
  private:
-  P* pipeline_;
-  std::shared_ptr<H> handler_;
-  InboundHandlerContext<Rout>* nextIn_{nullptr};
-  OutboundHandlerContext<Wout>* nextOut_{nullptr};
-  bool attached_{false};
+  using DestructorGuard = typename P::DestructorGuard;
 };
 
 }}
index 643ccdaeec81d415b36561ce9c14b3295dc7bbab..738a83f9d8b9414e3495b89f2c99e8f0f9260177 100644 (file)
@@ -133,12 +133,12 @@ class Pipeline : public DelayedDestruction {
       ctxs_[i]->link(ctxs_[i+1].get());
     }
 
-    back_ = dynamic_cast<OutboundHandlerContext<W>*>(ctxs_.back().get());
+    back_ = dynamic_cast<OutboundLink<W>*>(ctxs_.back().get());
     if (!back_) {
       throw std::invalid_argument("wrong type for last handler");
     }
 
-    front_ = dynamic_cast<InboundHandlerContext<R>*>(ctxs_.front().get());
+    front_ = dynamic_cast<InboundLink<R>*>(ctxs_.front().get());
     if (!front_) {
       throw std::invalid_argument("wrong type for first handler");
     }
@@ -205,8 +205,8 @@ class Pipeline : public DelayedDestruction {
   std::pair<uint64_t, uint64_t> readBufferSettings_{2048, 2048};
 
   bool isStatic_{false};
-  InboundHandlerContext<R>* front_{nullptr};
-  OutboundHandlerContext<W>* back_{nullptr};
+  InboundLink<R>* front_{nullptr};
+  OutboundLink<W>* back_{nullptr};
   std::vector<std::shared_ptr<PipelineContext>> ctxs_;
   std::shared_ptr<PipelineContext> owner_;
 };