2 * Copyright 2015 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 #if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__APPLE__)
21 #include <boost/noncopyable.hpp>
22 #include <folly/Synchronized.h>
23 #include <folly/io/async/EventBase.h>
26 #include <unordered_map>
27 #include <unordered_set>
33 class EventBaseLocalBase : boost::noncopyable {
35 EventBaseLocalBase() {}
36 virtual ~EventBaseLocalBase();
37 void erase(EventBase& evb);
38 void onEventBaseDestruction(EventBase& evb);
41 void setVoid(EventBase& evb, std::shared_ptr<void>&& ptr);
42 void setVoidUnlocked(EventBase& evb, std::shared_ptr<void>&& ptr);
43 void* getVoid(EventBase& evb);
45 folly::Synchronized<std::unordered_set<EventBase*>> eventBases_;
46 static std::atomic<uint64_t> keyCounter_;
47 uint64_t key_{keyCounter_++};
53 * A storage abstraction for data that should be tied to an EventBase.
55 * struct Foo { Foo(int a, int b); };
56 * EventBaseLocal<Foo> myFoo;
59 * myFoo.set(evb, new Foo(1, 2));
60 * myFoo.set(evb, 1, 2);
61 * Foo* foo = myFoo.get(evb);
63 * Foo& foo = myFoo.getOrCreate(evb, 1, 2); // ctor
64 * Foo& foo = myFoo.getOrCreate(evb, 1, 2); // no ctor
66 * Foo& foo = myFoo.getOrCreateFn(evb, [] () { return new Foo(3, 4); })
68 * The objects will be deleted when the EventBaseLocal or the EventBase is
69 * destructed (whichever comes first). All methods are thread-safe.
71 * The user is responsible for throwing away invalid references/ptrs returned
72 * by the get() method after set/erase is called. If shared ownership is
73 * needed, use a EventBaseLocal<shared_ptr<...>>.
76 class EventBaseLocal : public detail::EventBaseLocalBase {
78 EventBaseLocal(): EventBaseLocalBase() {}
80 T* get(EventBase& evb) {
81 return static_cast<T*>(getVoid(evb));
84 void emplace(EventBase& evb, T* ptr) {
85 std::shared_ptr<T> smartPtr(ptr);
86 setVoid(evb, std::move(smartPtr));
89 template<typename... Args>
90 void emplace(EventBase& evb, Args... args) {
91 auto smartPtr = std::make_shared<T>(args...);
92 setVoid(evb, smartPtr);
95 template<typename... Args>
96 T& getOrCreate(EventBase& evb, Args... args) {
97 std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
99 auto it2 = evb.localStorage_.find(key_);
100 if (LIKELY(it2 != evb.localStorage_.end())) {
101 return *static_cast<T*>(it2->second.get());
103 auto smartPtr = std::make_shared<T>(args...);
104 auto ptr = smartPtr.get();
105 setVoidUnlocked(evb, std::move(smartPtr));
110 template <typename Func>
111 T& getOrCreateFn(EventBase& evb, Func& fn) {
112 // If this looks like it's copy/pasted from above, that's because it is.
113 // gcc has a bug (fixed in 4.9) that doesn't allow capturing variadic
114 // params in a lambda.
115 std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
117 auto it2 = evb.localStorage_.find(key_);
118 if (LIKELY(it2 != evb.localStorage_.end())) {
119 return *static_cast<T*>(it2->second.get());
121 std::shared_ptr<T> smartPtr(fn());
122 auto ptr = smartPtr.get();
123 setVoidUnlocked(evb, std::move(smartPtr));
132 #endif // !__ANDROID__ && !ANDROID && !__APPLE__