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 virtual ~EventBaseLocalBase();
35 void erase(EventBase& evb);
36 void onEventBaseDestruction(EventBase& evb) override;
39 void setVoid(EventBase& evb, std::shared_ptr<void>&& ptr);
40 void setVoidUnlocked(EventBase& evb, std::shared_ptr<void>&& ptr);
41 void* getVoid(EventBase& evb);
43 folly::Synchronized<std::unordered_set<EventBase*>> eventBases_;
44 static std::atomic<uint64_t> keyCounter_;
45 uint64_t key_{keyCounter_++};
51 * A storage abstraction for data that should be tied to an EventBase.
53 * struct Foo { Foo(int a, int b); };
54 * EventBaseLocal<Foo> myFoo;
57 * myFoo.set(evb, new Foo(1, 2));
58 * myFoo.set(evb, 1, 2);
59 * Foo* foo = myFoo.get(evb);
61 * Foo& foo = myFoo.getOrCreate(evb, 1, 2); // ctor
62 * Foo& foo = myFoo.getOrCreate(evb, 1, 2); // no ctor
64 * Foo& foo = myFoo.getOrCreateFn(evb, [] () { return new Foo(3, 4); })
66 * The objects will be deleted when the EventBaseLocal or the EventBase is
67 * destructed (whichever comes first). All methods are thread-safe.
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 std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
97 auto it2 = evb.localStorage_.find(key_);
98 if (LIKELY(it2 != evb.localStorage_.end())) {
99 return *static_cast<T*>(it2->second.get());
101 auto smartPtr = std::make_shared<T>(std::forward<Args>(args)...);
102 auto ptr = smartPtr.get();
103 setVoidUnlocked(evb, std::move(smartPtr));
108 template <typename Func>
109 T& getOrCreateFn(EventBase& evb, Func& fn) {
110 // If this looks like it's copy/pasted from above, that's because it is.
111 // gcc has a bug (fixed in 4.9) that doesn't allow capturing variadic
112 // params in a lambda.
113 std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
115 auto it2 = evb.localStorage_.find(key_);
116 if (LIKELY(it2 != evb.localStorage_.end())) {
117 return *static_cast<T*>(it2->second.get());
119 std::shared_ptr<T> smartPtr(fn());
120 auto ptr = smartPtr.get();
121 setVoidUnlocked(evb, std::move(smartPtr));