folly: avoid compile warning/failure due to lvalue-to-rvalue conversion
[folly.git] / folly / io / async / EventBaseLocal.h
index 78e35f0a2e052ac398dc0bd345b3d5831499ddec..8e4bdce3b77b4b98bb6b90a75e47f84db07cb8ae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,8 +21,8 @@
 #include <folly/io/async/EventBase.h>
 #include <memory>
 #include <mutex>
-#include <unordered_map>
 #include <unordered_set>
+#include <utility>
 
 namespace folly {
 
@@ -31,13 +31,12 @@ namespace detail {
 class EventBaseLocalBase : public EventBaseLocalBaseBase, boost::noncopyable {
  public:
   EventBaseLocalBase() {}
-  virtual ~EventBaseLocalBase();
+  ~EventBaseLocalBase() override;
   void erase(EventBase& evb);
   void onEventBaseDestruction(EventBase& evb) override;
 
  protected:
   void setVoid(EventBase& evb, std::shared_ptr<void>&& ptr);
-  void setVoidUnlocked(EventBase& evb, std::shared_ptr<void>&& ptr);
   void* getVoid(EventBase& evb);
 
   folly::Synchronized<std::unordered_set<EventBase*>> eventBases_;
@@ -45,7 +44,7 @@ class EventBaseLocalBase : public EventBaseLocalBaseBase, boost::noncopyable {
   uint64_t key_{keyCounter_++};
 };
 
-}
+} // namespace detail
 
 /**
  * A storage abstraction for data that should be tied to an EventBase.
@@ -64,13 +63,14 @@ class EventBaseLocalBase : public EventBaseLocalBaseBase, boost::noncopyable {
  *   Foo& foo = myFoo.getOrCreateFn(evb, [] () { return new Foo(3, 4); })
  *
  * The objects will be deleted when the EventBaseLocal or the EventBase is
- * destructed (whichever comes first).  All methods are thread-safe.
+ * destructed (whichever comes first). All methods must be called from the
+ * EventBase thread.
  *
  * The user is responsible for throwing away invalid references/ptrs returned
  * by the get() method after set/erase is called.  If shared ownership is
  * needed, use a EventBaseLocal<shared_ptr<...>>.
  */
-template<typename T>
+template <typename T>
 class EventBaseLocal : public detail::EventBaseLocalBase {
  public:
   EventBaseLocal(): EventBaseLocalBase() {}
@@ -84,25 +84,21 @@ class EventBaseLocal : public detail::EventBaseLocalBase {
     setVoid(evb, std::move(smartPtr));
   }
 
-  template<typename... Args>
-  void emplace(EventBase& evb, Args... args) {
-    auto smartPtr = std::make_shared<T>(args...);
+  template <typename... Args>
+  void emplace(EventBase& evb, Args&&... args) {
+    auto smartPtr = std::make_shared<T>(std::forward<Args>(args)...);
     setVoid(evb, smartPtr);
   }
 
-  template<typename... Args>
-  T& getOrCreate(EventBase& evb, Args... args) {
-    std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
-
-    auto it2 = evb.localStorage_.find(key_);
-    if (LIKELY(it2 != evb.localStorage_.end())) {
-      return *static_cast<T*>(it2->second.get());
-    } else {
-      auto smartPtr = std::make_shared<T>(args...);
-      auto ptr = smartPtr.get();
-      setVoidUnlocked(evb, std::move(smartPtr));
-      return *ptr;
+  template <typename... Args>
+  T& getOrCreate(EventBase& evb, Args&&... args) {
+    if (auto ptr = getVoid(evb)) {
+      return *static_cast<T*>(ptr);
     }
+    auto smartPtr = std::make_shared<T>(std::forward<Args>(args)...);
+    auto& ref = *smartPtr;
+    setVoid(evb, std::move(smartPtr));
+    return ref;
   }
 
   template <typename Func>
@@ -110,19 +106,14 @@ class EventBaseLocal : public detail::EventBaseLocalBase {
     // If this looks like it's copy/pasted from above, that's because it is.
     // gcc has a bug (fixed in 4.9) that doesn't allow capturing variadic
     // params in a lambda.
-    std::lock_guard<std::mutex> lg(evb.localStorageMutex_);
-
-    auto it2 = evb.localStorage_.find(key_);
-    if (LIKELY(it2 != evb.localStorage_.end())) {
-      return *static_cast<T*>(it2->second.get());
-    } else {
-      std::shared_ptr<T> smartPtr(fn());
-      auto ptr = smartPtr.get();
-      setVoidUnlocked(evb, std::move(smartPtr));
-      return *ptr;
+    if (auto ptr = getVoid(evb)) {
+      return *static_cast<T*>(ptr);
     }
+    std::shared_ptr<T> smartPtr(fn());
+    auto& ref = *smartPtr;
+    setVoid(evb, std::move(smartPtr));
+    return ref;
   }
 };
 
-
-}
+} // namespace folly