6c6c5e0868062269825052730f3513adb3b01c05
[folly.git] / folly / wangle / channel / StaticPipeline.h
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <folly/wangle/channel/Pipeline.h>
20
21 namespace folly { namespace wangle {
22
23 /*
24  * StaticPipeline allows you to create a Pipeline with minimal allocations.
25  * Specify your handlers after the input/output types of your Pipeline in order
26  * from front to back, and construct with either H&&, H*, or std::shared_ptr<H>
27  * for each handler. The pipeline will be finalized for you at the end of
28  * construction. For example:
29  *
30  * StringToStringHandler stringHandler1;
31  * auto stringHandler2 = std::make_shared<StringToStringHandler>();
32  *
33  * StaticPipeline<int, std::string,
34  *   IntToStringHandler,
35  *   StringToStringHandler,
36  *   StringToStringHandler>(
37  *     IntToStringHandler(),  // H&&
38  *     &stringHandler1,       // H*
39  *     stringHandler2)        // std::shared_ptr<H>
40  * pipeline;
41  *
42  * You can then use pipeline just like any Pipeline. See Pipeline.h.
43  */
44 template <class R, class W, class... Handlers>
45 class StaticPipeline;
46
47 template <class R, class W>
48 class StaticPipeline<R, W> : public Pipeline<R, W> {
49  protected:
50   explicit StaticPipeline(bool) : Pipeline<R, W>(true) {}
51 };
52
53 template <class R, class W, class Handler, class... Handlers>
54 class StaticPipeline<R, W, Handler, Handlers...>
55     : public StaticPipeline<R, W, Handlers...> {
56  public:
57   template <class... HandlerArgs>
58   explicit StaticPipeline(HandlerArgs&&... handlers)
59     : StaticPipeline(true, std::forward<HandlerArgs>(handlers)...) {
60     isFirst_ = true;
61   }
62
63   ~StaticPipeline() {
64     if (isFirst_) {
65       Pipeline<R, W>::detachHandlers();
66     }
67   }
68
69  protected:
70   typedef ContextImpl<Pipeline<R, W>, Handler> Context;
71
72   template <class HandlerArg, class... HandlerArgs>
73   StaticPipeline(
74       bool isFirst,
75       HandlerArg&& handler,
76       HandlerArgs&&... handlers)
77     : StaticPipeline<R, W, Handlers...>(
78           false,
79           std::forward<HandlerArgs>(handlers)...) {
80     isFirst_ = isFirst;
81     setHandler(std::forward<HandlerArg>(handler));
82     CHECK(handlerPtr_);
83     ctx_.initialize(this, handlerPtr_);
84     Pipeline<R, W>::addContextFront(&ctx_);
85     if (isFirst_) {
86       Pipeline<R, W>::finalize();
87     }
88   }
89
90  private:
91   template <class HandlerArg>
92   typename std::enable_if<std::is_same<
93     typename std::remove_reference<HandlerArg>::type,
94     Handler
95   >::value>::type
96   setHandler(HandlerArg&& arg) {
97     handler_.emplace(std::forward<HandlerArg>(arg));
98     handlerPtr_ = std::shared_ptr<Handler>(&(*handler_), [](Handler*){});
99   }
100
101   template <class HandlerArg>
102   typename std::enable_if<std::is_same<
103     typename std::decay<HandlerArg>::type,
104     std::shared_ptr<Handler>
105   >::value>::type
106   setHandler(HandlerArg&& arg) {
107     handlerPtr_ = std::forward<HandlerArg>(arg);
108   }
109
110   template <class HandlerArg>
111   typename std::enable_if<std::is_same<
112     typename std::decay<HandlerArg>::type,
113     Handler*
114   >::value>::type
115   setHandler(HandlerArg&& arg) {
116     handlerPtr_ = std::shared_ptr<Handler>(arg, [](Handler*){});
117   }
118
119   bool isFirst_;
120   folly::Optional<Handler> handler_;
121   std::shared_ptr<Handler> handlerPtr_;
122   ContextImpl<Pipeline<R, W>, Handler> ctx_;
123 };
124
125 }} // folly::wangle