/* Fast open-addressing concurrent hash table. * * Copyright 2023 Christian Mazakas. * 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. */ /* Reference: * https://github.com/joaquintides/concurrent_hashmap_api#proposed-synopsis */ #ifndef BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP #define BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP #include #include #include #include #include #include #include namespace boost { namespace unordered { namespace detail { template struct concurrent_map_types { using key_type = Key; using raw_key_type = typename std::remove_const::type; using raw_mapped_type = typename std::remove_const::type; using init_type = std::pair; using moved_type = std::pair; using value_type = std::pair; using element_type = value_type; static value_type& value_from(element_type& x) { return x; } template static raw_key_type const& extract(std::pair const& kv) { return kv.first; } static moved_type move(init_type& x) { return {std::move(x.first), std::move(x.second)}; } static moved_type move(element_type& x) { // TODO: we probably need to launder here return {std::move(const_cast(x.first)), std::move(const_cast(x.second))}; } template static void construct(A& al, init_type* p, Args&&... args) { boost::allocator_construct(al, p, std::forward(args)...); } template static void construct(A& al, value_type* p, Args&&... args) { boost::allocator_construct(al, p, std::forward(args)...); } template static void destroy(A& al, init_type* p) noexcept { boost::allocator_destroy(al, p); } template static void destroy(A& al, value_type* p) noexcept { boost::allocator_destroy(al, p); } }; } // namespace detail template , class Pred = std::equal_to, class Allocator = std::allocator > > class concurrent_flat_map { private: using type_policy = detail::concurrent_map_types; detail::foa::concurrent_table table_; public: using key_type = Key; using mapped_type = T; 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_map() : concurrent_flat_map(0) {} explicit concurrent_flat_map(size_type n, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type()) : table_(n, hf, eql, a) { } /// Capacity /// size_type size() const noexcept { return table_.size(); } BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept { return size() == 0; } /// Modifiers /// bool insert(value_type const& obj) { return table_.insert(obj); } bool insert(value_type&& obj) { return table_.insert(std::move(obj)); } bool insert(init_type const& obj) { return table_.insert(obj); } bool insert(init_type&& obj) { return table_.insert(std::move(obj)); } template void insert(InputIterator begin, InputIterator end) { for (auto pos = begin; pos != end; ++pos) { table_.insert(*pos); } } void insert(std::initializer_list ilist) { this->insert(ilist.begin(), ilist.end()); } template std::size_t visit_all(F f) { return table_.visit_all(std::move(f)); } template bool insert_or_assign(key_type const& k, M&& obj) { return table_.try_emplace_or_visit( k, [&](value_type& m) { m.second = std::forward(obj); }, std::forward(obj)); } template bool insert_or_assign(key_type&& k, M&& obj) { return table_.try_emplace_or_visit( std::move(k), [&](value_type& m) { m.second = std::forward(obj); }, std::forward(obj)); } template typename std::enable_if< detail::are_transparent::value, bool>::type insert_or_assign(K&& k, M&& obj) { return table_.try_emplace_or_visit( std::forward(k), [&](value_type& m) { m.second = std::forward(obj); }, std::forward(obj)); } template bool insert_or_visit(value_type const& obj, F f) { return table_.insert_or_visit(obj, std::move(f)); } template bool insert_or_visit(value_type&& obj, F f) { return table_.insert_or_visit(std::move(obj), std::move(f)); } template bool insert_or_visit(init_type const& obj, F f) { return table_.insert_or_visit(obj, std::move(f)); } template bool insert_or_visit(init_type&& obj, F f) { return table_.insert_or_visit(std::move(obj), std::move(f)); } template void insert_or_visit(InputIterator first, InputIterator last, F f) { for (; first != last; ++first) { table_.insert_or_visit(*first, f); } } template void insert_or_visit(std::initializer_list ilist, F f) { this->insert_or_visit(ilist.begin(), ilist.end(), std::move(f)); } size_type erase(key_type const& k) { return table_.erase(k); } /// Hash Policy /// void rehash(size_type n) { table_.rehash(n); } void reserve(size_type n) { table_.reserve(n); } }; } // namespace unordered } // namespace boost #endif // BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP