copy wangle back into folly
[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 <type_traits>
20
21 #include <folly/wangle/channel/Pipeline.h>
22
23 namespace folly { namespace wangle {
24
25 /*
26  * StaticPipeline allows you to create a Pipeline with minimal allocations.
27  * Specify your handlers after the input/output types of your Pipeline in order
28  * from front to back, and construct with either H&&, H*, or std::shared_ptr<H>
29  * for each handler. The pipeline will be finalized for you at the end of
30  * construction. For example:
31  *
32  * StringToStringHandler stringHandler1;
33  * auto stringHandler2 = std::make_shared<StringToStringHandler>();
34  *
35  * StaticPipeline<int, std::string,
36  *   IntToStringHandler,
37  *   StringToStringHandler,
38  *   StringToStringHandler>(
39  *     IntToStringHandler(),  // H&&
40  *     &stringHandler1,       // H*
41  *     stringHandler2)        // std::shared_ptr<H>
42  * pipeline;
43  *
44  * You can then use pipeline just like any Pipeline. See Pipeline.h.
45  */
46 template <class R, class W, class... Handlers>
47 class StaticPipeline;
48
49 template <class R, class W>
50 class StaticPipeline<R, W> : public Pipeline<R, W> {
51  protected:
52   explicit StaticPipeline(bool) : Pipeline<R, W>(true) {}
53 };
54
55 template <class Handler>
56 class BaseWithOptional {
57  protected:
58   folly::Optional<Handler> handler_;
59 };
60
61 template <class Handler>
62 class BaseWithoutOptional {
63 };
64
65 template <class R, class W, class Handler, class... Handlers>
66 class StaticPipeline<R, W, Handler, Handlers...>
67     : public StaticPipeline<R, W, Handlers...>
68     , public std::conditional<std::is_abstract<Handler>::value,
69                               BaseWithoutOptional<Handler>,
70                               BaseWithOptional<Handler>>::type {
71  public:
72   template <class... HandlerArgs>
73   explicit StaticPipeline(HandlerArgs&&... handlers)
74     : StaticPipeline(true, std::forward<HandlerArgs>(handlers)...) {
75     isFirst_ = true;
76   }
77
78   ~StaticPipeline() {
79     if (isFirst_) {
80       Pipeline<R, W>::detachHandlers();
81     }
82   }
83
84  protected:
85   template <class HandlerArg, class... HandlerArgs>
86   StaticPipeline(
87       bool isFirst,
88       HandlerArg&& handler,
89       HandlerArgs&&... handlers)
90     : StaticPipeline<R, W, Handlers...>(
91           false,
92           std::forward<HandlerArgs>(handlers)...) {
93     isFirst_ = isFirst;
94     setHandler(std::forward<HandlerArg>(handler));
95     CHECK(handlerPtr_);
96     ctx_.initialize(this, handlerPtr_);
97     Pipeline<R, W>::addContextFront(&ctx_);
98     if (isFirst_) {
99       Pipeline<R, W>::finalize();
100     }
101   }
102
103  private:
104   template <class HandlerArg>
105   typename std::enable_if<std::is_same<
106     typename std::remove_reference<HandlerArg>::type,
107     Handler
108   >::value>::type
109   setHandler(HandlerArg&& arg) {
110     BaseWithOptional<Handler>::handler_.emplace(std::forward<HandlerArg>(arg));
111     handlerPtr_ = std::shared_ptr<Handler>(&(*BaseWithOptional<Handler>::handler_), [](Handler*){});
112   }
113
114   template <class HandlerArg>
115   typename std::enable_if<std::is_same<
116     typename std::decay<HandlerArg>::type,
117     std::shared_ptr<Handler>
118   >::value>::type
119   setHandler(HandlerArg&& arg) {
120     handlerPtr_ = std::forward<HandlerArg>(arg);
121   }
122
123   template <class HandlerArg>
124   typename std::enable_if<std::is_same<
125     typename std::decay<HandlerArg>::type,
126     Handler*
127   >::value>::type
128   setHandler(HandlerArg&& arg) {
129     handlerPtr_ = std::shared_ptr<Handler>(arg, [](Handler*){});
130   }
131
132   bool isFirst_;
133   std::shared_ptr<Handler> handlerPtr_;
134   typename ContextType<Handler, Pipeline<R, W>>::type ctx_;
135 };
136
137 }} // folly::wangle