Fixes RCU test cases error (loads should use Consume ordering)
[folly.git] / folly / test / SynchronizedPtrTest.cpp
1 /*
2  * Copyright 2017-present 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 #include <folly/SynchronizedPtr.h>
17
18 #include <folly/Optional.h>
19 #include <folly/Replaceable.h>
20 #include <folly/portability/GTest.h>
21 #include <folly/synchronization/RWSpinLock.h>
22
23 template <typename SPtr>
24 void basics(SPtr& sptr) {
25   EXPECT_TRUE((std::is_same<int const&, decltype(*sptr.rlock())>::value));
26   auto initialValue = *sptr.rlock();
27   bool rlockedTypeOK{false};
28   sptr.withRLock([&](auto&& value) {
29     rlockedTypeOK = std::is_same<int const&, decltype(value)>::value;
30   });
31   EXPECT_TRUE(rlockedTypeOK);
32   EXPECT_TRUE((std::is_same<int&, decltype(*sptr.wlock())>::value));
33   bool wlockedTypeOK{false};
34   sptr.withWLock([&](auto&& value) {
35     wlockedTypeOK = std::is_same<int&, decltype(value)>::value;
36     ++value;
37   });
38   EXPECT_TRUE(wlockedTypeOK);
39   EXPECT_EQ(initialValue + 1, *sptr.rlock());
40 }
41
42 TEST(SynchronizedPtrTest, Shared) {
43   folly::SynchronizedPtr<std::shared_ptr<int>> pInt{std::make_shared<int>(0)};
44   basics(pInt);
45 }
46
47 TEST(SynchronizedPtrTest, UniqueBasic) {
48   folly::SynchronizedPtr<std::unique_ptr<int>> pInt{std::make_unique<int>(0)};
49   basics(pInt);
50 }
51
52 TEST(SynchronizedPtrTest, UniqueDeleter) {
53   bool calledDeleter = false;
54   auto x = [&](int* ptr) {
55     delete ptr;
56     calledDeleter = true;
57   };
58   {
59     folly::SynchronizedPtr<std::unique_ptr<int, decltype(x)>> pInt{
60         std::unique_ptr<int, decltype(x)>(new int(0), x)};
61     basics(pInt);
62     EXPECT_TRUE((std::is_same<
63                  std::unique_ptr<int, decltype(x)>&,
64                  decltype(*pInt.wlockPointer())>::value));
65     pInt.wlockPointer()->reset(new int(5));
66     EXPECT_TRUE(calledDeleter);
67     calledDeleter = false;
68   }
69   EXPECT_TRUE(calledDeleter);
70 }
71
72 TEST(SynchronizedPtrTest, Replaceable) {
73   folly::SynchronizedPtr<folly::Replaceable<int>> pInt{0};
74   folly::SynchronizedPtr<folly::Replaceable<int const>> pcInt{2};
75   basics(pInt);
76   EXPECT_TRUE(
77       (std::is_same<folly::Replaceable<int>&, decltype(*pInt.wlockPointer())>::
78            value));
79   EXPECT_TRUE((std::is_same<
80                folly::Replaceable<int const>&,
81                decltype(*pcInt.wlockPointer())>::value));
82   pcInt.withWLockPointer([](auto&& ptr) {
83     EXPECT_TRUE(
84         (std::is_same<folly::Replaceable<int const>&, decltype(ptr)>::value));
85     ptr.emplace(4);
86   });
87   EXPECT_EQ(4, *pcInt.rlock());
88 }
89
90 TEST(SynchronizedPtrTest, Optional) {
91   folly::SynchronizedPtr<folly::Optional<int>, folly::RWSpinLock> pInt{0};
92   basics(pInt);
93   EXPECT_TRUE(
94       (std::is_same<folly::Optional<int>&, decltype(*pInt.wlockPointer())>::
95            value));
96   EXPECT_TRUE(static_cast<bool>(pInt.rlock()));
97   pInt.withWLockPointer([](auto&& ptr) {
98     EXPECT_TRUE((std::is_same<folly::Optional<int>&, decltype(ptr)>::value));
99     ptr.clear();
100   });
101   EXPECT_FALSE(static_cast<bool>(pInt.rlock()));
102 }
103
104 TEST(SynchronizedPtrTest, Virtual) {
105   struct A {
106     virtual void poke(bool&) const {}
107     virtual ~A() = default;
108   };
109   struct B : A {
110     void poke(bool& b) const override {
111       b = true;
112     }
113   };
114   folly::SynchronizedPtr<A*> pA{new B()};
115   bool itWorks = false;
116   pA.rlock()->poke(itWorks);
117   EXPECT_TRUE(itWorks);
118   itWorks = false;
119   pA.wlock()->poke(itWorks);
120   EXPECT_TRUE(itWorks);
121   pA.withWLockPointer([](auto&& ptr) {
122     EXPECT_TRUE((std::is_same<A*&, decltype(ptr)>::value));
123     delete ptr;
124     ptr = new B();
125   });
126   {
127     auto lockedPtr = pA.wlockPointer();
128     EXPECT_TRUE((std::is_same<A*&, decltype(*lockedPtr)>::value));
129     delete *lockedPtr;
130     *lockedPtr = new B();
131   }
132   itWorks = false;
133   pA.wlock()->poke(itWorks);
134   EXPECT_TRUE(itWorks);
135   delete *pA.wlockPointer();
136 }