// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. // Copyright (C) 2005-2016 Daniel James // Copyright (C) 2022-2024 Joaquin M Lopez Munoz. // Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2024 Braden Ganetsky // // 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) #ifndef BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP #define BOOST_UNORDERED_DETAIL_IMPLEMENTATION_HPP #include #if defined(BOOST_HAS_PRAGMA_ONCE) #pragma once #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // std::forward_as_tuple namespace boost { namespace tuples { struct null_type; } } // namespace boost // BOOST_UNORDERED_SUPPRESS_DEPRECATED // // Define to stop deprecation attributes #if defined(BOOST_UNORDERED_SUPPRESS_DEPRECATED) #define BOOST_UNORDERED_DEPRECATED(msg) #endif // BOOST_UNORDERED_DEPRECATED // // Wrapper around various depreaction attributes. #if defined(__has_cpp_attribute) && \ (!defined(__cplusplus) || __cplusplus >= 201402) #if __has_cpp_attribute(deprecated) && !defined(BOOST_UNORDERED_DEPRECATED) #define BOOST_UNORDERED_DEPRECATED(msg) [[deprecated(msg)]] #endif #endif #if !defined(BOOST_UNORDERED_DEPRECATED) #if defined(__GNUC__) && __GNUC__ >= 4 #define BOOST_UNORDERED_DEPRECATED(msg) __attribute__((deprecated)) #elif defined(_MSC_VER) && _MSC_VER >= 1400 #define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated(msg)) #elif defined(_MSC_VER) && _MSC_VER >= 1310 #define BOOST_UNORDERED_DEPRECATED(msg) __declspec(deprecated) #else #define BOOST_UNORDERED_DEPRECATED(msg) #endif #endif namespace boost { namespace unordered { using std::piecewise_construct; using std::piecewise_construct_t; namespace detail { template struct table; static const float minimum_max_load_factor = 1e-3f; static const std::size_t default_bucket_count = 0; struct move_tag { }; struct empty_emplace { }; struct no_key { no_key() {} template no_key(T const&) {} }; struct converting_key { }; namespace func { template inline void ignore_unused_variable_warning(T const&) { } } // namespace func ////////////////////////////////////////////////////////////////////////// // iterator SFINAE template struct is_forward : std::is_base_of::iterator_category> { }; template struct enable_if_forward : std::enable_if::value, ReturnType> { }; template struct disable_if_forward : std::enable_if::value, ReturnType> { }; } // namespace detail } // namespace unordered } // namespace boost namespace boost { namespace unordered { namespace detail { ////////////////////////////////////////////////////////////////////////// // insert_size/initial_size template inline typename boost::unordered::detail::enable_if_forward::type insert_size(I i, I j) { return static_cast(std::distance(i, j)); } template inline typename boost::unordered::detail::disable_if_forward::type insert_size(I, I) { return 1; } template inline std::size_t initial_size(I i, I j, std::size_t num_buckets = boost::unordered::detail::default_bucket_count) { return (std::max)( boost::unordered::detail::insert_size(i, j), num_buckets); } ////////////////////////////////////////////////////////////////////////// // compressed template struct compressed_base : boost::empty_value { compressed_base(T const& x) : empty_value(boost::empty_init_t(), x) { } compressed_base(T& x, move_tag) : empty_value(boost::empty_init_t(), std::move(x)) { } T& get() { return empty_value::get(); } T const& get() const { return empty_value::get(); } }; template struct generate_base : boost::unordered::detail::compressed_base { typedef compressed_base type; generate_base() : type() {} }; template struct compressed : private boost::unordered::detail::generate_base::type, private boost::unordered::detail::generate_base::type { typedef typename generate_base::type base1; typedef typename generate_base::type base2; typedef T1 first_type; typedef T2 second_type; first_type& first() { return static_cast(this)->get(); } first_type const& first() const { return static_cast(this)->get(); } second_type& second() { return static_cast(this)->get(); } second_type const& second() const { return static_cast(this)->get(); } template compressed(First const& x1, Second const& x2) : base1(x1), base2(x2) { } compressed(compressed const& x) : base1(x.first()), base2(x.second()) {} compressed(compressed& x, move_tag m) : base1(x.first(), m), base2(x.second(), m) { } void assign(compressed const& x) { first() = x.first(); second() = x.second(); } void move_assign(compressed& x) { first() = std::move(x.first()); second() = std::move(x.second()); } void swap(compressed& x) { boost::core::invoke_swap(first(), x.first()); boost::core::invoke_swap(second(), x.second()); } private: // Prevent assignment just to make use of assign or // move_assign explicit. compressed& operator=(compressed const&); }; ////////////////////////////////////////////////////////////////////////// // pair_traits // // Used to get the types from a pair without instantiating it. template struct pair_traits { typedef typename Pair::first_type first_type; typedef typename Pair::second_type second_type; }; template struct pair_traits > { typedef T1 first_type; typedef T2 second_type; }; #if defined(BOOST_MSVC) #pragma warning(push) #pragma warning(disable : 4512) // assignment operator could not be generated. #pragma warning(disable : 4345) // behavior change: an object of POD type // constructed with an initializer of the form () // will be default-initialized. #endif ////////////////////////////////////////////////////////////////////////// // Bits and pieces for implementing traits template typename std::add_lvalue_reference::type make(); struct choice2 { typedef char (&type)[2]; }; struct choice1 : choice2 { typedef char (&type)[1]; }; choice1 choose(); typedef choice1::type yes_type; typedef choice2::type no_type; struct private_type { private_type const& operator,(int) const; }; template no_type is_private_type(T const&); yes_type is_private_type(private_type const&); struct convert_from_anything { template convert_from_anything(T const&); }; } // namespace detail } // namespace unordered } // namespace boost //////////////////////////////////////////////////////////////////////////////// // // Some utilities for implementing allocator_traits, but useful elsewhere so // they're always defined. namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// // Explicitly call a destructor #if defined(BOOST_MSVC) #pragma warning(push) #pragma warning(disable : 4100) // unreferenced formal parameter #endif namespace func { template inline void destroy(T* x) { x->~T(); } } // namespace func #if defined(BOOST_MSVC) #pragma warning(pop) #endif ////////////////////////////////////////////////////////////////////////// // value_base // // Space used to store values. template struct value_base { typedef ValueType value_type; opt_storage data_; value_base() : data_() {} void* address() { return this; } value_type& value() { return *(ValueType*)this; } value_type const& value() const { return *(ValueType const*)this; } value_type* value_ptr() { return (ValueType*)this; } value_type const* value_ptr() const { return (ValueType const*)this; } private: value_base& operator=(value_base const&); }; ////////////////////////////////////////////////////////////////////////// // optional // TODO: Use std::optional when available. template class optional { boost::unordered::detail::value_base value_; bool has_value_; void destroy() { if (has_value_) { boost::unordered::detail::func::destroy(value_.value_ptr()); has_value_ = false; } } void move(optional& x) { BOOST_ASSERT(!has_value_ && x.has_value_); new (value_.value_ptr()) T(std::move(x.value_.value())); boost::unordered::detail::func::destroy(x.value_.value_ptr()); has_value_ = true; x.has_value_ = false; } public: optional() noexcept : has_value_(false) {} optional(optional const&) = delete; optional& operator=(optional const&) = delete; optional(optional&& x) : has_value_(false) { if (x.has_value_) { move(x); } } explicit optional(T const& x) : has_value_(true) { new (value_.value_ptr()) T(x); } optional& operator=(optional&& x) { destroy(); if (x.has_value_) { move(x); } return *this; } ~optional() { destroy(); } bool has_value() const { return has_value_; } T& operator*() { return value_.value(); } T const& operator*() const { return value_.value(); } T* operator->() { return value_.value_ptr(); } T const* operator->() const { return value_.value_ptr(); } bool operator==(optional const& x) const { return has_value_ ? x.has_value_ && value_.value() == x.value_.value() : !x.has_value_; } bool operator!=(optional const& x) const { return !((*this) == x); } void swap(optional& x) { if (has_value_ != x.has_value_) { if (has_value_) { x.move(*this); } else { move(x); } } else if (has_value_) { boost::core::invoke_swap(value_.value(), x.value_.value()); } } friend void swap(optional& x, optional& y) { x.swap(y); } }; } // namespace detail } // namespace unordered } // namespace boost //////////////////////////////////////////////////////////////////////////////// // // Allocator traits // namespace boost { namespace unordered { namespace detail { template struct allocator_traits : boost::allocator_traits { }; template struct rebind_wrap : boost::allocator_rebind { }; } // namespace detail } // namespace unordered } // namespace boost namespace boost { namespace unordered { namespace detail { namespace func { //////////////////////////////////////////////////////////////////////// // Trait to check for piecewise construction. template struct use_piecewise { static choice1::type test(choice1, std::piecewise_construct_t); static choice2::type test(choice2, ...); enum { value = sizeof(choice1::type) == sizeof(test(choose(), boost::unordered::detail::make())) }; }; //////////////////////////////////////////////////////////////////////// // Construct from variadic parameters template inline void construct_from_args( Alloc& alloc, T* address, Args&&... args) { boost::allocator_construct( alloc, address, std::forward(args)...); } // For backwards compatibility, implement a special case for // piecewise_construct with boost::tuple template struct detect_std_tuple { template static choice1::type test(choice1, std::tuple const&); static choice2::type test(choice2, ...); enum { value = sizeof(choice1::type) == sizeof(test(choose(), boost::unordered::detail::make())) }; }; // Special case for piecewise_construct template