Move folly/AtomicStruct.h to folly/synchronization/
authorYedidya Feldblum <yfeldblum@fb.com>
Tue, 26 Dec 2017 01:07:39 +0000 (17:07 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Tue, 26 Dec 2017 01:23:42 +0000 (17:23 -0800)
Summary: [Folly] Move `folly/AtomicStruct.h` to `folly/synchronization/`.

Reviewed By: Orvid

Differential Revision: D6636072

fbshipit-source-id: 87098e25fc40d0d60b4a657ba395418388e170fc

folly/AtomicStruct.h [deleted file]
folly/IndexedMemPool.h
folly/Makefile.am
folly/concurrency/AtomicSharedPtr.h
folly/detail/MemoryIdler.h
folly/synchronization/AtomicStruct.h [new file with mode: 0644]
folly/synchronization/LifoSem.h
folly/synchronization/test/AtomicStructTest.cpp [new file with mode: 0644]
folly/test/AtomicStructTest.cpp [deleted file]

diff --git a/folly/AtomicStruct.h b/folly/AtomicStruct.h
deleted file mode 100644 (file)
index a774d31..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <folly/Traits.h>
-#include <folly/synchronization/detail/AtomicUtils.h>
-#include <stdint.h>
-#include <string.h>
-#include <atomic>
-#include <type_traits>
-
-namespace folly {
-
-namespace detail {
-template <int N> struct AtomicStructIntPick {};
-} // namespace detail
-
-/// AtomicStruct<T> work like C++ atomics, but can be used on any POD
-/// type <= 8 bytes.
-template <
-    typename T,
-    template <typename> class Atom = std::atomic,
-    typename Raw = typename detail::AtomicStructIntPick<sizeof(T)>::type>
-class AtomicStruct {
-  static_assert(alignof(T) <= alignof(Raw),
-      "target type can't have stricter alignment than matching int");
-  static_assert(sizeof(T) <= sizeof(Raw),
-      "underlying type isn't big enough");
-  static_assert(std::is_trivial<T>::value ||
-                folly::IsTriviallyCopyable<T>::value,
-      "target type must be trivially copyable");
-
-  union {
-    Atom<Raw> data;
-    T typedData;
-  };
-
-  static Raw encode(T v) noexcept {
-    // we expect the compiler to optimize away the memcpy, but without
-    // it we would violate strict aliasing rules
-    Raw d = 0;
-    memcpy(&d, &v, sizeof(T));
-    return d;
-  }
-
-  static T decode(Raw d) noexcept {
-    T v;
-    memcpy(&v, &d, sizeof(T));
-    return v;
-  }
-
- public:
-  AtomicStruct() = default;
-  ~AtomicStruct() = default;
-  AtomicStruct(AtomicStruct<T> const &) = delete;
-  AtomicStruct<T>& operator= (AtomicStruct<T> const &) = delete;
-
-  constexpr /* implicit */ AtomicStruct(T v) noexcept : typedData(v) {}
-
-  bool is_lock_free() const noexcept {
-    return data.is_lock_free();
-  }
-
-  bool compare_exchange_strong(
-      T& v0,
-      T v1,
-      std::memory_order mo = std::memory_order_seq_cst) noexcept {
-    return compare_exchange_strong(
-        v0, v1, mo, detail::default_failure_memory_order(mo));
-  }
-  bool compare_exchange_strong(
-      T& v0,
-      T v1,
-      std::memory_order success,
-      std::memory_order failure) noexcept {
-    Raw d0 = encode(v0);
-    bool rv = data.compare_exchange_strong(d0, encode(v1), success, failure);
-    if (!rv) {
-      v0 = decode(d0);
-    }
-    return rv;
-  }
-
-  bool compare_exchange_weak(
-      T& v0,
-      T v1,
-      std::memory_order mo = std::memory_order_seq_cst) noexcept {
-    return compare_exchange_weak(
-        v0, v1, mo, detail::default_failure_memory_order(mo));
-  }
-  bool compare_exchange_weak(
-      T& v0,
-      T v1,
-      std::memory_order success,
-      std::memory_order failure) noexcept {
-    Raw d0 = encode(v0);
-    bool rv = data.compare_exchange_weak(d0, encode(v1), success, failure);
-    if (!rv) {
-      v0 = decode(d0);
-    }
-    return rv;
-  }
-
-  T exchange(T v, std::memory_order mo = std::memory_order_seq_cst) noexcept {
-    return decode(data.exchange(encode(v), mo));
-  }
-
-  /* implicit */ operator T () const noexcept {
-    return decode(data);
-  }
-
-  T load(std::memory_order mo = std::memory_order_seq_cst) const noexcept {
-    return decode(data.load(mo));
-  }
-
-  T operator= (T v) noexcept {
-    return decode(data = encode(v));
-  }
-
-  void store(T v, std::memory_order mo = std::memory_order_seq_cst) noexcept {
-    data.store(encode(v), mo);
-  }
-
-  // std::atomic also provides volatile versions of all of the access
-  // methods.  These are callable on volatile objects, and also can
-  // theoretically have different implementations than their non-volatile
-  // counterpart.  If someone wants them here they can easily be added
-  // by duplicating the above code and the corresponding unit tests.
-};
-
-namespace detail {
-
-template <> struct AtomicStructIntPick<1> { typedef uint8_t type; };
-template <> struct AtomicStructIntPick<2> { typedef uint16_t type; };
-template <> struct AtomicStructIntPick<3> { typedef uint32_t type; };
-template <> struct AtomicStructIntPick<4> { typedef uint32_t type; };
-template <> struct AtomicStructIntPick<5> { typedef uint64_t type; };
-template <> struct AtomicStructIntPick<6> { typedef uint64_t type; };
-template <> struct AtomicStructIntPick<7> { typedef uint64_t type; };
-template <> struct AtomicStructIntPick<8> { typedef uint64_t type; };
-
-} // namespace detail
-
-} // namespace folly
index cab5cac1f437c2faa258c512cabe0c782fd555d5..14661dd7d60980337198c31b8c1ef3034563338a 100644 (file)
 #include <type_traits>
 
 #include <boost/noncopyable.hpp>
-#include <folly/AtomicStruct.h>
 #include <folly/Portability.h>
 #include <folly/concurrency/CacheLocality.h>
 #include <folly/portability/SysMman.h>
 #include <folly/portability/Unistd.h>
+#include <folly/synchronization/AtomicStruct.h>
 
 // Ignore shadowing warnings within this file, so includers can use -Wshadow.
 FOLLY_PUSH_WARNING
index 6df61c3c6a3c2ed362394de1b8182b1123f7f7e3..ec1e2e671a7a893707a230b561c4eb6715ddbedb 100644 (file)
@@ -34,7 +34,6 @@ nobase_follyinclude_HEADERS = \
        AtomicHashMap-inl.h \
        AtomicIntrusiveLinkedList.h \
        AtomicLinkedList.h \
-       AtomicStruct.h \
        AtomicUnorderedMap.h \
        Benchmark.h \
        Bits.h \
@@ -436,6 +435,7 @@ nobase_follyinclude_HEADERS = \
        stats/TimeseriesHistogram-defs.h \
        stats/TimeseriesHistogram.h \
        synchronization/AsymmetricMemoryBarrier.h \
+       synchronization/AtomicStruct.h \
        synchronization/Baton.h \
        synchronization/CallOnce.h \
        synchronization/LifoSem.h \
index d1b2aa7a1d888714f2d79befbd6c5de0c55f9303..7b2e697e507184ed72a41330bb7e37316f888018 100644 (file)
@@ -15,9 +15,9 @@
  */
 #pragma once
 
-#include <folly/AtomicStruct.h>
 #include <folly/PackedSyncPtr.h>
 #include <folly/concurrency/detail/AtomicSharedPtr-detail.h>
+#include <folly/synchronization/AtomicStruct.h>
 #include <folly/synchronization/detail/AtomicUtils.h>
 #include <atomic>
 #include <thread>
index 1cabfecc558eea838d8873769b7378df3cb9f2b0..1a924b578e4b260a4baa1eecd2d697bdecaa6602 100644 (file)
 #include <atomic>
 #include <chrono>
 
-#include <folly/AtomicStruct.h>
 #include <folly/Traits.h>
 #include <folly/detail/Futex.h>
 #include <folly/hash/Hash.h>
+#include <folly/synchronization/AtomicStruct.h>
 #include <folly/system/ThreadId.h>
 
 namespace folly {
diff --git a/folly/synchronization/AtomicStruct.h b/folly/synchronization/AtomicStruct.h
new file mode 100644 (file)
index 0000000..a774d31
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <folly/Traits.h>
+#include <folly/synchronization/detail/AtomicUtils.h>
+#include <stdint.h>
+#include <string.h>
+#include <atomic>
+#include <type_traits>
+
+namespace folly {
+
+namespace detail {
+template <int N> struct AtomicStructIntPick {};
+} // namespace detail
+
+/// AtomicStruct<T> work like C++ atomics, but can be used on any POD
+/// type <= 8 bytes.
+template <
+    typename T,
+    template <typename> class Atom = std::atomic,
+    typename Raw = typename detail::AtomicStructIntPick<sizeof(T)>::type>
+class AtomicStruct {
+  static_assert(alignof(T) <= alignof(Raw),
+      "target type can't have stricter alignment than matching int");
+  static_assert(sizeof(T) <= sizeof(Raw),
+      "underlying type isn't big enough");
+  static_assert(std::is_trivial<T>::value ||
+                folly::IsTriviallyCopyable<T>::value,
+      "target type must be trivially copyable");
+
+  union {
+    Atom<Raw> data;
+    T typedData;
+  };
+
+  static Raw encode(T v) noexcept {
+    // we expect the compiler to optimize away the memcpy, but without
+    // it we would violate strict aliasing rules
+    Raw d = 0;
+    memcpy(&d, &v, sizeof(T));
+    return d;
+  }
+
+  static T decode(Raw d) noexcept {
+    T v;
+    memcpy(&v, &d, sizeof(T));
+    return v;
+  }
+
+ public:
+  AtomicStruct() = default;
+  ~AtomicStruct() = default;
+  AtomicStruct(AtomicStruct<T> const &) = delete;
+  AtomicStruct<T>& operator= (AtomicStruct<T> const &) = delete;
+
+  constexpr /* implicit */ AtomicStruct(T v) noexcept : typedData(v) {}
+
+  bool is_lock_free() const noexcept {
+    return data.is_lock_free();
+  }
+
+  bool compare_exchange_strong(
+      T& v0,
+      T v1,
+      std::memory_order mo = std::memory_order_seq_cst) noexcept {
+    return compare_exchange_strong(
+        v0, v1, mo, detail::default_failure_memory_order(mo));
+  }
+  bool compare_exchange_strong(
+      T& v0,
+      T v1,
+      std::memory_order success,
+      std::memory_order failure) noexcept {
+    Raw d0 = encode(v0);
+    bool rv = data.compare_exchange_strong(d0, encode(v1), success, failure);
+    if (!rv) {
+      v0 = decode(d0);
+    }
+    return rv;
+  }
+
+  bool compare_exchange_weak(
+      T& v0,
+      T v1,
+      std::memory_order mo = std::memory_order_seq_cst) noexcept {
+    return compare_exchange_weak(
+        v0, v1, mo, detail::default_failure_memory_order(mo));
+  }
+  bool compare_exchange_weak(
+      T& v0,
+      T v1,
+      std::memory_order success,
+      std::memory_order failure) noexcept {
+    Raw d0 = encode(v0);
+    bool rv = data.compare_exchange_weak(d0, encode(v1), success, failure);
+    if (!rv) {
+      v0 = decode(d0);
+    }
+    return rv;
+  }
+
+  T exchange(T v, std::memory_order mo = std::memory_order_seq_cst) noexcept {
+    return decode(data.exchange(encode(v), mo));
+  }
+
+  /* implicit */ operator T () const noexcept {
+    return decode(data);
+  }
+
+  T load(std::memory_order mo = std::memory_order_seq_cst) const noexcept {
+    return decode(data.load(mo));
+  }
+
+  T operator= (T v) noexcept {
+    return decode(data = encode(v));
+  }
+
+  void store(T v, std::memory_order mo = std::memory_order_seq_cst) noexcept {
+    data.store(encode(v), mo);
+  }
+
+  // std::atomic also provides volatile versions of all of the access
+  // methods.  These are callable on volatile objects, and also can
+  // theoretically have different implementations than their non-volatile
+  // counterpart.  If someone wants them here they can easily be added
+  // by duplicating the above code and the corresponding unit tests.
+};
+
+namespace detail {
+
+template <> struct AtomicStructIntPick<1> { typedef uint8_t type; };
+template <> struct AtomicStructIntPick<2> { typedef uint16_t type; };
+template <> struct AtomicStructIntPick<3> { typedef uint32_t type; };
+template <> struct AtomicStructIntPick<4> { typedef uint32_t type; };
+template <> struct AtomicStructIntPick<5> { typedef uint64_t type; };
+template <> struct AtomicStructIntPick<6> { typedef uint64_t type; };
+template <> struct AtomicStructIntPick<7> { typedef uint64_t type; };
+template <> struct AtomicStructIntPick<8> { typedef uint64_t type; };
+
+} // namespace detail
+
+} // namespace folly
index b06ec4ca2501b9fdf6093302a7c175eda79cf2d9..102154cf66230257143fc9082cc86599e65b759d 100644 (file)
 #include <memory>
 #include <system_error>
 
-#include <folly/AtomicStruct.h>
 #include <folly/CachelinePadded.h>
 #include <folly/IndexedMemPool.h>
 #include <folly/Likely.h>
+#include <folly/synchronization/AtomicStruct.h>
 #include <folly/synchronization/Baton.h>
 
 namespace folly {
diff --git a/folly/synchronization/test/AtomicStructTest.cpp b/folly/synchronization/test/AtomicStructTest.cpp
new file mode 100644 (file)
index 0000000..59d3467
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/synchronization/AtomicStruct.h>
+
+#include <folly/portability/GTest.h>
+
+using namespace folly;
+
+struct TwoBy32 {
+  uint32_t left;
+  uint32_t right;
+};
+
+TEST(AtomicStruct, two_by_32) {
+  AtomicStruct<TwoBy32> a(TwoBy32{ 10, 20 });
+  TwoBy32 av = a;
+  EXPECT_EQ(av.left, 10);
+  EXPECT_EQ(av.right, 20);
+  EXPECT_TRUE(a.compare_exchange_strong(av, TwoBy32{ 30, 40 }));
+  EXPECT_FALSE(a.compare_exchange_weak(av, TwoBy32{ 31, 41 }));
+  EXPECT_EQ(av.left, 30);
+  EXPECT_TRUE(a.is_lock_free());
+  auto b = a.exchange(TwoBy32{ 50, 60 });
+  EXPECT_EQ(b.left, 30);
+  EXPECT_EQ(b.right, 40);
+  EXPECT_EQ(a.load().left, 50);
+  a = TwoBy32{ 70, 80 };
+  EXPECT_EQ(a.load().right, 80);
+  a.store(TwoBy32{ 90, 100 });
+  av = a;
+  EXPECT_EQ(av.left, 90);
+  AtomicStruct<TwoBy32> c;
+  c = b;
+  EXPECT_EQ(c.load().right, 40);
+}
+
+TEST(AtomicStruct, size_selection) {
+  struct S1 { char x[1]; };
+  struct S2 { char x[2]; };
+  struct S3 { char x[3]; };
+  struct S4 { char x[4]; };
+  struct S5 { char x[5]; };
+  struct S6 { char x[6]; };
+  struct S7 { char x[7]; };
+  struct S8 { char x[8]; };
+
+  EXPECT_EQ(sizeof(AtomicStruct<S1>), 1);
+  EXPECT_EQ(sizeof(AtomicStruct<S2>), 2);
+  EXPECT_EQ(sizeof(AtomicStruct<S3>), 4);
+  EXPECT_EQ(sizeof(AtomicStruct<S4>), 4);
+  EXPECT_EQ(sizeof(AtomicStruct<S5>), 8);
+  EXPECT_EQ(sizeof(AtomicStruct<S6>), 8);
+  EXPECT_EQ(sizeof(AtomicStruct<S7>), 8);
+  EXPECT_EQ(sizeof(AtomicStruct<S8>), 8);
+}
diff --git a/folly/test/AtomicStructTest.cpp b/folly/test/AtomicStructTest.cpp
deleted file mode 100644 (file)
index 507f164..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/AtomicStruct.h>
-
-#include <folly/portability/GTest.h>
-
-using namespace folly;
-
-struct TwoBy32 {
-  uint32_t left;
-  uint32_t right;
-};
-
-TEST(AtomicStruct, two_by_32) {
-  AtomicStruct<TwoBy32> a(TwoBy32{ 10, 20 });
-  TwoBy32 av = a;
-  EXPECT_EQ(av.left, 10);
-  EXPECT_EQ(av.right, 20);
-  EXPECT_TRUE(a.compare_exchange_strong(av, TwoBy32{ 30, 40 }));
-  EXPECT_FALSE(a.compare_exchange_weak(av, TwoBy32{ 31, 41 }));
-  EXPECT_EQ(av.left, 30);
-  EXPECT_TRUE(a.is_lock_free());
-  auto b = a.exchange(TwoBy32{ 50, 60 });
-  EXPECT_EQ(b.left, 30);
-  EXPECT_EQ(b.right, 40);
-  EXPECT_EQ(a.load().left, 50);
-  a = TwoBy32{ 70, 80 };
-  EXPECT_EQ(a.load().right, 80);
-  a.store(TwoBy32{ 90, 100 });
-  av = a;
-  EXPECT_EQ(av.left, 90);
-  AtomicStruct<TwoBy32> c;
-  c = b;
-  EXPECT_EQ(c.load().right, 40);
-}
-
-TEST(AtomicStruct, size_selection) {
-  struct S1 { char x[1]; };
-  struct S2 { char x[2]; };
-  struct S3 { char x[3]; };
-  struct S4 { char x[4]; };
-  struct S5 { char x[5]; };
-  struct S6 { char x[6]; };
-  struct S7 { char x[7]; };
-  struct S8 { char x[8]; };
-
-  EXPECT_EQ(sizeof(AtomicStruct<S1>), 1);
-  EXPECT_EQ(sizeof(AtomicStruct<S2>), 2);
-  EXPECT_EQ(sizeof(AtomicStruct<S3>), 4);
-  EXPECT_EQ(sizeof(AtomicStruct<S4>), 4);
-  EXPECT_EQ(sizeof(AtomicStruct<S5>), 8);
-  EXPECT_EQ(sizeof(AtomicStruct<S6>), 8);
-  EXPECT_EQ(sizeof(AtomicStruct<S7>), 8);
-  EXPECT_EQ(sizeof(AtomicStruct<S8>), 8);
-}