diff --git a/util/SingleWriterValueList.cpp b/util/SingleWriterValueList.cpp deleted file mode 100644 index 005c3a06..00000000 --- a/util/SingleWriterValueList.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "SingleWriterValueList.h" - -namespace facebook { -namespace yoga { -namespace detail { - -void* FreeList::getRaw() { - if (free_.size() == 0) - return nullptr; - - auto ptr = free_.top(); - free_.pop(); - return ptr; -} - -void FreeList::put(std::mutex& mutex, void* ptr) { - std::lock_guard lock{mutex}; - free_.push(ptr); -} - -FreeList::FreeList() = default; -FreeList::~FreeList() = default; - -} // namespace detail -} // namespace yoga -} // namespace facebook diff --git a/util/SingleWriterValueList.h b/util/SingleWriterValueList.h deleted file mode 100644 index b8563565..00000000 --- a/util/SingleWriterValueList.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include - -#ifndef YOGA_EXPORT -#ifdef _MSC_VER -#define YOGA_EXPORT -#else -#define YOGA_EXPORT __attribute__((visibility("default"))) -#endif -#endif - -namespace facebook { -namespace yoga { - -namespace detail { - -class YOGA_EXPORT FreeList { - std::stack free_; - void* getRaw(); - -public: - FreeList(); - ~FreeList(); - - void put(std::mutex&, void*); - - template - T* get() { - return static_cast(getRaw()); - } -}; - -} // namespace detail - -/// SingleWriterValueList is a data structure that holds a list of values. Each -/// value can be borrowed for exclusive writing, and will not be exposed to -/// another borrower until returned. -/// Additionaly, the whole list of values can be accessed for reading via const -/// iterators. Read consistency depends on CPU internals, i.e. whether values -/// are written to memory atomically. -/// -/// A typical usage scenario would be a set of threads, where each thread -/// borrows a value for lock free writing, e.g. as a thread local variable. This -/// avoids the usage of atomics, or locking of shared memory, which both can -/// lead to increased latency due to CPU cache flushes and waits. -/// -/// Values are heap allocated (via forward_list), which typically will avoid -/// multiple values being allocated in the same CPU cache line, which would also -/// lead to cache flushing. -/// -/// SingleWriterValueList never deallocates, to guarantee the validity of -/// references and iterators. However, memory returned by a borrower can be -/// borrowed again. -/// -/// SingleWriterValueList supports return policies as second template parameter, -/// i.e. an optional mutation of values after a borrower returns them. The -/// default policy is to do nothing. SingleWriterValueList::resetPolicy is a -/// convenience method that will move assign the default value of a type. -/// -/// Example: -/// -/// static SingleWriterValueList counters; -/// thread_local auto localCounter = counters.borrow(); -/// -/// /* per thread */ -/// localCounter =+ n; -/// -/// /* anywhere */ -/// std::accumulate(counters.begin(), counters.end(), 0); -/// -template -class YOGA_EXPORT SingleWriterValueList { - std::forward_list values_{}; - std::mutex acquireMutex_{}; - detail::FreeList freeValuesList_{}; - - T* allocValue() { - values_.emplace_front(); - return &values_.front(); - } - - void returnRef(T* value) { - if (ReturnPolicy != nullptr) { - ReturnPolicy(*value); - } - freeValuesList_.put(acquireMutex_, value); - } - -public: - using const_iterator = decltype(values_.cbegin()); - - /// RAII representation of a single value, borrowed for exclusive writing. - /// Instances cannot be copied, and will return the borrowed value to the - /// owner upon destruction. - class Borrowed { - T* value_; - SingleWriterValueList* owner_; - - public: - Borrowed(T* value, SingleWriterValueList* owner) - : value_{value}, owner_{owner} {} - ~Borrowed() { - if (owner_ != nullptr && value_ != nullptr) { - owner_->returnRef(value_); - } - } - - Borrowed(Borrowed&& other) = default; - Borrowed& operator=(Borrowed&& other) = default; - - // no copies allowed - Borrowed(const Borrowed&) = delete; - Borrowed& operator=(const Borrowed&) = delete; - - T& get() { return *value_; } - T& operator*() { return get(); } - }; - - Borrowed borrow() { - std::lock_guard lock{acquireMutex_}; - T* value = freeValuesList_.get(); - return {value != nullptr ? value : allocValue(), this}; - } - - const_iterator cbegin() const { return values_.cbegin(); }; - const_iterator cend() const { return values_.cend(); }; - const_iterator begin() const { return cbegin(); }; - const_iterator end() const { return cend(); }; - - static void resetPolicy(T& value) { value = std::move(T{}); } -}; - -} // namespace yoga -} // namespace facebook diff --git a/util/SingleWriterValueListTest.cpp b/util/SingleWriterValueListTest.cpp deleted file mode 100644 index 692cd144..00000000 --- a/util/SingleWriterValueListTest.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include -#include - -#include -#include -#include - -namespace facebook { -namespace yoga { - -static_assert( - !std::is_copy_constructible>::value, - "SingleWriterValueList must not be copyable"); -static_assert( - !std::is_copy_assignable>::value, - "SingleWriterValueList must not be copyable"); -static_assert( - !std::is_copy_constructible::Borrowed>::value, - "SingleWriterValueList::Borrowed must not be copyable"); -static_assert( - !std::is_copy_assignable::Borrowed>::value, - "SingleWriterValueList::Borrowed must not be copyable"); -static_assert( - std::is_move_constructible::Borrowed>::value, - "SingleWriterValueList::Borrowed must be movable"); -static_assert( - std::is_move_assignable::Borrowed>::value, - "SingleWriterValueList::Borrowed must be movable"); - -TEST(SingleWriterValueList, borrowsAreExclusive) { - SingleWriterValueList x{}; - - auto a = x.borrow(); - auto b = x.borrow(); - - ASSERT_NE(&a.get(), &b.get()); -} - -TEST(SingleWriterValueList, borrowsSupportDereference) { - SingleWriterValueList x{}; - - auto a = x.borrow(); - *a = 123; - - ASSERT_EQ(*a, 123); -} - -TEST(SingleWriterValueList, borrowsHaveGetMethod) { - SingleWriterValueList x{}; - - auto a = x.borrow(); - a.get() = 123; - - ASSERT_EQ(a.get(), 123); -} - -TEST(SingleWriterValueList, exposesBorrowsViaIterator) { - SingleWriterValueList x{}; - - auto a = x.borrow(); - auto b = x.borrow(); - - *a = 12; - *b = 34; - - int sum = 0; - for (auto& i : x) { - sum += i; - } - ASSERT_EQ(sum, 12 + 34); -} - -TEST(SingleWriterValueList, exposesBorrowsViaConstIterator) { - SingleWriterValueList x{}; - - auto a = x.borrow(); - auto b = x.borrow(); - - *a = 12; - *b = 34; - - ASSERT_EQ(std::accumulate(x.cbegin(), x.cend(), 0), 12 + 34); -} - -TEST(SingleWriterValueList, doesNotDeallocateReturnedBorrows) { - SingleWriterValueList x{}; - - std::unordered_set values; - { - auto a = x.borrow(); - auto b = x.borrow(); - values.insert(&a.get()); - values.insert(&b.get()); - } - - auto it = x.begin(); - - ASSERT_NE(it, x.end()); - ASSERT_NE(values.find(&*it), values.end()); - - ASSERT_NE(++it, x.end()); - ASSERT_NE(values.find(&*it), values.end()); -} - -TEST(SingleWriterValueList, reusesReturnedBorrows) { - SingleWriterValueList x{}; - - int* firstBorrow; - { - auto a = x.borrow(); - firstBorrow = &a.get(); - } - - auto b = x.borrow(); - - ASSERT_EQ(&b.get(), firstBorrow); -} - -TEST(SingleWriterValueList, keepsValuesAfterReturning) { - SingleWriterValueList x{}; - - { - auto a = x.borrow(); - *a = 123; - } - - ASSERT_EQ(*x.begin(), 123); -} - -static void addOne(int& v) { - v += 1; -} - -TEST(SingleWriterValueList, allowsCustomReturnPolicy) { - SingleWriterValueList x{}; - - { - auto a = x.borrow(); - *a = 123; - } - - ASSERT_EQ(*x.begin(), 124); -} - -TEST(SingleWriterValueList, hasConvenienceResetPolicy) { - SingleWriterValueList::resetPolicy> x{}; - - { - auto a = x.borrow(); - *a = 123; - } - - ASSERT_EQ(*x.begin(), 0); -} - -} // namespace yoga -} // namespace facebook