Make EventBaseLocal::getOrCreate work with noncopyable args
authorVictor Zverovich <viz@fb.com>
Sat, 18 Mar 2017 13:29:19 +0000 (06:29 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sat, 18 Mar 2017 13:34:37 +0000 (06:34 -0700)
Summary: Use perfect forwarding in `EventBaseLocal::getOrCreate` to make it work with noncopyable but moveable arguments.

Reviewed By: yfeldblum

Differential Revision: D4730566

fbshipit-source-id: fa02348b7a9217fef980ec5e743b5990b9d19e9a

folly/io/async/EventBaseLocal.h
folly/io/async/test/EventBaseLocalTest.cpp

index 4a4a10b..41f76a7 100644 (file)
@@ -21,8 +21,8 @@
 #include <folly/io/async/EventBase.h>
 #include <memory>
 #include <mutex>
-#include <unordered_map>
 #include <unordered_set>
+#include <utility>
 
 namespace folly {
 
@@ -84,21 +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) {
+  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 smartPtr = std::make_shared<T>(std::forward<Args>(args)...);
       auto ptr = smartPtr.get();
       setVoidUnlocked(evb, std::move(smartPtr));
       return *ptr;
index 96ff491..f7b963a 100644 (file)
@@ -87,3 +87,23 @@ TEST(EventBaseLocalTest, getOrCreate) {
   auto creator = []() { return new int(4); };
   EXPECT_EQ(ints.getOrCreateFn(evb2, creator), 4);
 }
+
+using IntPtr = std::unique_ptr<int>;
+
+TEST(EventBaseLocalTest, getOrCreateNoncopyable) {
+  folly::EventBase evb1;
+  folly::EventBaseLocal<IntPtr> ints;
+
+  EXPECT_EQ(ints.getOrCreate(evb1), IntPtr());
+  EXPECT_EQ(ints.getOrCreate(evb1, std::make_unique<int>(5)), IntPtr());
+
+  folly::EventBase evb2;
+  EXPECT_EQ(*ints.getOrCreate(evb2, std::make_unique<int>(5)), 5);
+}
+
+TEST(EventBaseLocalTest, emplaceNoncopyable) {
+  folly::EventBase evb;
+  folly::EventBaseLocal<IntPtr> ints;
+  ints.emplace(evb, std::make_unique<int>(42));
+  EXPECT_EQ(42, **ints.get(evb));
+}