2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <boost/noncopyable.hpp>
20 #include <folly/Synchronized.h>
21 #include <folly/io/async/EventBase.h>
24 #include <unordered_set>
31 class EventBaseLocalBase : public EventBaseLocalBaseBase, boost::noncopyable {
33 EventBaseLocalBase() {}
34 ~EventBaseLocalBase() override;
35 void erase(EventBase& evb);
36 void onEventBaseDestruction(EventBase& evb) override;
39 void setVoid(EventBase& evb, std::shared_ptr<void>&& ptr);
40 void* getVoid(EventBase& evb);
42 folly::Synchronized<std::unordered_set<EventBase*>> eventBases_;
43 static std::atomic<uint64_t> keyCounter_;
44 uint64_t key_{keyCounter_++};
50 * A storage abstraction for data that should be tied to an EventBase.
52 * struct Foo { Foo(int a, int b); };
53 * EventBaseLocal<Foo> myFoo;
56 * myFoo.set(evb, new Foo(1, 2));
57 * myFoo.set(evb, 1, 2);
58 * Foo* foo = myFoo.get(evb);
60 * Foo& foo = myFoo.getOrCreate(evb, 1, 2); // ctor
61 * Foo& foo = myFoo.getOrCreate(evb, 1, 2); // no ctor
63 * Foo& foo = myFoo.getOrCreateFn(evb, [] () { return new Foo(3, 4); })
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
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<...>>.
74 class EventBaseLocal : public detail::EventBaseLocalBase {
76 EventBaseLocal(): EventBaseLocalBase() {}
78 T* get(EventBase& evb) {
79 return static_cast<T*>(getVoid(evb));
82 void emplace(EventBase& evb, T* ptr) {
83 std::shared_ptr<T> smartPtr(ptr);
84 setVoid(evb, std::move(smartPtr));
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);
93 template <typename... Args>
94 T& getOrCreate(EventBase& evb, Args&&... args) {
95 if (auto ptr = getVoid(evb)) {
96 return *static_cast<T*>(ptr);
98 auto smartPtr = std::make_shared<T>(std::forward<Args>(args)...);
99 auto& ref = *smartPtr;
100 setVoid(evb, std::move(smartPtr));
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);
112 std::shared_ptr<T> smartPtr(fn());
113 auto& ref = *smartPtr;
114 setVoid(evb, std::move(smartPtr));