From 0673c5653cd7b5f669631daa51823b694896a12b Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 10 Sep 2023 18:34:12 +0200 Subject: [PATCH] added boost::concurrent_flat_set --- .../boost/unordered/concurrent_flat_map.hpp | 67 +- .../unordered/concurrent_flat_map_fwd.hpp | 2 +- .../boost/unordered/concurrent_flat_set.hpp | 697 ++++++++++++++++++ .../unordered/concurrent_flat_set_fwd.hpp | 55 ++ .../detail/concurrent_static_asserts.hpp | 75 ++ .../boost/unordered/unordered_flat_set.hpp | 10 + 6 files changed, 842 insertions(+), 64 deletions(-) create mode 100644 include/boost/unordered/concurrent_flat_set.hpp create mode 100644 include/boost/unordered/concurrent_flat_set_fwd.hpp create mode 100644 include/boost/unordered/detail/concurrent_static_asserts.hpp diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index c95a3015..a06ec31f 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -1,4 +1,4 @@ -/* Fast open-addressing concurrent hash table. +/* Fast open-addressing concurrent hashmap. * * Copyright 2023 Christian Mazakas. * Distributed under the Boost Software License, Version 1.0. @@ -12,6 +12,7 @@ #define BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP #include +#include #include #include #include @@ -20,65 +21,12 @@ #include #include #include -#include -#include #include -#include #include -#include - -#define BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) \ - static_assert(boost::unordered::detail::is_invocable::value, \ - "The provided Callable must be invocable with value_type&"); - -#define BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) \ - static_assert( \ - boost::unordered::detail::is_invocable::value, \ - "The provided Callable must be invocable with value_type const&"); - -#if BOOST_CXX_VERSION >= 202002L - -#define BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(P) \ - static_assert(!std::is_base_of::value, \ - "ExecPolicy must be sequenced."); \ - static_assert( \ - !std::is_base_of::value, \ - "ExecPolicy must be sequenced."); - -#else - -#define BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(P) \ - static_assert(!std::is_base_of::value, \ - "ExecPolicy must be sequenced."); -#endif - -#define BOOST_UNORDERED_COMMA , - -#define BOOST_UNORDERED_LAST_ARG(Arg, Args) \ - mp11::mp_back > - -#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args) \ - BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(BOOST_UNORDERED_LAST_ARG(Arg, Args)) - -#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args) \ - BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE( \ - BOOST_UNORDERED_LAST_ARG(Arg, Args)) namespace boost { namespace unordered { - namespace detail { - template - struct is_invocable - : std::is_constructible, - std::reference_wrapper::type> > - { - }; - - } // namespace detail - template class concurrent_flat_map { @@ -479,6 +427,7 @@ namespace boost { BOOST_FORCEINLINE auto insert_or_visit(Ty&& value, F f) -> decltype(table_.insert_or_visit(std::forward(value), f)) { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) return table_.insert_or_visit(std::forward(value), f); } @@ -533,7 +482,7 @@ namespace boost { void insert_or_cvisit(std::initializer_list ilist, F f) { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) - this->insert_or_visit(ilist.begin(), ilist.end(), f); + this->insert_or_cvisit(ilist.begin(), ilist.end(), f); } template BOOST_FORCEINLINE bool emplace(Args&&... args) @@ -882,12 +831,4 @@ namespace boost { using unordered::concurrent_flat_map; } // namespace boost -#undef BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE -#undef BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE -#undef BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY -#undef BOOST_UNORDERED_COMMA -#undef BOOST_UNORDERED_LAST_ARG -#undef BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE -#undef BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE - #endif // BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP diff --git a/include/boost/unordered/concurrent_flat_map_fwd.hpp b/include/boost/unordered/concurrent_flat_map_fwd.hpp index 3a39c7a7..8a1dca3b 100644 --- a/include/boost/unordered/concurrent_flat_map_fwd.hpp +++ b/include/boost/unordered/concurrent_flat_map_fwd.hpp @@ -1,4 +1,4 @@ -/* Fast open-addressing concurrent hash table. +/* Fast open-addressing concurrent hashmap. * * Copyright 2023 Christian Mazakas. * Distributed under the Boost Software License, Version 1.0. diff --git a/include/boost/unordered/concurrent_flat_set.hpp b/include/boost/unordered/concurrent_flat_set.hpp new file mode 100644 index 00000000..96ddd98b --- /dev/null +++ b/include/boost/unordered/concurrent_flat_set.hpp @@ -0,0 +1,697 @@ +/* Fast open-addressing concurrent hashset. + * + * Copyright 2023 Christian Mazakas. + * Copyright 2023 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See https://www.boost.org/libs/unordered for library home page. + */ + +#ifndef BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP +#define BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace boost { + namespace unordered { + template + class concurrent_flat_set + { + private: + template + friend class concurrent_flat_set; + template + friend class unordered_flat_set; + + using type_policy = detail::foa::flat_set_types; + + detail::foa::concurrent_table table_; + + template + bool friend operator==(concurrent_flat_set const& lhs, + concurrent_flat_set const& rhs); + + template + friend typename concurrent_flat_set::size_type erase_if( + concurrent_flat_set& set, Predicate pred); + + template + friend void serialize( + Archive& ar, concurrent_flat_set& c, + unsigned int version); + + public: + using key_type = Key; + using value_type = typename type_policy::value_type; + using init_type = typename type_policy::init_type; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using hasher = typename boost::type_identity::type; + using key_equal = typename boost::type_identity::type; + using allocator_type = typename boost::type_identity::type; + using reference = value_type&; + using const_reference = value_type const&; + using pointer = typename boost::allocator_pointer::type; + using const_pointer = + typename boost::allocator_const_pointer::type; + + concurrent_flat_set() + : concurrent_flat_set(detail::foa::default_bucket_count) + { + } + + explicit concurrent_flat_set(size_type n, const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : table_(n, hf, eql, a) + { + } + + template + concurrent_flat_set(InputIterator f, InputIterator l, + size_type n = detail::foa::default_bucket_count, + const hasher& hf = hasher(), const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : table_(n, hf, eql, a) + { + this->insert(f, l); + } + + concurrent_flat_set(concurrent_flat_set const& rhs) + : table_(rhs.table_, + boost::allocator_select_on_container_copy_construction( + rhs.get_allocator())) + { + } + + concurrent_flat_set(concurrent_flat_set&& rhs) + : table_(std::move(rhs.table_)) + { + } + + template + concurrent_flat_set( + InputIterator f, InputIterator l, allocator_type const& a) + : concurrent_flat_set(f, l, 0, hasher(), key_equal(), a) + { + } + + explicit concurrent_flat_set(allocator_type const& a) + : table_(detail::foa::default_bucket_count, hasher(), key_equal(), a) + { + } + + concurrent_flat_set( + concurrent_flat_set const& rhs, allocator_type const& a) + : table_(rhs.table_, a) + { + } + + concurrent_flat_set(concurrent_flat_set&& rhs, allocator_type const& a) + : table_(std::move(rhs.table_), a) + { + } + + concurrent_flat_set(std::initializer_list il, + size_type n = detail::foa::default_bucket_count, + const hasher& hf = hasher(), const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()) + : concurrent_flat_set(n, hf, eql, a) + { + this->insert(il.begin(), il.end()); + } + + concurrent_flat_set(size_type n, const allocator_type& a) + : concurrent_flat_set(n, hasher(), key_equal(), a) + { + } + + concurrent_flat_set( + size_type n, const hasher& hf, const allocator_type& a) + : concurrent_flat_set(n, hf, key_equal(), a) + { + } + + template + concurrent_flat_set( + InputIterator f, InputIterator l, size_type n, const allocator_type& a) + : concurrent_flat_set(f, l, n, hasher(), key_equal(), a) + { + } + + template + concurrent_flat_set(InputIterator f, InputIterator l, size_type n, + const hasher& hf, const allocator_type& a) + : concurrent_flat_set(f, l, n, hf, key_equal(), a) + { + } + + concurrent_flat_set( + std::initializer_list il, const allocator_type& a) + : concurrent_flat_set( + il, detail::foa::default_bucket_count, hasher(), key_equal(), a) + { + } + + concurrent_flat_set(std::initializer_list il, size_type n, + const allocator_type& a) + : concurrent_flat_set(il, n, hasher(), key_equal(), a) + { + } + + concurrent_flat_set(std::initializer_list il, size_type n, + const hasher& hf, const allocator_type& a) + : concurrent_flat_set(il, n, hf, key_equal(), a) + { + } + + + concurrent_flat_set( + unordered_flat_set&& other) + : table_(std::move(other.table_)) + { + } + + ~concurrent_flat_set() = default; + + concurrent_flat_set& operator=(concurrent_flat_set const& rhs) + { + table_ = rhs.table_; + return *this; + } + + concurrent_flat_set& operator=(concurrent_flat_set&& rhs) + noexcept(boost::allocator_is_always_equal::type::value || + boost::allocator_propagate_on_container_move_assignment< + Allocator>::type::value) + { + table_ = std::move(rhs.table_); + return *this; + } + + concurrent_flat_set& operator=(std::initializer_list ilist) + { + table_ = ilist; + return *this; + } + + /// Capacity + /// + + size_type size() const noexcept { return table_.size(); } + size_type max_size() const noexcept { return table_.max_size(); } + + BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept + { + return size() == 0; + } + + template + BOOST_FORCEINLINE size_type visit(key_type const& k, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit(k, f); + } + + template + BOOST_FORCEINLINE size_type cvisit(key_type const& k, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit(k, f); + } + + template + BOOST_FORCEINLINE typename std::enable_if< + detail::are_transparent::value, size_type>::type + visit(K&& k, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit(std::forward(k), f); + } + + template + BOOST_FORCEINLINE typename std::enable_if< + detail::are_transparent::value, size_type>::type + cvisit(K&& k, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit(std::forward(k), f); + } + + template size_type visit_all(F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit_all(f); + } + + template size_type cvisit_all(F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.cvisit_all(f); + } + +#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS) + template + typename std::enable_if::value, + void>::type + visit_all(ExecPolicy&& p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + table_.visit_all(p, f); + } + + template + typename std::enable_if::value, + void>::type + cvisit_all(ExecPolicy&& p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + table_.cvisit_all(p, f); + } +#endif + + template bool visit_while(F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit_while(f); + } + + template bool cvisit_while(F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.cvisit_while(f); + } + +#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS) + template + typename std::enable_if::value, + bool>::type + visit_while(ExecPolicy&& p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + return table_.visit_while(p, f); + } + + template + typename std::enable_if::value, + bool>::type + cvisit_while(ExecPolicy&& p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + return table_.cvisit_while(p, f); + } +#endif + + /// Modifiers + /// + + BOOST_FORCEINLINE bool insert(value_type const& obj) + { + return table_.insert(obj); + } + + BOOST_FORCEINLINE bool insert(value_type&& obj) + { + return table_.insert(std::move(obj)); + } + + template + BOOST_FORCEINLINE typename std::enable_if< + detail::are_transparent::value, + bool >::type + insert(K&& k) + { + return table_.try_emplace(std::forward(k)); + } + + template + void insert(InputIterator begin, InputIterator end) + { + for (auto pos = begin; pos != end; ++pos) { + table_.emplace(*pos); + } + } + + void insert(std::initializer_list ilist) + { + this->insert(ilist.begin(), ilist.end()); + } + + template + BOOST_FORCEINLINE bool insert_or_visit(value_type const& obj, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.insert_or_cvisit(obj, f); + } + + template + BOOST_FORCEINLINE bool insert_or_visit(value_type&& obj, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.insert_or_cvisit(std::move(obj), f); + } + + template + BOOST_FORCEINLINE typename std::enable_if< + detail::are_transparent::value, + bool >::type + insert_or_visit(K&& k, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.try_emplace_or_cvisit(std::forward(k), f); + } + + template + void insert_or_visit(InputIterator first, InputIterator last, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + for (; first != last; ++first) { + table_.emplace_or_cvisit(*first, f); + } + } + + template + void insert_or_visit(std::initializer_list ilist, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + this->insert_or_cvisit(ilist.begin(), ilist.end(), f); + } + + template + BOOST_FORCEINLINE bool insert_or_cvisit(value_type const& obj, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.insert_or_cvisit(obj, f); + } + + template + BOOST_FORCEINLINE bool insert_or_cvisit(value_type&& obj, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.insert_or_cvisit(std::move(obj), f); + } + + template + BOOST_FORCEINLINE typename std::enable_if< + detail::are_transparent::value, + bool >::type + insert_or_cvisit(K&& k, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.try_emplace_or_cvisit(std::forward(k), f); + } + + template + void insert_or_cvisit(InputIterator first, InputIterator last, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + for (; first != last; ++first) { + table_.emplace_or_cvisit(*first, f); + } + } + + template + void insert_or_cvisit(std::initializer_list ilist, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + this->insert_or_cvisit(ilist.begin(), ilist.end(), f); + } + + template BOOST_FORCEINLINE bool emplace(Args&&... args) + { + return table_.emplace(std::forward(args)...); + } + + template + BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args) + { + BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...) + return table_.emplace_or_cvisit( + std::forward(arg), std::forward(args)...); + } + + template + BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args) + { + BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...) + return table_.emplace_or_cvisit( + std::forward(arg), std::forward(args)...); + } + + BOOST_FORCEINLINE size_type erase(key_type const& k) + { + return table_.erase(k); + } + + template + BOOST_FORCEINLINE typename std::enable_if< + detail::are_transparent::value, size_type>::type + erase(K&& k) + { + return table_.erase(std::forward(k)); + } + + template + BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f) + { + return table_.erase_if(k, f); + } + + template + BOOST_FORCEINLINE typename std::enable_if< + detail::are_transparent::value && + !detail::is_execution_policy::value, + size_type>::type + erase_if(K&& k, F f) + { + return table_.erase_if(std::forward(k), f); + } + +#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS) + template + typename std::enable_if::value, + void>::type + erase_if(ExecPolicy&& p, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + table_.erase_if(p, f); + } +#endif + + template size_type erase_if(F f) { return table_.erase_if(f); } + + void swap(concurrent_flat_set& other) noexcept( + boost::allocator_is_always_equal::type::value || + boost::allocator_propagate_on_container_swap::type::value) + { + return table_.swap(other.table_); + } + + void clear() noexcept { table_.clear(); } + + template + size_type merge(concurrent_flat_set& x) + { + BOOST_ASSERT(get_allocator() == x.get_allocator()); + return table_.merge(x.table_); + } + + template + size_type merge(concurrent_flat_set&& x) + { + return merge(x); + } + + BOOST_FORCEINLINE size_type count(key_type const& k) const + { + return table_.count(k); + } + + template + BOOST_FORCEINLINE typename std::enable_if< + detail::are_transparent::value, size_type>::type + count(K const& k) + { + return table_.count(k); + } + + BOOST_FORCEINLINE bool contains(key_type const& k) const + { + return table_.contains(k); + } + + template + BOOST_FORCEINLINE typename std::enable_if< + detail::are_transparent::value, bool>::type + contains(K const& k) const + { + return table_.contains(k); + } + + /// Hash Policy + /// + size_type bucket_count() const noexcept { return table_.capacity(); } + + float load_factor() const noexcept { return table_.load_factor(); } + float max_load_factor() const noexcept + { + return table_.max_load_factor(); + } + void max_load_factor(float) {} + size_type max_load() const noexcept { return table_.max_load(); } + + void rehash(size_type n) { table_.rehash(n); } + void reserve(size_type n) { table_.reserve(n); } + + /// Observers + /// + allocator_type get_allocator() const noexcept + { + return table_.get_allocator(); + } + + hasher hash_function() const { return table_.hash_function(); } + key_equal key_eq() const { return table_.key_eq(); } + }; + + template + bool operator==( + concurrent_flat_set const& lhs, + concurrent_flat_set const& rhs) + { + return lhs.table_ == rhs.table_; + } + + template + bool operator!=( + concurrent_flat_set const& lhs, + concurrent_flat_set const& rhs) + { + return !(lhs == rhs); + } + + template + void swap(concurrent_flat_set& x, + concurrent_flat_set& y) + noexcept(noexcept(x.swap(y))) + { + x.swap(y); + } + + template + typename concurrent_flat_set::size_type erase_if( + concurrent_flat_set& c, Predicate pred) + { + return c.table_.erase_if(pred); + } + + template + void serialize( + Archive& ar, concurrent_flat_set& c, unsigned int) + { + ar & core::make_nvp("table",c.table_); + } + +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + + template ::value_type>, + class Pred = + std::equal_to::value_type>, + class Allocator = std::allocator< + typename std::iterator_traits::value_type>, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + concurrent_flat_set(InputIterator, InputIterator, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_flat_set< + typename std::iterator_traits::value_type, Hash, Pred, + Allocator>; + + template , + class Pred = std::equal_to, class Allocator = std::allocator, + class = boost::enable_if_t >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + concurrent_flat_set(std::initializer_list, + std::size_t = boost::unordered::detail::foa::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_flat_set< T, Hash, Pred, Allocator>; + + template >, + class = boost::enable_if_t > > + concurrent_flat_set(InputIterator, InputIterator, std::size_t, Allocator) + -> concurrent_flat_set< + typename std::iterator_traits::value_type, + boost::hash::value_type>, + std::equal_to::value_type>, + Allocator>; + + template >, + class = boost::enable_if_t > > + concurrent_flat_set(InputIterator, InputIterator, Allocator) + -> concurrent_flat_set< + typename std::iterator_traits::value_type, + boost::hash::value_type>, + std::equal_to::value_type>, + Allocator>; + + template >, + class = boost::enable_if_t >, + class = boost::enable_if_t > > + concurrent_flat_set( + InputIterator, InputIterator, std::size_t, Hash, Allocator) + -> concurrent_flat_set< + typename std::iterator_traits::value_type, Hash, + std::equal_to::value_type>, + Allocator>; + + template > > + concurrent_flat_set(std::initializer_list, std::size_t, Allocator) + -> concurrent_flat_set,std::equal_to, Allocator>; + + template > > + concurrent_flat_set(std::initializer_list, Allocator) + -> concurrent_flat_set, std::equal_to, Allocator>; + + template >, + class = boost::enable_if_t > > + concurrent_flat_set(std::initializer_list, std::size_t,Hash, Allocator) + -> concurrent_flat_set, Allocator>; + +#endif + + } // namespace unordered + + using unordered::concurrent_flat_set; +} // namespace boost + +#endif // BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP diff --git a/include/boost/unordered/concurrent_flat_set_fwd.hpp b/include/boost/unordered/concurrent_flat_set_fwd.hpp new file mode 100644 index 00000000..d225a60b --- /dev/null +++ b/include/boost/unordered/concurrent_flat_set_fwd.hpp @@ -0,0 +1,55 @@ +/* Fast open-addressing concurrent hashset. + * + * Copyright 2023 Christian Mazakas. + * Copyright 2023 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See https://www.boost.org/libs/unordered for library home page. + */ + +#ifndef BOOST_UNORDERED_CONCURRENT_FLAT_SET_FWD_HPP +#define BOOST_UNORDERED_CONCURRENT_FLAT_SET_FWD_HPP + +#include + +#include +#include + +namespace boost { + namespace unordered { + + template , + class Pred = std::equal_to, + class Allocator = std::allocator > + class concurrent_flat_set; + + template + bool operator==( + concurrent_flat_set const& lhs, + concurrent_flat_set const& rhs); + + template + bool operator!=( + concurrent_flat_set const& lhs, + concurrent_flat_set const& rhs); + + template + void swap(concurrent_flat_set& x, + concurrent_flat_set& y) + noexcept(noexcept(x.swap(y))); + + template + typename concurrent_flat_set::size_type erase_if( + concurrent_flat_set& c, Predicate pred); + + } // namespace unordered + + using boost::unordered::concurrent_flat_set; + using boost::unordered::swap; + using boost::unordered::operator==; + using boost::unordered::operator!=; +} // namespace boost + +#endif // BOOST_UNORDERED_CONCURRENT_FLAT_SET_FWD_HPP diff --git a/include/boost/unordered/detail/concurrent_static_asserts.hpp b/include/boost/unordered/detail/concurrent_static_asserts.hpp new file mode 100644 index 00000000..93717534 --- /dev/null +++ b/include/boost/unordered/detail/concurrent_static_asserts.hpp @@ -0,0 +1,75 @@ +/* Copyright 2023 Christian Mazakas. + * Copyright 2023 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See https://www.boost.org/libs/unordered for library home page. + */ + +#ifndef BOOST_UNORDERED_DETAIL_CONCURRENT_STATIC_ASSERTS_HPP +#define BOOST_UNORDERED_DETAIL_CONCURRENT_STATIC_ASSERTS_HPP + +#include +#include + +#include +#include + +#define BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) \ + static_assert(boost::unordered::detail::is_invocable::value, \ + "The provided Callable must be invocable with value_type&"); + +#define BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) \ + static_assert( \ + boost::unordered::detail::is_invocable::value, \ + "The provided Callable must be invocable with value_type const&"); + +#if BOOST_CXX_VERSION >= 202002L + +#define BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(P) \ + static_assert(!std::is_base_of::value, \ + "ExecPolicy must be sequenced."); \ + static_assert( \ + !std::is_base_of::value, \ + "ExecPolicy must be sequenced."); + +#else + +#define BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(P) \ + static_assert(!std::is_base_of::value, \ + "ExecPolicy must be sequenced."); +#endif + +#define BOOST_UNORDERED_DETAIL_COMMA , + +#define BOOST_UNORDERED_DETAIL_LAST_ARG(Arg, Args) \ + mp11::mp_back > + +#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args) \ + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE( \ + BOOST_UNORDERED_DETAIL_LAST_ARG(Arg, Args)) + +#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args) \ + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE( \ + BOOST_UNORDERED_DETAIL_LAST_ARG(Arg, Args)) + +namespace boost { + namespace unordered { + namespace detail { + template + struct is_invocable + : std::is_constructible, + std::reference_wrapper::type> > + { + }; + + } // namespace detail + + } // namespace unordered + +} // namespace boost + +#endif // BOOST_UNORDERED_DETAIL_CONCURRENT_STATIC_ASSERTS_HPP diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 2676cafc..70286cbb 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -10,6 +10,7 @@ #pragma once #endif +#include #include #include #include @@ -35,6 +36,9 @@ namespace boost { template class unordered_flat_set { + template + friend class concurrent_flat_set; + using set_types = detail::foa::flat_set_types; using table_type = detail::foa::table&& other) + : table_(std::move(other.table_)) + { + } + ~unordered_flat_set() = default; unordered_flat_set& operator=(unordered_flat_set const& other)