Commit dded9096 authored by James Sedgwick's avatar James Sedgwick Committed by Praveen Kumar Ramakrishnan

moar CRTP to minimize copypasta for inbound/outbound handlers

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
parent b44cacfd
...@@ -43,7 +43,7 @@ class HandlerBase { ...@@ -43,7 +43,7 @@ class HandlerBase {
} }
private: private:
friend detail::HandlerContextBase<Context>; friend PipelineContext;
uint64_t attachCount_{0}; uint64_t attachCount_{0};
Context* ctx_{nullptr}; Context* ctx_{nullptr};
}; };
......
...@@ -22,26 +22,8 @@ ...@@ -22,26 +22,8 @@
namespace folly { namespace wangle { 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> template <class In, class Out>
class HandlerContext class HandlerContext {
: public detail::HandlerContextBase<HandlerContext<In, Out>> {
public: public:
virtual ~HandlerContext() {} virtual ~HandlerContext() {}
...@@ -83,6 +65,15 @@ class PipelineContext { ...@@ -83,6 +65,15 @@ class PipelineContext {
virtual void attachTransport() = 0; virtual void attachTransport() = 0;
virtual void detachTransport() = 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) { void link(PipelineContext* other) {
setNextIn(other); setNextIn(other);
other->setNextOut(this); other->setNextOut(this);
...@@ -94,68 +85,62 @@ class PipelineContext { ...@@ -94,68 +85,62 @@ class PipelineContext {
}; };
template <class In> template <class In>
class InboundHandlerContext { class InboundLink {
public: public:
virtual ~InboundHandlerContext() {} virtual ~InboundLink() {}
virtual void read(In msg) = 0; virtual void read(In msg) = 0;
virtual void readEOF() = 0; virtual void readEOF() = 0;
virtual void readException(exception_wrapper e) = 0; virtual void readException(exception_wrapper e) = 0;
}; };
template <class Out> template <class Out>
class OutboundHandlerContext { class OutboundLink {
public: public:
virtual ~OutboundHandlerContext() {} virtual ~OutboundLink() {}
virtual Future<void> write(Out msg) = 0; virtual Future<void> write(Out msg) = 0;
virtual Future<void> close() = 0; virtual Future<void> close() = 0;
}; };
template <class P, class H> template <class P, class H, class Context>
class ContextImpl : public HandlerContext<typename H::rout, class ContextImplBase : public PipelineContext {
typename H::wout>,
public InboundHandlerContext<typename H::rin>,
public OutboundHandlerContext<typename H::win>,
public PipelineContext {
public: public:
typedef typename H::rin Rin; ~ContextImplBase() {}
typedef typename H::rout Rout;
typedef typename H::win Win;
typedef typename H::wout Wout;
explicit ContextImpl(P* pipeline, std::shared_ptr<H> handler) { H* getHandler() {
initialize(pipeline, std::move(handler)); return handler_.get();
} }
// For StaticPipeline
ContextImpl() {}
~ContextImpl() {}
void initialize(P* pipeline, std::shared_ptr<H> handler) { void initialize(P* pipeline, std::shared_ptr<H> handler) {
pipeline_ = pipeline; pipeline_ = pipeline;
handler_ = std::move(handler); handler_ = std::move(handler);
} }
H* getHandler() {
return handler_.get();
}
// PipelineContext overrides // PipelineContext overrides
void attachPipeline() override { void attachPipeline() override {
if (!attached_) { if (!attached_) {
this->attachContext(handler_.get(), this); this->attachContext(handler_.get(), impl_);
handler_->attachPipeline(this); handler_->attachPipeline(impl_);
attached_ = true; attached_ = true;
} }
} }
void detachPipeline() override { void detachPipeline() override {
handler_->detachPipeline(this); handler_->detachPipeline(impl_);
attached_ = false; 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 { void setNextIn(PipelineContext* ctx) override {
auto nextIn = dynamic_cast<InboundHandlerContext<Rout>*>(ctx); auto nextIn = dynamic_cast<InboundLink<typename H::rout>*>(ctx);
if (nextIn) { if (nextIn) {
nextIn_ = nextIn; nextIn_ = nextIn;
} else { } else {
...@@ -164,7 +149,7 @@ class ContextImpl : public HandlerContext<typename H::rout, ...@@ -164,7 +149,7 @@ class ContextImpl : public HandlerContext<typename H::rout,
} }
void setNextOut(PipelineContext* ctx) override { void setNextOut(PipelineContext* ctx) override {
auto nextOut = dynamic_cast<OutboundHandlerContext<Wout>*>(ctx); auto nextOut = dynamic_cast<OutboundLink<typename H::wout>*>(ctx);
if (nextOut) { if (nextOut) {
nextOut_ = nextOut; nextOut_ = nextOut;
} else { } else {
...@@ -172,48 +157,74 @@ class ContextImpl : public HandlerContext<typename H::rout, ...@@ -172,48 +157,74 @@ class ContextImpl : public HandlerContext<typename H::rout,
} }
} }
void attachTransport() override { protected:
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); Context* impl_;
handler_->attachTransport(this); 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 { // For StaticPipeline
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); ContextImpl() {
handler_->detachTransport(this); this->impl_ = this;
} }
~ContextImpl() {}
// HandlerContext overrides // HandlerContext overrides
void fireRead(Rout msg) override { void fireRead(Rout msg) override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
if (nextIn_) { if (this->nextIn_) {
nextIn_->read(std::forward<Rout>(msg)); this->nextIn_->read(std::forward<Rout>(msg));
} else { } else {
LOG(WARNING) << "read reached end of pipeline"; LOG(WARNING) << "read reached end of pipeline";
} }
} }
void fireReadEOF() override { void fireReadEOF() override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
if (nextIn_) { if (this->nextIn_) {
nextIn_->readEOF(); this->nextIn_->readEOF();
} else { } else {
LOG(WARNING) << "readEOF reached end of pipeline"; LOG(WARNING) << "readEOF reached end of pipeline";
} }
} }
void fireReadException(exception_wrapper e) override { void fireReadException(exception_wrapper e) override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
if (nextIn_) { if (this->nextIn_) {
nextIn_->readException(std::move(e)); this->nextIn_->readException(std::move(e));
} else { } else {
LOG(WARNING) << "readException reached end of pipeline"; LOG(WARNING) << "readException reached end of pipeline";
} }
} }
Future<void> fireWrite(Wout msg) override { Future<void> fireWrite(Wout msg) override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
if (nextOut_) { if (this->nextOut_) {
return nextOut_->write(std::forward<Wout>(msg)); return this->nextOut_->write(std::forward<Wout>(msg));
} else { } else {
LOG(WARNING) << "write reached end of pipeline"; LOG(WARNING) << "write reached end of pipeline";
return makeFuture(); return makeFuture();
...@@ -221,9 +232,9 @@ class ContextImpl : public HandlerContext<typename H::rout, ...@@ -221,9 +232,9 @@ class ContextImpl : public HandlerContext<typename H::rout,
} }
Future<void> fireClose() override { Future<void> fireClose() override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
if (nextOut_) { if (this->nextOut_) {
return nextOut_->close(); return this->nextOut_->close();
} else { } else {
LOG(WARNING) << "close reached end of pipeline"; LOG(WARNING) << "close reached end of pipeline";
return makeFuture(); return makeFuture();
...@@ -231,60 +242,56 @@ class ContextImpl : public HandlerContext<typename H::rout, ...@@ -231,60 +242,56 @@ class ContextImpl : public HandlerContext<typename H::rout,
} }
std::shared_ptr<AsyncTransport> getTransport() override { std::shared_ptr<AsyncTransport> getTransport() override {
return pipeline_->getTransport(); return this->pipeline_->getTransport();
} }
void setWriteFlags(WriteFlags flags) override { void setWriteFlags(WriteFlags flags) override {
pipeline_->setWriteFlags(flags); this->pipeline_->setWriteFlags(flags);
} }
WriteFlags getWriteFlags() override { WriteFlags getWriteFlags() override {
return pipeline_->getWriteFlags(); return this->pipeline_->getWriteFlags();
} }
void setReadBufferSettings( void setReadBufferSettings(
uint64_t minAvailable, uint64_t minAvailable,
uint64_t allocationSize) override { uint64_t allocationSize) override {
pipeline_->setReadBufferSettings(minAvailable, allocationSize); this->pipeline_->setReadBufferSettings(minAvailable, allocationSize);
} }
std::pair<uint64_t, uint64_t> getReadBufferSettings() override { std::pair<uint64_t, uint64_t> getReadBufferSettings() override {
return pipeline_->getReadBufferSettings(); return this->pipeline_->getReadBufferSettings();
} }
// InboundHandlerContext overrides // InboundLink overrides
void read(Rin msg) override { void read(Rin msg) override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
handler_->read(this, std::forward<Rin>(msg)); this->handler_->read(this, std::forward<Rin>(msg));
} }
void readEOF() override { void readEOF() override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
handler_->readEOF(this); this->handler_->readEOF(this);
} }
void readException(exception_wrapper e) override { void readException(exception_wrapper e) override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
handler_->readException(this, std::move(e)); this->handler_->readException(this, std::move(e));
} }
// OutboundHandlerContext overrides // OutboundLink overrides
Future<void> write(Win msg) override { Future<void> write(Win msg) override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
return handler_->write(this, std::forward<Win>(msg)); return this->handler_->write(this, std::forward<Win>(msg));
} }
Future<void> close() override { Future<void> close() override {
typename P::DestructorGuard dg(static_cast<DelayedDestruction*>(pipeline_)); DestructorGuard dg(this->pipeline_);
return handler_->close(this); return this->handler_->close(this);
} }
private: private:
P* pipeline_; using DestructorGuard = typename P::DestructorGuard;
std::shared_ptr<H> handler_;
InboundHandlerContext<Rout>* nextIn_{nullptr};
OutboundHandlerContext<Wout>* nextOut_{nullptr};
bool attached_{false};
}; };
}} }}
...@@ -133,12 +133,12 @@ class Pipeline : public DelayedDestruction { ...@@ -133,12 +133,12 @@ class Pipeline : public DelayedDestruction {
ctxs_[i]->link(ctxs_[i+1].get()); 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_) { if (!back_) {
throw std::invalid_argument("wrong type for last handler"); 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_) { if (!front_) {
throw std::invalid_argument("wrong type for first handler"); throw std::invalid_argument("wrong type for first handler");
} }
...@@ -205,8 +205,8 @@ class Pipeline : public DelayedDestruction { ...@@ -205,8 +205,8 @@ class Pipeline : public DelayedDestruction {
std::pair<uint64_t, uint64_t> readBufferSettings_{2048, 2048}; std::pair<uint64_t, uint64_t> readBufferSettings_{2048, 2048};
bool isStatic_{false}; bool isStatic_{false};
InboundHandlerContext<R>* front_{nullptr}; InboundLink<R>* front_{nullptr};
OutboundHandlerContext<W>* back_{nullptr}; OutboundLink<W>* back_{nullptr};
std::vector<std::shared_ptr<PipelineContext>> ctxs_; std::vector<std::shared_ptr<PipelineContext>> ctxs_;
std::shared_ptr<PipelineContext> owner_; std::shared_ptr<PipelineContext> owner_;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment