5b627f0f0723836afc8631f793624b51086cc573
[folly.git] / folly / io / async / EventBaseLocal.h
1 /*
2  * Copyright 2017 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 <boost/noncopyable.hpp>
20 #include <folly/Synchronized.h>
21 #include <folly/io/async/EventBase.h>
22 #include <memory>
23 #include <mutex>
24 #include <unordered_set>
25 #include <utility>
26
27 namespace folly {
28
29 namespace detail {
30
31 class EventBaseLocalBase : public EventBaseLocalBaseBase, boost::noncopyable {
32  public:
33   EventBaseLocalBase() {}
34   virtual ~EventBaseLocalBase();
35   void erase(EventBase& evb);
36   void onEventBaseDestruction(EventBase& evb) override;
37
38  protected:
39   void setVoid(EventBase& evb, std::shared_ptr<void>&& ptr);
40   void* getVoid(EventBase& evb);
41
42   folly::Synchronized<std::unordered_set<EventBase*>> eventBases_;
43   static std::atomic<uint64_t> keyCounter_;
44   uint64_t key_{keyCounter_++};
45 };
46
47 }
48
49 /**
50  * A storage abstraction for data that should be tied to an EventBase.
51  *
52  *   struct Foo { Foo(int a, int b); };
53  *   EventBaseLocal<Foo> myFoo;
54  *   ...
55  *   EventBase evb;
56  *   myFoo.set(evb, new Foo(1, 2));
57  *   myFoo.set(evb, 1, 2);
58  *   Foo* foo = myFoo.get(evb);
59  *   myFoo.erase(evb);
60  *   Foo& foo = myFoo.getOrCreate(evb, 1, 2); // ctor
61  *   Foo& foo = myFoo.getOrCreate(evb, 1, 2); // no ctor
62  *   myFoo.erase(evb);
63  *   Foo& foo = myFoo.getOrCreateFn(evb, [] () { return new Foo(3, 4); })
64  *
65  * The objects will be deleted when the EventBaseLocal or the EventBase is
66  * destructed (whichever comes first). All methods must be called from the
67  * EventBase thread.
68  *
69  * The user is responsible for throwing away invalid references/ptrs returned
70  * by the get() method after set/erase is called.  If shared ownership is
71  * needed, use a EventBaseLocal<shared_ptr<...>>.
72  */
73 template<typename T>
74 class EventBaseLocal : public detail::EventBaseLocalBase {
75  public:
76   EventBaseLocal(): EventBaseLocalBase() {}
77
78   T* get(EventBase& evb) {
79     return static_cast<T*>(getVoid(evb));
80   }
81
82   void emplace(EventBase& evb, T* ptr) {
83     std::shared_ptr<T> smartPtr(ptr);
84     setVoid(evb, std::move(smartPtr));
85   }
86
87   template <typename... Args>
88   void emplace(EventBase& evb, Args&&... args) {
89     auto smartPtr = std::make_shared<T>(std::forward<Args>(args)...);
90     setVoid(evb, smartPtr);
91   }
92
93   template <typename... Args>
94   T& getOrCreate(EventBase& evb, Args&&... args) {
95     if (auto ptr = getVoid(evb)) {
96       return *static_cast<T*>(ptr);
97     }
98     auto smartPtr = std::make_shared<T>(std::forward<Args>(args)...);
99     auto& ref = *smartPtr;
100     setVoid(evb, std::move(smartPtr));
101     return ref;
102   }
103
104   template <typename Func>
105   T& getOrCreateFn(EventBase& evb, Func& fn) {
106     // If this looks like it's copy/pasted from above, that's because it is.
107     // gcc has a bug (fixed in 4.9) that doesn't allow capturing variadic
108     // params in a lambda.
109     if (auto ptr = getVoid(evb)) {
110       return *static_cast<T*>(ptr);
111     }
112     std::shared_ptr<T> smartPtr(fn());
113     auto& ref = *smartPtr;
114     setVoid(evb, std::move(smartPtr));
115     return ref;
116   }
117 };
118
119
120 }