Not to use EventBaseLocal on mobile
[folly.git] / folly / io / async / EventBaseLocal.h
1 /*
2  * Copyright 2015 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 #if !defined(ANDROID) && !defined(__ANDROID__) && !defined(__APPLE__)
20
21 #include <boost/noncopyable.hpp>
22 #include <folly/Synchronized.h>
23 #include <folly/io/async/EventBase.h>
24 #include <memory>
25 #include <mutex>
26 #include <unordered_map>
27 #include <unordered_set>
28
29 namespace folly {
30
31 namespace detail {
32
33 class EventBaseLocalBase : boost::noncopyable {
34  public:
35   EventBaseLocalBase() {}
36   virtual ~EventBaseLocalBase();
37   void erase(EventBase& evb);
38   void onEventBaseDestruction(EventBase& evb);
39
40  protected:
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);
44
45   folly::Synchronized<std::unordered_set<EventBase*>> eventBases_;
46   static std::atomic<uint64_t> keyCounter_;
47   uint64_t key_{keyCounter_++};
48 };
49
50 }
51
52 /**
53  * A storage abstraction for data that should be tied to an EventBase.
54  *
55  *   struct Foo { Foo(int a, int b); };
56  *   EventBaseLocal<Foo> myFoo;
57  *   ...
58  *   EventBase evb;
59  *   myFoo.set(evb, new Foo(1, 2));
60  *   myFoo.set(evb, 1, 2);
61  *   Foo* foo = myFoo.get(evb);
62  *   myFoo.erase(evb);
63  *   Foo& foo = myFoo.getOrCreate(evb, 1, 2); // ctor
64  *   Foo& foo = myFoo.getOrCreate(evb, 1, 2); // no ctor
65  *   myFoo.erase(evb);
66  *   Foo& foo = myFoo.getOrCreateFn(evb, [] () { return new Foo(3, 4); })
67  *
68  * The objects will be deleted when the EventBaseLocal or the EventBase is
69  * destructed (whichever comes first).  All methods are thread-safe.
70  *
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<...>>.
74  */
75 template<typename T>
76 class EventBaseLocal : public detail::EventBaseLocalBase {
77  public:
78   EventBaseLocal(): EventBaseLocalBase() {}
79
80   T* get(EventBase& evb) {
81     return static_cast<T*>(getVoid(evb));
82   }
83
84   void emplace(EventBase& evb, T* ptr) {
85     std::shared_ptr<T> smartPtr(ptr);
86     setVoid(evb, std::move(smartPtr));
87   }
88
89   template<typename... Args>
90   void emplace(EventBase& evb, Args... args) {
91     auto smartPtr = std::make_shared<T>(args...);
92     setVoid(evb, smartPtr);
93   }
94
95   template<typename... Args>
96   T& getOrCreate(EventBase& evb, Args... args) {
97     std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
98
99     auto it2 = evb.localStorage_.find(key_);
100     if (LIKELY(it2 != evb.localStorage_.end())) {
101       return *static_cast<T*>(it2->second.get());
102     } else {
103       auto smartPtr = std::make_shared<T>(args...);
104       auto ptr = smartPtr.get();
105       setVoidUnlocked(evb, std::move(smartPtr));
106       return *ptr;
107     }
108   }
109
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_);
116
117     auto it2 = evb.localStorage_.find(key_);
118     if (LIKELY(it2 != evb.localStorage_.end())) {
119       return *static_cast<T*>(it2->second.get());
120     } else {
121       std::shared_ptr<T> smartPtr(fn());
122       auto ptr = smartPtr.get();
123       setVoidUnlocked(evb, std::move(smartPtr));
124       return *ptr;
125     }
126   }
127 };
128
129
130 }
131
132 #endif // !__ANDROID__ && !ANDROID && !__APPLE__