diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index f5b621a33..60913a1d3 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -31,11 +31,7 @@ set(LIB_UTIL_SRC util/logging/win32_logger.cpp util/lokinet_init.c util/mem.cpp - util/meta/memfn_traits.cpp - util/meta/memfn.cpp - util/meta/object.cpp util/meta/traits.cpp - util/meta/variant.cpp util/printer.cpp util/status.cpp util/str.cpp diff --git a/llarp/util/meta/memfn.hpp b/llarp/util/meta/memfn.hpp index 3ce1b1646..51354088e 100644 --- a/llarp/util/meta/memfn.hpp +++ b/llarp/util/meta/memfn.hpp @@ -1,88 +1,68 @@ #ifndef LLARP_UTIL_MEMFN #define LLARP_UTIL_MEMFN -#include -#include -#include - -#include +#include #include +#include namespace llarp { namespace util { - template < typename Obj > - struct MemFnDereference + // Wraps a member function and instance into a callable object that invokes + // the method (non-const overload). + template < + typename Return, typename Class, typename Derived, typename... Arg, + typename = + std::enable_if_t< std::is_base_of< Class, Derived >::value > > + auto + memFn(Return (Class::*f)(Arg...), Derived* self) { - // clang-format off - static inline Obj& derefImp(Obj& obj, std::false_type) - { - return obj; - } - - template < typename Type > - static inline Obj& derefImp(Type& obj, std::true_type) - { - return *obj; - } - - template < typename Type > - static inline Obj& derefImp(const Type& obj, std::true_type) - { - return *obj; - } - - template < typename Type > - static inline Obj& deref(Type& obj) - { - return derefImp(obj, traits::is_pointy< Type >()); - } - - template < typename Type > - static inline Obj& deref(const Type& obj) - { - return derefImp(obj, traits::is_pointy< Type >()); - } - // clang-format on - }; + return [f, self](Arg... args) { + return (self->*f)(std::forward< Arg >(args)...); + }; + } - template < typename Prototype, typename Instance > - class MemFn + // Wraps a member function and instance into a lambda that invokes the + // method (const overload). + template < + typename Return, typename Class, typename Derived, typename... Arg, + typename = + std::enable_if_t< std::is_base_of< Class, Derived >::value > > + auto + memFn(Return (Class::*f)(Arg...) const, const Derived* self) { - using traits = MemFnTraits< Prototype >; - - static_assert(traits::IsMemFn, ""); - - public: - using result_type = typename traits::result_type; - - private: - Prototype m_func; - object::Proxy< Instance > m_instance; - - using Deref = MemFnDereference< typename traits::class_type >; - - public: - MemFn(Prototype prototype, const Instance& instance) - : m_func(prototype), m_instance(instance) - { - } + return [f, self](Arg... args) { + return (self->*f)(std::forward< Arg >(args)...); + }; + } - template < typename... Args > - result_type - operator()(Args&&... args) const - { - return (Deref::deref(m_instance.value()) - .*m_func)(std::forward< Args >(args)...); - } - }; + // Wraps a member function and shared pointer to an instance into a lambda + // that invokes the method. + template < + typename Return, typename Class, typename Derived, typename... Arg, + typename = + std::enable_if_t< std::is_base_of< Class, Derived >::value > > + auto + memFn(Return (Class::*f)(Arg...), std::shared_ptr< Derived > self) + { + return [f, self = std::move(self)](Arg... args) { + return (self.get()->*f)(std::forward< Arg >(args)...); + }; + } - template < typename Prototype, typename Instance > - MemFn< Prototype, Instance > - memFn(Prototype prototype, const Instance& instance) + // Wraps a member function and shared pointer to an instance into a lambda + // that invokes the method (const method overload). + template < + typename Return, typename Class, typename Derived, typename... Arg, + typename = + std::enable_if_t< std::is_base_of< Class, Derived >::value > > + auto + memFn(Return (Class::*f)(Arg...) const, std::shared_ptr< Derived > self) { - return MemFn< Prototype, Instance >(prototype, instance); + return [f, self = std::move(self)](Arg... args) { + return (self.get()->*f)(std::forward< Arg >(args)...); + }; } } // namespace util diff --git a/llarp/util/meta/memfn_traits.cpp b/llarp/util/meta/memfn_traits.cpp deleted file mode 100644 index da17eccde..000000000 --- a/llarp/util/meta/memfn_traits.cpp +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/llarp/util/meta/memfn_traits.hpp b/llarp/util/meta/memfn_traits.hpp deleted file mode 100644 index 8cdd96801..000000000 --- a/llarp/util/meta/memfn_traits.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef LLARP_UTIL_MEMFN_TRAITS -#define LLARP_UTIL_MEMFN_TRAITS - -#include -#include - -#include -#include - -namespace llarp -{ - namespace util - { - template < typename Prototype, typename TestPrototype > - struct MemFnTraitsImpl; - - template < typename Prototype > - struct MemFnTraits : public MemFnTraitsImpl< Prototype, Prototype > - { - }; - - template < typename Prototype, typename Return, typename Type, - typename... Args > - class MemFnTraitsClass - { - using NonCVTag = traits::Tag< 0 >; - using ConstTag = traits::Tag< 1 >; - using VolTag = traits::Tag< 2 >; - using ConstVolTag = traits::Tag< 3 >; - - // clang-format off - static constexpr NonCVTag test(Return (Type::*)(Args...)); - static constexpr ConstTag test(Return (Type::*)(Args...) const); - static constexpr VolTag test(Return (Type::*)(Args...) volatile); - static constexpr ConstVolTag test(Return (Type::*)(Args...) const volatile); - // clang-format on - public: - static constexpr bool IsConst = - ((sizeof((test)((Prototype)0)) - 1) & 1) != 0; - static constexpr bool IsVolatile = - ((sizeof((test)((Prototype)0)) - 1) & 2) != 0; - - using ctype = std::conditional_t< IsConst, const Type, Type >; - using type = std::conditional_t< IsVolatile, volatile ctype, ctype >; - }; - - template < typename Prototype, typename Return, typename Type, - typename... Args > - struct MemFnTraitsImpl< Prototype, Return (Type::*)(Args...) > - { - static constexpr bool IsMemFn = true; - - using class_type = - typename MemFnTraitsClass< Prototype, Return, Type, Args... >::type; - - using result_type = Return; - }; - - template < typename Prototype, typename Return, typename Type, - typename... Args > - struct MemFnTraitsImpl< Prototype, Return (Type::*)(Args...) const > - { - static constexpr bool IsMemFn = true; - - using class_type = - typename MemFnTraitsClass< Prototype, Return, Type, Args... >::type; - - using result_type = Return; - }; - - template < typename Prototype, typename Return, typename Type, - typename... Args > - struct MemFnTraitsImpl< Prototype, Return (Type::*)(Args...) volatile > - { - static constexpr bool IsMemFn = true; - - using class_type = - typename MemFnTraitsClass< Prototype, Return, Type, Args... >::type; - - using result_type = Return; - }; - - template < typename Prototype, typename Return, typename Type, - typename... Args > - struct MemFnTraitsImpl< Prototype, - Return (Type::*)(Args...) const volatile > - { - static constexpr bool IsMemFn = true; - - using class_type = - typename MemFnTraitsClass< Prototype, Return, Type, Args... >::type; - - using result_type = Return; - }; - - template < typename Prototype, typename TestPrototype > - struct MemFnTraitsImpl - { - static constexpr bool IsMemFn = false; - - using result_type = void; - using class_type = void; - }; - } // namespace util -} // namespace llarp - -#endif diff --git a/llarp/util/meta/object.cpp b/llarp/util/meta/object.cpp deleted file mode 100644 index 962108c18..000000000 --- a/llarp/util/meta/object.cpp +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/llarp/util/meta/object.hpp b/llarp/util/meta/object.hpp deleted file mode 100644 index 77d5d5ca1..000000000 --- a/llarp/util/meta/object.hpp +++ /dev/null @@ -1,466 +0,0 @@ -#ifndef LLARP_OBJECT_HPP -#define LLARP_OBJECT_HPP - -#include -#include - -#include -#include - -namespace llarp -{ - namespace object - { - /// Provide a buffer, capable of holding a single `Value` object. - /// This is useful for node-based data structures. - /// Note: - /// - This union explicitly does *not* manage the lifetime of the object, - /// explicit calls to the constructor/destructor must be made. - template < typename Value > - union Buffer { - private: - char m_buffer[sizeof(Value)]; - char m_align[alignof(Value)]; - - public: - Value* - address() - { - return reinterpret_cast< Value* >(static_cast< void* >(m_buffer)); - } - const Value* - address() const - { - return reinterpret_cast< Value* >(static_cast< void* >(m_buffer)); - } - - char* - buffer() - { - return m_buffer; - } - const char* - buffer() const - { - return m_buffer; - } - - Value& - value() - { - return *reinterpret_cast< Value* >(this); - } - const Value& - value() const - { - return *reinterpret_cast< const Value* >(this); - } - }; - - template < typename Value > - class Proxy - { - Buffer< Value > m_value; - - Proxy& - operator=(const Proxy&) = delete; - - public: - Proxy() - { - ::new(m_value.buffer()) Value(); - } - - Proxy(const Proxy& other) - { - ::new(m_value.buffer()) Value(other.value()); - } - - Proxy(const Value& value) - { - ::new(m_value.buffer()) Value(value); - } - - // template < typename... Args > - // Proxy(Args&&... args) - // { - // ::new(m_value.buffer()) Value(std::forward< Args >(args)...); - // } - - ~Proxy() - { - m_value.address()->~Value(); - } - - Value& - value() - { - return m_value.value(); - } - - const Value& - value() const - { - return m_value.value(); - } - }; - - template < typename Value > - class Catalog; - template < typename Value > - class CatalogIterator; - - template < typename Value > - class CatalogCleaner - { - Catalog< Value >* m_catalog; - typename Catalog< Value >::Node* m_node; - bool m_shouldDelete; - - CatalogCleaner(const CatalogCleaner&) = delete; - CatalogCleaner& - operator=(const CatalogCleaner&) = delete; - - public: - explicit CatalogCleaner(Catalog< Value >* catalog) - : m_catalog(catalog), m_node(nullptr), m_shouldDelete(false) - { - } - - ~CatalogCleaner(); - - void - manageNode(typename Catalog< Value >::Node* node, bool shouldDelete) - { - m_node = node; - m_shouldDelete = shouldDelete; - } - - void - releaseNode() - { - m_node = nullptr; - } - - void - release() - { - releaseNode(); - m_catalog = nullptr; - } - }; - - /// A pooling catalog of objects, referred to by a 32-bit handle - template < typename Value > - class Catalog - { - enum - { - INDEX_MASK = 0X007FFFFF, - BUSY_INDICATOR = 0x00800000, - GENERATION_INC = 0x01000000, - GENERATION_MASK = 0XFF000000 - }; - - struct Node - { - union Payload { - Buffer< Value > m_buffer; - Node* m_next; - }; - Payload m_payload; - int32_t m_handle; - }; - - std::vector< Node* > m_nodes GUARDED_BY(m_mutex); - Node* m_next; - std::atomic_size_t m_size; - - mutable util::Mutex m_mutex; - - friend class CatalogCleaner< Value >; - friend class CatalogIterator< Value >; - - static Value* - getValue(Node* node) - { - return node->m_payload.m_buffer.address(); - } - - void - freeNode(Node* node) - { - node->m_handle += GENERATION_INC; - node->m_handle &= ~BUSY_INDICATOR; - - node->m_payload.m_next = m_next; - m_next = node; - } - - Node* - findNode(int32_t handle) const REQUIRES_SHARED(m_mutex) - { - int32_t index = handle & INDEX_MASK; - - if(0 > index || index >= static_cast< int32_t >(m_nodes.size()) - || !(handle & BUSY_INDICATOR)) - { - return nullptr; - } - - Node* node = m_nodes[index]; - - return (node->m_handle == handle) ? node : nullptr; - } - - public: - Catalog() : m_next(nullptr), m_size(0) - { - } - - ~Catalog() - { - removeAll(); - } - - int32_t - add(const Value& value) - { - int32_t handle; - util::Lock l(m_mutex); - CatalogCleaner< Value > guard(this); - Node* node; - - if(m_next) - { - node = m_next; - m_next = node->m_payload.m_next; - - guard.manageNode(node, false); - } - else - { - assert(m_nodes.size() < BUSY_INDICATOR); - - node = new Node; - guard.manageNode(node, true); - - m_nodes.push_back(node); - node->m_handle = static_cast< int32_t >(m_nodes.size() - 1); - guard.manageNode(node, false); - } - - node->m_handle |= BUSY_INDICATOR; - handle = node->m_handle; - - // construct into the node. - ::new(getValue(node)) Value(value); - - guard.release(); - - ++m_size; - return handle; - } - - bool - remove(int32_t handle, Value* value = nullptr) - { - util::Lock l(m_mutex); - Node* node = findNode(handle); - - if(!node) - { - return false; - } - - Value* val = getValue(node); - - if(value) - { - *value = *val; - } - - val->~Value(); - freeNode(node); - - --m_size; - return true; - } - - void - removeAll(std::vector< Value >* output = nullptr) - { - util::Lock l(m_mutex); - - for(Node* node : m_nodes) - { - if(node->m_handle & BUSY_INDICATOR) - { - Value* value = getValue(node); - - if(output) - { - output->push_back(*value); - } - value->~Value(); - } - - delete node; - } - m_nodes.clear(); - m_next = nullptr; - m_size = 0; - } - - bool - replace(const Value& newValue, int32_t handle) - { - util::Lock l(m_mutex); - Node* node = findNode(handle); - - if(!node) - { - return false; - } - - Value* value = getValue(node); - - value->~Value(); - // construct into the node. - ::new(value) Value(newValue); - return true; - } - - nonstd::optional< Value > - find(int32_t handle) - { - auto l = util::shared_lock(m_mutex); - Node* node = findNode(handle); - - if(!node) - { - return {}; - } - - return *getValue(node); - } - - size_t - size() const - { - return m_size; - } - - /// introduced for testing only. verify the current state of the catalog. - bool - verify() const; - }; - - template < typename Value > - class SCOPED_CAPABILITY CatalogIterator - { - const Catalog< Value >* m_catalog; - size_t m_index; - - std::shared_lock lock; - - CatalogIterator(const CatalogIterator&) = delete; - CatalogIterator& - operator=(const CatalogIterator&) = delete; - - public: - explicit CatalogIterator(const Catalog< Value >* catalog) - ACQUIRE_SHARED(catalog->m_mutex) - : m_catalog(catalog), m_index(-1), lock(m_catalog->m_mutex) - { - operator++(); - } - - void - operator++() NO_THREAD_SAFETY_ANALYSIS - { - m_index++; - while(m_index < m_catalog->m_nodes.size() - && !(m_catalog->m_nodes[m_index]->m_handle - & Catalog< Value >::BUSY_INDICATOR)) - { - m_index++; - } - } - - explicit operator bool() const NO_THREAD_SAFETY_ANALYSIS - { - return m_index < m_catalog->m_nodes.size(); - } - - std::pair< int32_t, Value > - operator()() const NO_THREAD_SAFETY_ANALYSIS - { - auto* node = m_catalog->m_nodes[m_index]; - return {node->m_handle, *Catalog< Value >::getValue(node)}; - } - }; - - template < typename Value > - CatalogCleaner< Value >::~CatalogCleaner() - { - if(m_catalog && m_node) - { - if(m_shouldDelete) - { - // We call the destructor elsewhere. - operator delete(m_node); - } - else - { - m_catalog->freeNode(m_node); - } - } - } - - template < typename Value > - bool - Catalog< Value >::verify() const - { - util::Lock l(m_mutex); - - if(m_nodes.size() < m_size) - { - return false; - } - - size_t busyCount = 0; - for(size_t i = 0; i < m_nodes.size(); i++) - { - if((m_nodes[i]->m_handle & INDEX_MASK) != i) - { - return false; - } - if(m_nodes[i]->m_handle & BUSY_INDICATOR) - { - busyCount++; - } - } - - if(m_size != busyCount) - { - return false; - } - - size_t freeCount = 0; - for(Node* p = m_next; p != nullptr; p = p->m_payload.m_next) - { - freeCount++; - } - - if(freeCount + busyCount != m_nodes.size()) - { - return false; - } - - return true; - } - } // namespace object -} // namespace llarp - -#endif diff --git a/llarp/util/meta/traits.hpp b/llarp/util/meta/traits.hpp index 2e39311e0..af1e28ef6 100644 --- a/llarp/util/meta/traits.hpp +++ b/llarp/util/meta/traits.hpp @@ -1,8 +1,6 @@ #ifndef LLARP_TRAITS_HPP #define LLARP_TRAITS_HPP -#include - #include #include #include @@ -12,9 +10,18 @@ namespace llarp { namespace traits { - using absl::conjunction; - using absl::disjunction; - using absl::void_t; +#ifdef __cpp_lib_void_t + using std::void_t; +#else + /// C++17 void_t backport + template < typename... Ts > + struct void_t_impl + { + using type = void; + }; + template < typename... Ts > + using void_t = typename void_t_impl< Ts... >::type; +#endif /// Represents the empty type struct Bottom diff --git a/llarp/util/meta/variant.cpp b/llarp/util/meta/variant.cpp deleted file mode 100644 index 8a2a04643..000000000 --- a/llarp/util/meta/variant.cpp +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/llarp/util/meta/variant.hpp b/llarp/util/meta/variant.hpp deleted file mode 100644 index 1905ba8fc..000000000 --- a/llarp/util/meta/variant.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef LLARP_VARIANT_HPP -#define LLARP_VARIANT_HPP - -#include - -namespace llarp -{ - namespace util - { - template < typename... Ts > - struct _overloaded; - - template < typename T, typename... Ts > - struct _overloaded< T, Ts... > : T, _overloaded< Ts... > - { - _overloaded(T&& t, Ts&&... ts) - : T(t), _overloaded< Ts... >(std::forward< Ts >(ts)...) - { - } - using T::operator(); - - using _overloaded< Ts... >::operator(); - }; - - template < typename T > - struct _overloaded< T > : T - { - _overloaded(T&& t) : T(t) - { - } - - using T::operator(); - }; - - template < typename... Ts > - constexpr auto - overloaded(Ts&&... ts) -> _overloaded< Ts... > - { - return _overloaded< Ts... >(std::forward< Ts >(ts)...); - } - - } // namespace util -} // namespace llarp - -#endif diff --git a/llarp/util/printer.hpp b/llarp/util/printer.hpp index 8580bbddf..7ff8247e3 100644 --- a/llarp/util/printer.hpp +++ b/llarp/util/printer.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include diff --git a/llarp/util/status.hpp b/llarp/util/status.hpp index 6e70e9c2c..bb38ca836 100644 --- a/llarp/util/status.hpp +++ b/llarp/util/status.hpp @@ -8,7 +8,6 @@ #include #include #include -#include namespace llarp { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 85c6d8895..0c7a1bbc3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -32,7 +32,6 @@ list(APPEND TEST_SRC test_llarp_router_contact.cpp test_md5.cpp util/meta/test_llarp_util_memfn.cpp - util/meta/test_llarp_util_object.cpp util/meta/test_llarp_util_traits.cpp util/test_llarp_util_aligned.cpp util/test_llarp_util_bencode.cpp diff --git a/test/util/meta/test_llarp_util_memfn.cpp b/test/util/meta/test_llarp_util_memfn.cpp index 22ff0fe96..085776da5 100644 --- a/test/util/meta/test_llarp_util_memfn.cpp +++ b/test/util/meta/test_llarp_util_memfn.cpp @@ -40,8 +40,8 @@ TEST(MemFn, call) ASSERT_EQ(11, util::memFn(&Foo::arg, &foo)(10)); ASSERT_EQ(9, util::memFn(&Foo::constArg, &foo)(10)); - ASSERT_TRUE(util::memFn(&Foo::constEmpty, foo)()); - ASSERT_EQ(9, util::memFn(&Foo::constArg, foo)(10)); + ASSERT_TRUE(util::memFn(&Foo::constEmpty, &foo)()); + ASSERT_EQ(9, util::memFn(&Foo::constArg, &foo)(10)); } template < typename T > @@ -54,7 +54,6 @@ TYPED_TEST_SUITE_P(MemFnType); TYPED_TEST_P(MemFnType, Smoke) { TypeParam foo{}; - ASSERT_TRUE(util::memFn(&Foo::constEmpty, foo)()); ASSERT_TRUE(util::memFn(&Foo::constEmpty, &foo)()); } diff --git a/test/util/meta/test_llarp_util_object.cpp b/test/util/meta/test_llarp_util_object.cpp deleted file mode 100644 index 9de7febe8..000000000 --- a/test/util/meta/test_llarp_util_object.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include - -#include -#include - -#include -#include - -using namespace llarp::object; - -TEST(Object, VerifySize) -{ - static_assert(sizeof(Buffer< char >) == sizeof(char), ""); - static_assert(sizeof(Buffer< int >) == sizeof(int), ""); - static_assert(sizeof(Buffer< double >) == sizeof(double), ""); - static_assert(sizeof(Buffer< std::string >) == sizeof(std::string), ""); -} - -TEST(Object, Inplace) -{ - // Verify we can create and destroy a type with a non-trivial destructor - Buffer< std::vector< std::string > > strBuf; - new(strBuf.buffer()) std::vector< std::string >(100, "abc"); - strBuf.value().~vector(); -} - -TEST(Catalog, smoke) -{ - const double value1 = 1.0; - const double value2 = 2.0; - int32_t handle1 = -1; - int32_t handle2 = -1; - - Catalog< double > catalog; - - handle1 = catalog.add(value1); - catalog.remove(handle1); - - for(size_t j = 0; j < 5; ++j) - { - for(size_t i = 1; i < 256; ++i) - { - ASSERT_FALSE(catalog.find(handle1)); - - handle2 = catalog.add(value2); - catalog.remove(handle2); - } - handle2 = catalog.add(value2); - - ASSERT_EQ(handle1, handle2); - ASSERT_TRUE(catalog.find(handle1)); - - nonstd::optional< double > result = catalog.find(handle1); - ASSERT_TRUE(result); - ASSERT_EQ(value2, result); - catalog.remove(handle2); - } -} - -TEST(Catalog, Iterator) -{ - static constexpr size_t THREAD_COUNT = 10; - static constexpr size_t ITERATION_COUNT = 1000; - static constexpr int32_t MAX = std::numeric_limits< int32_t >::max(); - std::array< std::thread, THREAD_COUNT + 3 > threads; - - using llarp::util::Barrier; - using Iterator = CatalogIterator< int32_t >; - using Cat = Catalog< int32_t >; - - Barrier barrier(THREAD_COUNT + 3); - Cat catalog; - - // Repeatedly remove + add values from the catalog - for(size_t i = 0; i < THREAD_COUNT; ++i) - { - threads[i] = std::thread( - [](Barrier *b, Cat *cat, int32_t id) { - b->Block(); - for(size_t j = 0; j < ITERATION_COUNT; ++j) - { - int32_t handle = cat->add(id); - nonstd::optional< int32_t > res = cat->find(handle); - ASSERT_TRUE(res); - ASSERT_EQ(res.value(), id); - ASSERT_TRUE(cat->replace(MAX - id, handle)); - res = cat->find(handle); - ASSERT_TRUE(res); - ASSERT_EQ(MAX - id, res.value()); - int32_t removed = 0; - ASSERT_TRUE(cat->remove(handle, &removed)); - ASSERT_EQ(removed, MAX - id); - ASSERT_FALSE(cat->find(handle)); - } - }, - &barrier, &catalog, i); - } - - // Verify the length constraint is never violated - threads[THREAD_COUNT] = std::thread( - [](Barrier *b, Cat *cat) { - b->Block(); - for(size_t i = 0; i < ITERATION_COUNT; ++i) - { - size_t size = cat->size(); - ASSERT_LE(size, THREAD_COUNT); - } - }, - &barrier, &catalog); - - // Verify that iteration always produces a valid state - threads[THREAD_COUNT + 1] = std::thread( - [](Barrier *b, Cat *cat) { - b->Block(); - for(size_t i = 0; i < ITERATION_COUNT; ++i) - { - int32_t arr[100]; - size_t size = 0; - for(Iterator it(cat); it; ++it) - { - arr[size++] = it().second; - } - for(int32_t j = 0; j < 100; j++) - { - // value must be valid - bool present = false; - for(int32_t id = 0; id < static_cast< int32_t >(THREAD_COUNT); id++) - { - if(id == arr[j] || MAX - id == arr[j]) - { - present = true; - break; - } - } - - (void)present; - - // no duplicate should be there - for(size_t k = j + 1; k < size; k++) - { - ASSERT_NE(arr[j], arr[k]); - } - } - } - }, - &barrier, &catalog); - - // And that we don't have an invalid catalog - threads[THREAD_COUNT + 2] = std::thread( - [](Barrier *b, Cat *cat) { - b->Block(); - for(size_t i = 0; i < ITERATION_COUNT; ++i) - { - cat->verify(); - } - }, - &barrier, &catalog); - - for(std::thread &t : threads) - { - t.join(); - } -}