f7276375e51ba7696bc05cdca91f03f257027c52
[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 are thread-safe.
67  *
68  * The user is responsible for throwing away invalid references/ptrs returned
69  * by the get() method after set/erase is called.  If shared ownership is
70  * needed, use a EventBaseLocal<shared_ptr<...>>.
71  */
72 template<typename T>
73 class EventBaseLocal : public detail::EventBaseLocalBase {
74  public:
75   EventBaseLocal(): EventBaseLocalBase() {}
76
77   T* get(EventBase& evb) {
78     return static_cast<T*>(getVoid(evb));
79   }
80
81   void emplace(EventBase& evb, T* ptr) {
82     std::shared_ptr<T> smartPtr(ptr);
83     setVoid(evb, std::move(smartPtr));
84   }
85
86   template <typename... Args>
87   void emplace(EventBase& evb, Args&&... args) {
88     auto smartPtr = std::make_shared<T>(std::forward<Args>(args)...);
89     setVoid(evb, smartPtr);
90   }
91
92   template <typename... Args>
93   T& getOrCreate(EventBase& evb, Args&&... args) {
94     if (auto ptr = getVoid(evb)) {
95       return *static_cast<T*>(ptr);
96     }
97     auto smartPtr = std::make_shared<T>(std::forward<Args>(args)...);
98     auto& ref = *smartPtr;
99     setVoid(evb, std::move(smartPtr));
100     return ref;
101   }
102
103   template <typename Func>
104   T& getOrCreateFn(EventBase& evb, Func& fn) {
105     // If this looks like it's copy/pasted from above, that's because it is.
106     // gcc has a bug (fixed in 4.9) that doesn't allow capturing variadic
107     // params in a lambda.
108     if (auto ptr = getVoid(evb)) {
109       return *static_cast<T*>(ptr);
110     }
111     std::shared_ptr<T> smartPtr(fn());
112     auto& ref = *smartPtr;
113     setVoid(evb, std::move(smartPtr));
114     return ref;
115   }
116 };
117
118
119 }