proxygen
FilterChain.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
10 #pragma once
11 
12 #include <folly/Memory.h>
13 #include <folly/Function.h>
14 #include <glog/logging.h>
15 #include <memory>
16 #include <utility>
17 
18 namespace proxygen {
19 
38 template <typename T1, typename T2, void (T1::*set_callback)(T2*),
39  bool TakeOwnership, typename Dp = std::default_delete<T1> >
40 class GenericFilter: public T1, public T2 {
41  public:
49  GenericFilter(bool calls, bool callbacks):
50  kWantsCalls_(calls),
51  kWantsCallbacks_(callbacks) {}
52 
53  ~GenericFilter() override {
54  if (TakeOwnership) {
55  callbackSource_ = nullptr;
56  }
57  // For the last filter in the chain, next_ is null, and call_ points
58  // to the concrete implementation object.
59  auto next = next_ ? next_ : call_;
60  drop();
61  if (TakeOwnership && next) {
62  Dp()(next);
63  }
64  }
65 
69  void append(Filter* nextFilter) {
70  nextFilter->next_ = next_;
71  nextFilter->prev_ = this;
72  nextFilter->call_ = call_;
73  nextFilter->callback_ = kWantsCallbacks_ ? this : callback_;
74  nextFilter->callSource_ = kWantsCalls_ ? this : callSource_;
75  nextFilter->callbackSource_ = callbackSource_;
76  if (next_) {
77  next_->prev_ = nextFilter;
78  }
79 
80  if (nextFilter->kWantsCalls_) {
81  if (kWantsCalls_) {
82  call_ = nextFilter;
83  } else {
84  callSource_->call_ = nextFilter;
85  }
86  if (next_) {
87  next_->callSource_ = nextFilter;
88  }
89  }
90  if (nextFilter->kWantsCallbacks_) {
91  // Find the first filter before this one that wants callbacks
92  auto cur = this;
93  while (cur->prev_ && !cur->kWantsCallbacks_) {
94  cur = cur->prev_;
95  }
96  cur->callbackSource_ = nextFilter;
97  // Make sure nextFilter gets callbacks
98  ((nextFilter->callbackSource_)->*(set_callback))(nextFilter);
99  }
100  next_ = nextFilter;
101  }
102 
103  const bool kWantsCalls_;
104  const bool kWantsCallbacks_;
105 
106  protected:
111  void setCallbackInternal(T2* cb) {
112  setCallbackInternalImpl(cb, this);
113  }
114 
119  void drop() {
120  if (prev_) {
121  prev_->next_ = next_;
122  }
123  if (next_) {
124  next_->prev_ = prev_;
125  }
126  // TODO: could call fn gated by std::enable_if
127  if (kWantsCalls_ && callSource_) {
128  callSource_->call_ = call_;
129  if (call_) {
130  auto callFilter = dynamic_cast<Filter*>(call_);
131  if (callFilter) {
132  callFilter->callSource_ = callSource_;
133  }
134  }
135  }
136  // TODO: could call fn gated by std::enable_if
137  if (kWantsCallbacks_ && callbackSource_) {
138  ((callbackSource_)->*(set_callback))(callback_);
139  if (callback_) {
140  auto callbackFilter = dynamic_cast<Filter*>(callback_);
141  if (callbackFilter) {
142  callbackFilter->callbackSource_ = callbackSource_;
143  }
144  }
145  }
146  call_ = callbackSource_ = nullptr;
147  callback_ = nullptr;
148  callSource_ = next_ = prev_ = nullptr;
149  }
150 
151  // Next "call" filter (call_ == next_ iff next_->kWantsCalls_)
152  T1* call_{nullptr};
153  // Next "callback" filter (callback_ == prev_ iff prev_->kWantsCallbacks_)
154  T2* callback_{nullptr};
155 
156  private:
157 
158  void setCallbackInternalImpl(T2* cb, T2* sourceSet) {
159  if (callback_ != cb) {
160  callback_ = cb;
161  ((callbackSource_)->*(set_callback))(cb ? sourceSet : nullptr);
162  }
163  }
164 
165  // The next filter in the chain (towards T1 implementation)
166  Filter* next_{nullptr};
167  // The previous filter in the chain (towards T2 implementation)
168  Filter* prev_{nullptr};
169  // The first filter before this one in the chain that wants calls.
170  // Only valid if kWantsCalls_ is true.
171  Filter* callSource_{nullptr};
172  // Pointer to the first filter or object after this one in the chain
173  // that makes callbacks. Only valid if kWantsCallbacks_ is true.
174  T1* callbackSource_{nullptr};
175 
176  template <class A, class B, class F, void (A::*fn)(B*), bool Own>
177  friend class FilterChain;
178 };
179 
205 template <typename T1, typename T2, typename FilterType,
206  void (T1::*set_callback)(T2*), bool TakeOwnership>
207 class FilterChain: private FilterType {
208  public:
209  explicit FilterChain(std::unique_ptr<T1> destination):
210  FilterType(false, false) {
211  static_assert(TakeOwnership, "unique_ptr constructor only available "
212  "if the chain owns the filters.");
213  this->call_ = CHECK_NOTNULL(destination.release());
214  this->callback_ = nullptr; //must call setCallback() explicitly
215  this->callSource_ = this;
216  this->callbackSource_ = this->call_;
217  this->chainEnd_ = this->call_;
218  }
219 
220  explicit FilterChain(T1* destination):
221  FilterType(false, false) {
222  static_assert(!TakeOwnership, "raw pointer constructor only available "
223  "if the chain doesn't own the filters.");
224  this->call_ = CHECK_NOTNULL(destination);
225  this->callback_ = nullptr; //must call setCallback() explicitly
226  this->callSource_ = this;
227  this->callbackSource_ = this->call_;
228  this->chainEnd_ = this->call_;
229  }
230 
235  void setCallback(T2* cb) override { this->setCallbackInternalImpl(cb, cb); }
236 
242  T1* call() {
243  return this->call_;
244  }
245  const T1* call() const {
246  return this->call_;
247  }
248 
253  return chainEnd_;
254  }
255  const T1& getChainEnd() const {
256  return *chainEnd_;
257  }
258 
260  std::unique_ptr<T1> setDestination(std::unique_ptr<T1> destination) {
261  static_assert(TakeOwnership, "unique_ptr setDestination only available "
262  "if the chain owns the filters.");
263  // find the last filter in the chain, and the last filter that wants calls,
264  // callbacks
265  FilterChainType* lastFilter = this;
266  FilterChainType* lastCall = this;
267  FilterChainType* lastCallback = this;
268  while (lastFilter->next_) {
269  if (lastFilter->kWantsCalls_) {
270  lastCall = lastFilter;
271  }
272  if (lastFilter->kWantsCallbacks_) {
273  lastCallback = lastFilter;
274  }
275  if (lastFilter->call_ == this->chainEnd_) {
276  // Search and replace, the last N non-call filters all point to dest
277  lastFilter->call_ = destination.get();
278  }
279  lastFilter = lastFilter->next_;
280  }
281  if (lastFilter->kWantsCalls_) {
282  lastCall = lastFilter;
283  }
284  if (lastFilter->kWantsCallbacks_) {
285  lastCallback = lastFilter;
286  }
287  lastFilter->call_ = CHECK_NOTNULL(destination.release());
288  lastCall->call_ = lastFilter->call_;
289  lastCallback->callbackSource_ = lastFilter->call_;
290  auto oldChainEnd = this->chainEnd_;
291  this->chainEnd_ = lastFilter->call_;
292 
293  this->chainEnd_->setCallback(lastCallback);
294  return std::unique_ptr<T1>(oldChainEnd);
295  }
296 
300  template<typename C, typename C2, typename... Types>
302  // Callback <-> F1 <-> F2 ... <-> F_new <-> Destination
303  this->append(new C());
304  addFilters<C2, Types...>();
305  }
306 
310  template<typename C>
312  this->append(new C());
313  }
314 
319  template<typename C, typename... Types>
320  void addFilters(std::unique_ptr<C> cur, Types&&... remaining) {
321  static_assert(TakeOwnership, "addFilters() can only take "
322  "unique_ptr if the chain owns the filters");
323  this->append(cur.release());
324  addFilters(std::forward<Types>(remaining)...);
325  }
326 
327  template<typename C, typename... Types>
328  void addFilters(C* cur, Types&&... remaining) {
329  static_assert(!TakeOwnership, "addFilters() can only take "
330  "pointers if the chain doesn't own the filters");
331  this->append(cur);
332  addFilters(std::forward<Types>(remaining)...);
333  }
334 
339  template<typename C, typename... Args>
341  add(Args&&... args) {
342  this->append(new C(std::forward<Args>(args)...));
343  return *this;
344  }
345 
346  const T1* operator->() const { return call(); }
347  T1* operator->() { return call(); }
348 
349  void foreach(folly::FunctionRef<void(FilterChainType*)> fn) {
350  auto cur = this->next_;
351  while (cur) {
352  auto filter = cur;
353  cur = cur->next_;
354  fn(filter);
355  }
356  }
357 
358  private:
364  void addFilters() {}
365 
367 };
368 
369 }
void setCallbackInternalImpl(T2 *cb, T2 *sourceSet)
Definition: FilterChain.h:158
PUSHMI_INLINE_VAR constexpr detail::filter_fn filter
Definition: filter.h:75
void append(Filter *nextFilter)
Definition: FilterChain.h:69
const T1 & getChainEnd() const
Definition: FilterChain.h:255
PskType type
const T1 * operator->() const
Definition: FilterChain.h:346
std::enable_if< std::is_constructible< C >::value >::type addFilters()
Definition: FilterChain.h:301
A reference wrapper for callable objects.
Definition: Function.h:893
void append(std::unique_ptr< IOBuf > &buf, StringPiece str)
Definition: IOBufTest.cpp:37
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
void addFilters(C *cur, Types &&...remaining)
Definition: FilterChain.h:328
FilterChain< T1, T2, FilterType, set_callback, TakeOwnership > & add(Args &&...args)
Definition: FilterChain.h:341
const T1 * call() const
Definition: FilterChain.h:245
void setCallbackInternal(T2 *cb)
Definition: FilterChain.h:111
friend class FilterChain
Definition: FilterChain.h:177
const bool kWantsCallbacks_
Definition: FilterChain.h:104
GenericFilter(bool calls, bool callbacks)
Definition: FilterChain.h:49
void setCallback(T2 *cb) override
Definition: FilterChain.h:235
#define C(name, bit)
Definition: CpuId.h:204
static const char *const value
Definition: Conv.cpp:50
std::enable_if< std::is_constructible< C >::value >::type addFilters()
Definition: FilterChain.h:311
std::unique_ptr< T1 > setDestination(std::unique_ptr< T1 > destination)
Definition: FilterChain.h:260
FilterChain(std::unique_ptr< T1 > destination)
Definition: FilterChain.h:209
void addFilters(std::unique_ptr< C > cur, Types &&...remaining)
Definition: FilterChain.h:320
FilterChain(T1 *destination)
Definition: FilterChain.h:220
folly::Function< void()> callback_
Future< bool > call(int depth, Executor *executor)
~GenericFilter() override
Definition: FilterChain.h:53
def next(obj)
Definition: ast.py:58