forked from boostorg/unordered
Refactor internal implementation to use "fast closed-addressing" aka fca
This commit is contained in:
1 parent
ad639ffb61
commit
5a456eb295
9 files changed
+2251
-2153
No files matched your search
@@ -0,0 +1,1000 @@
|
||||
// Copyright (C) 2022 Joaquin M Lopez Munoz.
|
||||
// Copyright (C) 2022 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FCA_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FCA_HPP
|
||||
|
||||
/*
|
||||
|
||||
The general structure of the fast closed addressing implementation is that we
|
||||
use straight-forward separate chaining (i.e. each bucket contains its own linked
|
||||
list) and then improve iteration time by adding an array of "bucket groups".
|
||||
|
||||
A bucket group is a constant-width view into a subsection of the buckets array,
|
||||
containing a bitmask that indicates which one of the buckets in the subsection
|
||||
contains a list of nodes. This allows the code to test N buckets for occupancy
|
||||
in a single operation. Additional speed can be found by inter-linking occupied
|
||||
bucket groups with one another in a doubly-linked list. To this end, large
|
||||
swathes of the bucket groups array no longer need to be iterated and have their
|
||||
bitmasks examined for occupancy.
|
||||
|
||||
A bucket group iterator contains a pointer to a bucket group along with a
|
||||
pointer into the buckets array. The iterator's bucket pointer is guaranteed to
|
||||
point to a bucket within the bucket group's view of the array. To advance the
|
||||
iterator, we need to determine if we need to skip to the next bucket group or
|
||||
simply move to the next occupied bucket as denoted by the bitmask.
|
||||
|
||||
To accomplish this, we perform something roughly equivalent to this:
|
||||
```
|
||||
bucket_iterator itb = ...
|
||||
bucket_pointer p = itb.p
|
||||
bucket_group_pointer pbg = itb.pbg
|
||||
|
||||
offset = p - pbg->buckets
|
||||
// because we wish to see if the _next_ bit in the mask is occupied, we'll
|
||||
// generate a testing mask from the current offset + 1
|
||||
//
|
||||
testing_mask = reset_first_bits(offset + 1)
|
||||
n = ctz(pbg->bitmask & testing_mask)
|
||||
|
||||
if (n < N) {
|
||||
p = pbg->buckets + n
|
||||
} else {
|
||||
pbg = pbg->next
|
||||
p = pbg->buckets + ctz(pbg->bitmask)
|
||||
}
|
||||
```
|
||||
|
||||
`reset_first_bits` yields an unsigned integral with the first n bits set to 0
|
||||
and then by counting the number of trailing zeroes when AND'd against the bucket
|
||||
group's bitmask, we can derive the offset into the buckets array. When the
|
||||
calculated offset is equal to N, we know we've reached the end of a bucket group
|
||||
and we can advance to the next one.
|
||||
|
||||
This is a rough explanation for how iterator incrementation should work for a
|
||||
fixed width size of N as 3 for the bucket groups
|
||||
```
|
||||
N = 3
|
||||
p = buckets
|
||||
pbg->bitmask = 0b101
|
||||
pbg->buckets = buckets
|
||||
|
||||
offset = p - pbg->buckets // => 0
|
||||
testing_mask = reset_first_bits(offset + 1) // reset_first_bits(1) => 0b110
|
||||
|
||||
x = bitmask & testing_mask // => 0b101 & 0b110 => 0b100
|
||||
ctz(x) // ctz(0b100) => 2
|
||||
// 2 < 3
|
||||
=> p = pbg->buckets + 2
|
||||
|
||||
// increment again...
|
||||
offset = p - pbg->buckets // => 2
|
||||
testing_mask = reset_first_bits(offset + 1) // reset_first_bits(3) => 0b000
|
||||
|
||||
bitmask & testing_mask // 0b101 & 0b000 => 0b000
|
||||
ctz(0b000) => 3
|
||||
// 3 < 3 is false now
|
||||
pbg = pbg->next
|
||||
initial_offset = ctz(pbg->bitmask)
|
||||
p = pbg->buckets + initial_offset
|
||||
```
|
||||
|
||||
For `size_` number of buckets, there are `1 + (size_ / N)` bucket groups where
|
||||
`N` is the width of a bucket group, determined at compile-time.
|
||||
|
||||
We allocate space for `size_ + 1` buckets, using the last one as a dummy bucket
|
||||
which is kept permanently empty so it can act as a sentinel value in the
|
||||
implementation of `iterator end();`. We set the last bucket group to act as a
|
||||
sentinel.
|
||||
|
||||
```
|
||||
num_groups = size_ / N + 1
|
||||
groups = allocate(num_groups)
|
||||
pbg = groups + (num_groups - 1)
|
||||
|
||||
// not guaranteed to point to exactly N buckets
|
||||
pbg->buckets = buckets + N * (size_ / N)
|
||||
|
||||
// this marks the true end of the bucket array
|
||||
buckets pbg->bitmask = set_bit(size_ % N)
|
||||
|
||||
// links in on itself
|
||||
pbg->next = pbg->prev = pbg
|
||||
```
|
||||
|
||||
To this end, we can devise a safe iteration scheme while also creating a useful
|
||||
sentinel to use as the end iterator.
|
||||
|
||||
Otherwise, usage of the data structure is relatively straight-forward compared
|
||||
to normal separate chaining implementations.
|
||||
|
||||
*/
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/align/alignment_of.hpp>
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/core/bit.hpp>
|
||||
#include <boost/core/empty_value.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
// `iterator_facade` has transitive dependencies on Boost.MPL; one of the
|
||||
// headers is generating a `-Wsign-conversion` warning which has an open PR to
|
||||
// address the issue but merging does not seem likely so for now create a rote
|
||||
// workaround.
|
||||
//
|
||||
// TODO: eventually remove this once MPL is fixed or we decide to migrate off of
|
||||
// the Boost.Iterator dependency.
|
||||
//
|
||||
#if defined(BOOST_GCC)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
#else
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/move/core.hpp>
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/preprocessor/seq/enum.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
#include <boost/swap.hpp>
|
||||
#include <boost/type_traits/aligned_storage.hpp>
|
||||
|
||||
#include <climits>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
|
||||
#if defined(SIZE_MAX)
|
||||
#if ((((SIZE_MAX >> 16) >> 16) >> 16) >> 15) != 0
|
||||
#define BOOST_UNORDERED_FCA_HAS_64B_SIZE_T
|
||||
#endif
|
||||
#elif defined(UINTPTR_MAX) /* used as proxy for std::size_t */
|
||||
#if ((((UINTPTR_MAX >> 16) >> 16) >> 16) >> 15) != 0
|
||||
#define BOOST_UNORDERED_FCA_HAS_64B_SIZE_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_INT64_T) && \
|
||||
(defined(BOOST_HAS_INT128) || (defined(BOOST_MSVC) && defined(_WIN64)))
|
||||
#define BOOST_UNORDERED_FCA_FASTMOD_SUPPORT
|
||||
#endif
|
||||
|
||||
template <class = void> struct prime_fmod_size
|
||||
{
|
||||
// Because we compile for C++03, we don't have access to any inline
|
||||
// initialization for array data members so the definitions must exist
|
||||
// out-of-line. To keep the library header-only, we introduce a dummy
|
||||
// template parameter which permits the definition to be included in
|
||||
// multiple TUs without conflict.
|
||||
//
|
||||
static std::size_t sizes[];
|
||||
static std::size_t const sizes_len;
|
||||
static std::size_t (*positions[])(std::size_t);
|
||||
|
||||
#if defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT)
|
||||
static uint64_t inv_sizes32[];
|
||||
static std::size_t const inv_sizes32_len;
|
||||
#endif /* defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT) */
|
||||
|
||||
static inline std::size_t size_index(std::size_t n)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
for (; i < (sizes_len - 1); ++i) {
|
||||
if (sizes[i] >= n) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline std::size_t size(std::size_t size_index)
|
||||
{
|
||||
return sizes[size_index];
|
||||
}
|
||||
|
||||
template <std::size_t Size> static std::size_t modulo(std::size_t hash)
|
||||
{
|
||||
return hash % Size;
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT)
|
||||
// https://github.com/lemire/fastmod
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
static inline uint64_t mul128_u32(uint64_t lowbits, uint32_t d)
|
||||
{
|
||||
return __umulh(lowbits, d);
|
||||
}
|
||||
#else
|
||||
static inline uint64_t mul128_u32(uint64_t lowbits, uint32_t d)
|
||||
{
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
return static_cast<uint64_t>(((uint128)lowbits * d) >> 64);
|
||||
}
|
||||
#endif /* defined(_MSC_VER) */
|
||||
|
||||
static inline uint32_t fastmod_u32(uint32_t a, uint64_t M, uint32_t d)
|
||||
{
|
||||
uint64_t lowbits = M * a;
|
||||
return (uint32_t)(mul128_u32(lowbits, d));
|
||||
}
|
||||
#endif /* defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT) */
|
||||
|
||||
static inline std::size_t position(
|
||||
std::size_t hash, std::size_t size_index)
|
||||
{
|
||||
#if defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT)
|
||||
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
|
||||
std::size_t sizes_under_32bit = inv_sizes32_len;
|
||||
if (BOOST_LIKELY(size_index < sizes_under_32bit)) {
|
||||
return fastmod_u32(uint32_t(hash) + uint32_t(hash >> 32),
|
||||
inv_sizes32[size_index], uint32_t(sizes[size_index]));
|
||||
} else {
|
||||
return positions[size_index - sizes_under_32bit](hash);
|
||||
}
|
||||
#else
|
||||
return fastmod_u32(
|
||||
hash, inv_sizes32[size_index], uint32_t(sizes[size_index]));
|
||||
#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */
|
||||
#else
|
||||
return positions[size_index](hash);
|
||||
#endif /* defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT) */
|
||||
}
|
||||
}; // prime_fmod_size
|
||||
|
||||
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE \
|
||||
(13ul)(29ul)(53ul)(97ul)(193ul)(389ul)(769ul)(1543ul)(3079ul)(6151ul)( \
|
||||
12289ul)(24593ul)(49157ul)(98317ul)(196613ul)(393241ul)(786433ul)( \
|
||||
1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul)(50331653ul)( \
|
||||
100663319ul)(201326611ul)(402653189ul)(805306457ul)(1610612741ul)( \
|
||||
3221225473ul)
|
||||
|
||||
#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
|
||||
|
||||
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT \
|
||||
BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE(4294967291ul)
|
||||
|
||||
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT \
|
||||
BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE
|
||||
|
||||
// The original sequence here is this:
|
||||
// (6442450939ul)
|
||||
// (12884901893ul)
|
||||
// (25769803751ul)
|
||||
// (51539607551ul)
|
||||
// (103079215111ul)
|
||||
// (206158430209ul)
|
||||
// (412316860441ul)
|
||||
// (824633720831ul)
|
||||
// (1649267441651ul)
|
||||
//
|
||||
// but this causes problems on versions of mingw where the `long` type is 32
|
||||
// bits, even for 64-bit targets. We work around this by replacing the literals
|
||||
// with compile-time arithmetic, using bitshifts to reconstruct the number.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
#define BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT \
|
||||
((boost::ulong_long_type(1ul) << 32) + boost::ulong_long_type(2147483643ul)) \
|
||||
((boost::ulong_long_type(3ul) << 32) + boost::ulong_long_type(5ul)) \
|
||||
((boost::ulong_long_type(5ul) << 32) + boost::ulong_long_type(4294967271ul)) \
|
||||
((boost::ulong_long_type(11ul) << 32) + boost::ulong_long_type(4294967295ul)) \
|
||||
((boost::ulong_long_type(24ul) << 32) + boost::ulong_long_type(7ul)) \
|
||||
((boost::ulong_long_type(48ul) << 32) + boost::ulong_long_type(1ul)) \
|
||||
((boost::ulong_long_type(96ul) << 32) + boost::ulong_long_type(25ul)) \
|
||||
((boost::ulong_long_type(191ul) << 32) + boost::ulong_long_type(4294967295ul)) \
|
||||
((boost::ulong_long_type(383ul) << 32) + boost::ulong_long_type(4294967283ul))
|
||||
// clang-format on
|
||||
|
||||
#endif /* BOOST_UNORDERED_FCA_HAS_64B_SIZE_T */
|
||||
|
||||
#define BOOST_UNORDERED_PRIME_FMOD_SIZES \
|
||||
BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT
|
||||
|
||||
template <class T>
|
||||
std::size_t prime_fmod_size<T>::sizes[] = {
|
||||
BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIME_FMOD_SIZES)};
|
||||
|
||||
template <class T>
|
||||
std::size_t const prime_fmod_size<T>::sizes_len = BOOST_PP_SEQ_SIZE(
|
||||
BOOST_UNORDERED_PRIME_FMOD_SIZES);
|
||||
|
||||
// Similarly here, we have to re-express the integer initialization using
|
||||
// arithmetic such that each literal can fit in a 32-bit value.
|
||||
//
|
||||
#if defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT)
|
||||
// clang-format off
|
||||
template <class T>
|
||||
uint64_t prime_fmod_size<T>::inv_sizes32[] = {
|
||||
(boost::ulong_long_type(330382099ul) << 32) + boost::ulong_long_type(2973438898ul) /* = 1418980313362273202 */,
|
||||
(boost::ulong_long_type(148102320ul) << 32) + boost::ulong_long_type(2369637129ul) /* = 636094623231363849 */,
|
||||
(boost::ulong_long_type(81037118ul) << 32) + boost::ulong_long_type(3403558990ul) /* = 348051774975651918 */,
|
||||
(boost::ulong_long_type(44278013ul) << 32) + boost::ulong_long_type(1549730468ul) /* = 190172619316593316 */,
|
||||
(boost::ulong_long_type(22253716ul) << 32) + boost::ulong_long_type(2403401389ul) /* = 95578984837873325 */,
|
||||
(boost::ulong_long_type(11041047ul) << 32) + boost::ulong_long_type(143533612ul) /* = 47420935922132524 */,
|
||||
(boost::ulong_long_type(5585133ul) << 32) + boost::ulong_long_type(106117528ul) /* = 23987963684927896 */,
|
||||
(boost::ulong_long_type(2783517ul) << 32) + boost::ulong_long_type(1572687312ul) /* = 11955116055547344 */,
|
||||
(boost::ulong_long_type(1394922ul) << 32) + boost::ulong_long_type(3428720239ul) /* = 5991147799191151 */,
|
||||
(boost::ulong_long_type(698255ul) << 32) + boost::ulong_long_type(552319807ul) /* = 2998982941588287 */,
|
||||
(boost::ulong_long_type(349496ul) << 32) + boost::ulong_long_type(3827689953ul) /* = 1501077717772769 */,
|
||||
(boost::ulong_long_type(174641ul) << 32) + boost::ulong_long_type(3699438549ul) /* = 750081082979285 */,
|
||||
(boost::ulong_long_type(87372ul) << 32) + boost::ulong_long_type(1912757574ul) /* = 375261795343686 */,
|
||||
(boost::ulong_long_type(43684ul) << 32) + boost::ulong_long_type(3821029929ul) /* = 187625172388393 */,
|
||||
(boost::ulong_long_type(21844ul) << 32) + boost::ulong_long_type(3340590800ul) /* = 93822606204624 */,
|
||||
(boost::ulong_long_type(10921ul) << 32) + boost::ulong_long_type(4175852267ul) /* = 46909513691883 */,
|
||||
(boost::ulong_long_type(5461ul) << 32) + boost::ulong_long_type(1401829642ul) /* = 23456218233098 */,
|
||||
(boost::ulong_long_type(2730ul) << 32) + boost::ulong_long_type(2826028947ul) /* = 11728086747027 */,
|
||||
(boost::ulong_long_type(1365ul) << 32) + boost::ulong_long_type(1411150351ul) /* = 5864041509391 */,
|
||||
(boost::ulong_long_type(682ul) << 32) + boost::ulong_long_type(2857253105ul) /* = 2932024948977 */,
|
||||
(boost::ulong_long_type(341ul) << 32) + boost::ulong_long_type(1431073224ul) /* = 1466014921160 */,
|
||||
(boost::ulong_long_type(170ul) << 32) + boost::ulong_long_type(2862758116ul) /* = 733007198436 */,
|
||||
(boost::ulong_long_type(85ul) << 32) + boost::ulong_long_type(1431619357ul) /* = 366503839517 */,
|
||||
(boost::ulong_long_type(42ul) << 32) + boost::ulong_long_type(2863269661ul) /* = 183251896093 */,
|
||||
(boost::ulong_long_type(21ul) << 32) + boost::ulong_long_type(1431647119ul) /* = 91625960335 */,
|
||||
(boost::ulong_long_type(10ul) << 32) + boost::ulong_long_type(2863310962ul) /* = 45812983922 */,
|
||||
(boost::ulong_long_type(5ul) << 32) + boost::ulong_long_type(1431653234ul) /* = 22906489714 */,
|
||||
(boost::ulong_long_type(2ul) << 32) + boost::ulong_long_type(2863311496ul) /* = 11453246088 */,
|
||||
(boost::ulong_long_type(1ul) << 32) + boost::ulong_long_type(1431655764ul) /* = 5726623060 */,
|
||||
#if !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
|
||||
};
|
||||
#else
|
||||
(boost::ulong_long_type(1ul) << 32) + boost::ulong_long_type(6ul) /* 4294967302 */
|
||||
};
|
||||
// clang-format on
|
||||
#endif /* !defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */
|
||||
|
||||
template <class T>
|
||||
std::size_t const
|
||||
prime_fmod_size<T>::inv_sizes32_len = sizeof(inv_sizes32) /
|
||||
sizeof(inv_sizes32[0]);
|
||||
|
||||
#endif /* defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT) */
|
||||
|
||||
#define BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT(z, _, n) \
|
||||
prime_fmod_size<T>::template modulo<n>,
|
||||
|
||||
template <class T>
|
||||
std::size_t (*prime_fmod_size<T>::positions[])(std::size_t) = {
|
||||
#if !defined(BOOST_UNORDERED_FCA_FASTMOD_SUPPORT)
|
||||
BOOST_PP_SEQ_FOR_EACH(BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT, ~,
|
||||
BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT)
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
|
||||
BOOST_PP_SEQ_FOR_EACH(BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT, ~,
|
||||
BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT)
|
||||
#endif
|
||||
};
|
||||
|
||||
#undef BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT
|
||||
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES
|
||||
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_64BIT
|
||||
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_34BIT
|
||||
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_34BIT_INCOMPLETE
|
||||
|
||||
#ifdef BOOST_UNORDERED_FCA_FASTMOD_SUPPORT
|
||||
#undef BOOST_UNORDERED_FCA_FASTMOD_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_UNORDERED_FCA_HAS_64B_SIZE_T
|
||||
#undef BOOST_UNORDERED_FCA_HAS_64B_SIZE_T
|
||||
#endif
|
||||
|
||||
template <class ValueType, class VoidPtr> struct node
|
||||
{
|
||||
typedef ValueType value_type;
|
||||
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
|
||||
node>::type node_pointer;
|
||||
|
||||
node_pointer next;
|
||||
typename boost::aligned_storage<sizeof(value_type),
|
||||
boost::alignment_of<value_type>::value>::type buf;
|
||||
|
||||
node() BOOST_NOEXCEPT : next(), buf() {}
|
||||
|
||||
value_type* value_ptr() BOOST_NOEXCEPT
|
||||
{
|
||||
return reinterpret_cast<value_type*>(buf.address());
|
||||
}
|
||||
|
||||
value_type& value() BOOST_NOEXCEPT
|
||||
{
|
||||
return *reinterpret_cast<value_type*>(buf.address());
|
||||
}
|
||||
};
|
||||
|
||||
template <class Node, class VoidPtr> struct bucket
|
||||
{
|
||||
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
|
||||
Node>::type node_pointer;
|
||||
|
||||
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
|
||||
bucket>::type bucket_pointer;
|
||||
|
||||
node_pointer next;
|
||||
|
||||
bucket() BOOST_NOEXCEPT : next() {}
|
||||
};
|
||||
|
||||
template <class Bucket> struct bucket_group
|
||||
{
|
||||
typedef typename Bucket::bucket_pointer bucket_pointer;
|
||||
typedef
|
||||
typename boost::pointer_traits<bucket_pointer>::template rebind_to<
|
||||
bucket_group>::type bucket_group_pointer;
|
||||
|
||||
BOOST_STATIC_CONSTANT(std::size_t, N = sizeof(std::size_t) * CHAR_BIT);
|
||||
|
||||
bucket_pointer buckets;
|
||||
std::size_t bitmask;
|
||||
bucket_group_pointer next, prev;
|
||||
|
||||
bucket_group() BOOST_NOEXCEPT : buckets(), bitmask(0), next(), prev() {}
|
||||
~bucket_group() {}
|
||||
};
|
||||
|
||||
inline std::size_t set_bit(std::size_t n) { return std::size_t(1) << n; }
|
||||
|
||||
inline std::size_t reset_bit(std::size_t n)
|
||||
{
|
||||
return ~(std::size_t(1) << n);
|
||||
}
|
||||
|
||||
inline std::size_t reset_first_bits(std::size_t n) // n>0
|
||||
{
|
||||
return ~(~(std::size_t(0)) >> (sizeof(std::size_t) * 8 - n));
|
||||
}
|
||||
|
||||
template <class Bucket>
|
||||
struct grouped_bucket_iterator
|
||||
: public boost::iterator_facade<grouped_bucket_iterator<Bucket>,
|
||||
Bucket, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
typedef typename Bucket::bucket_pointer bucket_pointer;
|
||||
typedef
|
||||
typename boost::pointer_traits<bucket_pointer>::template rebind_to<
|
||||
bucket_group<Bucket> >::type bucket_group_pointer;
|
||||
|
||||
typedef typename boost::pointer_traits<bucket_pointer>::difference_type
|
||||
difference_type;
|
||||
|
||||
private:
|
||||
bucket_pointer p;
|
||||
bucket_group_pointer pbg;
|
||||
|
||||
public:
|
||||
grouped_bucket_iterator() : p(), pbg() {}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
template <typename, typename, typename>
|
||||
friend class grouped_bucket_array;
|
||||
|
||||
BOOST_STATIC_CONSTANT(std::size_t, N = bucket_group<Bucket>::N);
|
||||
|
||||
grouped_bucket_iterator(bucket_pointer p_, bucket_group_pointer pbg_)
|
||||
: p(p_), pbg(pbg_)
|
||||
{
|
||||
}
|
||||
|
||||
Bucket& dereference() const BOOST_NOEXCEPT { return *p; }
|
||||
|
||||
bool equal(const grouped_bucket_iterator& x) const BOOST_NOEXCEPT
|
||||
{
|
||||
return p == x.p;
|
||||
}
|
||||
|
||||
void increment() BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t const offset = static_cast<std::size_t>(p - pbg->buckets);
|
||||
|
||||
std::size_t n = std::size_t(boost::core::countr_zero(
|
||||
pbg->bitmask & reset_first_bits(offset + 1)));
|
||||
|
||||
if (n < N) {
|
||||
p = pbg->buckets + static_cast<difference_type>(n);
|
||||
} else {
|
||||
pbg = pbg->next;
|
||||
|
||||
std::ptrdiff_t x = boost::core::countr_zero(pbg->bitmask);
|
||||
p = pbg->buckets + x;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Node> struct const_grouped_local_bucket_iterator;
|
||||
|
||||
template <class Node>
|
||||
struct grouped_local_bucket_iterator
|
||||
: public boost::iterator_facade<grouped_local_bucket_iterator<Node>,
|
||||
typename Node::value_type, boost::forward_traversal_tag>
|
||||
{
|
||||
|
||||
typedef typename Node::node_pointer node_pointer;
|
||||
|
||||
public:
|
||||
typedef typename Node::value_type value_type;
|
||||
typedef value_type element_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
grouped_local_bucket_iterator() : p() {}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
template <typename, typename, typename>
|
||||
friend class grouped_bucket_array;
|
||||
|
||||
template <class> friend struct const_grouped_local_bucket_iterator;
|
||||
|
||||
grouped_local_bucket_iterator(node_pointer p_) : p(p_) {}
|
||||
|
||||
value_type& dereference() const BOOST_NOEXCEPT { return p->value(); }
|
||||
|
||||
bool equal(const grouped_local_bucket_iterator& x) const BOOST_NOEXCEPT
|
||||
{
|
||||
return p == x.p;
|
||||
}
|
||||
|
||||
void increment() BOOST_NOEXCEPT { p = p->next; }
|
||||
|
||||
node_pointer p;
|
||||
};
|
||||
|
||||
template <class Node>
|
||||
struct const_grouped_local_bucket_iterator
|
||||
: public boost::iterator_facade<
|
||||
const_grouped_local_bucket_iterator<Node>,
|
||||
typename Node::value_type const, boost::forward_traversal_tag>
|
||||
{
|
||||
typedef typename Node::node_pointer node_pointer;
|
||||
|
||||
public:
|
||||
typedef typename Node::value_type const value_type;
|
||||
typedef value_type const element_type;
|
||||
typedef value_type const* pointer;
|
||||
typedef value_type const& reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
const_grouped_local_bucket_iterator() : p() {}
|
||||
const_grouped_local_bucket_iterator(
|
||||
grouped_local_bucket_iterator<Node> it)
|
||||
: p(it.p)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
template <typename, typename, typename>
|
||||
friend class grouped_bucket_array;
|
||||
|
||||
const_grouped_local_bucket_iterator(node_pointer p_) : p(p_) {}
|
||||
|
||||
value_type& dereference() const BOOST_NOEXCEPT { return p->value(); }
|
||||
|
||||
bool equal(
|
||||
const const_grouped_local_bucket_iterator& x) const BOOST_NOEXCEPT
|
||||
{
|
||||
return p == x.p;
|
||||
}
|
||||
|
||||
void increment() BOOST_NOEXCEPT { p = p->next; }
|
||||
|
||||
node_pointer p;
|
||||
};
|
||||
|
||||
template <class T> struct span
|
||||
{
|
||||
T* begin() const BOOST_NOEXCEPT { return data; }
|
||||
T* end() const BOOST_NOEXCEPT { return data + size; }
|
||||
|
||||
T* data;
|
||||
std::size_t size;
|
||||
|
||||
span(T* data_, std::size_t size_) : data(data_), size(size_) {}
|
||||
};
|
||||
|
||||
template <class Bucket, class Allocator, class SizePolicy>
|
||||
class grouped_bucket_array
|
||||
: boost::empty_value<typename boost::allocator_rebind<Allocator,
|
||||
node<typename boost::allocator_value_type<Allocator>::type,
|
||||
typename boost::allocator_void_pointer<Allocator>::type> >::
|
||||
type>
|
||||
{
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(grouped_bucket_array)
|
||||
|
||||
typedef typename boost::allocator_value_type<Allocator>::type
|
||||
allocator_value_type;
|
||||
typedef
|
||||
typename boost::allocator_void_pointer<Allocator>::type void_pointer;
|
||||
typedef typename boost::allocator_difference_type<Allocator>::type
|
||||
difference_type;
|
||||
|
||||
public:
|
||||
typedef typename boost::allocator_rebind<Allocator,
|
||||
node<allocator_value_type, void_pointer> >::type node_allocator_type;
|
||||
|
||||
typedef node<allocator_value_type, void_pointer> node_type;
|
||||
typedef typename boost::allocator_pointer<node_allocator_type>::type
|
||||
node_pointer;
|
||||
typedef SizePolicy size_policy;
|
||||
|
||||
private:
|
||||
typedef typename boost::allocator_rebind<Allocator, Bucket>::type
|
||||
bucket_allocator_type;
|
||||
typedef typename boost::allocator_pointer<bucket_allocator_type>::type
|
||||
bucket_pointer;
|
||||
typedef boost::pointer_traits<bucket_pointer> bucket_pointer_traits;
|
||||
|
||||
typedef bucket_group<Bucket> group;
|
||||
typedef typename boost::allocator_rebind<Allocator, group>::type
|
||||
group_allocator_type;
|
||||
typedef typename boost::allocator_pointer<group_allocator_type>::type
|
||||
group_pointer;
|
||||
typedef typename boost::pointer_traits<group_pointer>
|
||||
group_pointer_traits;
|
||||
|
||||
public:
|
||||
typedef Bucket value_type;
|
||||
typedef Bucket bucket_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef Allocator allocator_type;
|
||||
typedef grouped_bucket_iterator<Bucket> iterator;
|
||||
typedef grouped_local_bucket_iterator<node_type> local_iterator;
|
||||
typedef const_grouped_local_bucket_iterator<node_type>
|
||||
const_local_iterator;
|
||||
|
||||
private:
|
||||
std::size_t size_index_, size_;
|
||||
bucket_pointer buckets;
|
||||
group_pointer groups;
|
||||
|
||||
public:
|
||||
grouped_bucket_array(size_type n, const Allocator& al)
|
||||
: empty_value<node_allocator_type>(empty_init_t(), al),
|
||||
size_index_(size_policy::size_index(n)),
|
||||
size_(size_policy::size(size_index_)), buckets(), groups()
|
||||
{
|
||||
bucket_allocator_type bucket_alloc = this->get_bucket_allocator();
|
||||
group_allocator_type group_alloc = this->get_group_allocator();
|
||||
|
||||
size_type const num_buckets = buckets_len();
|
||||
size_type const num_groups = groups_len();
|
||||
|
||||
buckets = boost::allocator_allocate(bucket_alloc, num_buckets);
|
||||
BOOST_TRY
|
||||
{
|
||||
groups = boost::allocator_allocate(group_alloc, num_groups);
|
||||
|
||||
bucket_type* pb = boost::to_address(buckets);
|
||||
for (size_type i = 0; i < num_buckets; ++i) {
|
||||
new (pb + i) bucket_type();
|
||||
}
|
||||
|
||||
group* pg = boost::to_address(groups);
|
||||
for (size_type i = 0; i < num_groups; ++i) {
|
||||
new (pg + i) group();
|
||||
}
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::allocator_deallocate(bucket_alloc, buckets, num_buckets);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
|
||||
size_type const N = group::N;
|
||||
group_pointer pbg =
|
||||
groups + static_cast<difference_type>(num_groups - 1);
|
||||
|
||||
pbg->buckets =
|
||||
buckets + static_cast<difference_type>(N * (size_ / N));
|
||||
pbg->bitmask = set_bit(size_ % N);
|
||||
pbg->next = pbg->prev = pbg;
|
||||
}
|
||||
|
||||
~grouped_bucket_array() { this->deallocate(); }
|
||||
|
||||
grouped_bucket_array(
|
||||
BOOST_RV_REF(grouped_bucket_array) other) BOOST_NOEXCEPT
|
||||
: empty_value<node_allocator_type>(
|
||||
empty_init_t(), other.get_node_allocator()),
|
||||
size_index_(other.size_index_),
|
||||
size_(other.size_),
|
||||
buckets(other.buckets),
|
||||
groups(other.groups)
|
||||
{
|
||||
other.size_ = 0;
|
||||
other.size_index_ = 0;
|
||||
other.buckets = bucket_pointer();
|
||||
other.groups = group_pointer();
|
||||
}
|
||||
|
||||
grouped_bucket_array& operator=(
|
||||
BOOST_RV_REF(grouped_bucket_array) other) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
this->get_node_allocator() == other.get_node_allocator());
|
||||
|
||||
if (this == boost::addressof(other)) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
this->deallocate();
|
||||
size_index_ = other.size_index_;
|
||||
size_ = other.size_;
|
||||
|
||||
buckets = other.buckets;
|
||||
groups = other.groups;
|
||||
|
||||
other.size_index_ = 0;
|
||||
other.size_ = 0;
|
||||
other.buckets = bucket_pointer();
|
||||
other.groups = group_pointer();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void deallocate() BOOST_NOEXCEPT
|
||||
{
|
||||
if (buckets) {
|
||||
bucket_allocator_type bucket_alloc = this->get_bucket_allocator();
|
||||
boost::allocator_deallocate(
|
||||
bucket_alloc, buckets, this->buckets_len());
|
||||
|
||||
buckets = bucket_pointer();
|
||||
}
|
||||
|
||||
if (groups) {
|
||||
group_allocator_type group_alloc = this->get_group_allocator();
|
||||
boost::allocator_deallocate(
|
||||
group_alloc, groups, this->groups_len());
|
||||
|
||||
groups = group_pointer();
|
||||
}
|
||||
}
|
||||
|
||||
void swap(grouped_bucket_array& other)
|
||||
{
|
||||
std::swap(size_index_, other.size_index_);
|
||||
std::swap(size_, other.size_);
|
||||
std::swap(buckets, other.buckets);
|
||||
std::swap(groups, other.groups);
|
||||
|
||||
bool b = boost::allocator_propagate_on_container_swap<
|
||||
allocator_type>::type::value;
|
||||
if (b) {
|
||||
boost::swap(get_node_allocator(), other.get_node_allocator());
|
||||
}
|
||||
}
|
||||
|
||||
node_allocator_type const& get_node_allocator() const
|
||||
{
|
||||
return empty_value<node_allocator_type>::get();
|
||||
}
|
||||
|
||||
node_allocator_type& get_node_allocator()
|
||||
{
|
||||
return empty_value<node_allocator_type>::get();
|
||||
}
|
||||
|
||||
bucket_allocator_type get_bucket_allocator() const
|
||||
{
|
||||
return this->get_node_allocator();
|
||||
}
|
||||
|
||||
group_allocator_type get_group_allocator() const
|
||||
{
|
||||
return this->get_node_allocator();
|
||||
}
|
||||
|
||||
size_type buckets_len() const BOOST_NOEXCEPT { return size_ + 1; }
|
||||
|
||||
size_type groups_len() const BOOST_NOEXCEPT
|
||||
{
|
||||
return size_ / group::N + 1;
|
||||
}
|
||||
|
||||
void reset_allocator(Allocator const& allocator_)
|
||||
{
|
||||
this->get_node_allocator() = node_allocator_type(allocator_);
|
||||
}
|
||||
|
||||
size_type bucket_count() const { return size_; }
|
||||
|
||||
iterator begin() const { return ++at(size_); }
|
||||
|
||||
iterator end() const
|
||||
{
|
||||
// micro optimization: no need to return the bucket group
|
||||
// as end() is not incrementable
|
||||
iterator pbg;
|
||||
pbg.p =
|
||||
buckets + static_cast<difference_type>(this->buckets_len() - 1);
|
||||
return pbg;
|
||||
}
|
||||
|
||||
local_iterator begin(size_type n) const
|
||||
{
|
||||
return local_iterator(
|
||||
(buckets + static_cast<difference_type>(n))->next);
|
||||
}
|
||||
|
||||
local_iterator end(size_type) const { return local_iterator(); }
|
||||
|
||||
size_type capacity() const BOOST_NOEXCEPT { return size_; }
|
||||
|
||||
iterator at(size_type n) const
|
||||
{
|
||||
std::size_t const N = group::N;
|
||||
|
||||
iterator pbg(buckets + static_cast<difference_type>(n),
|
||||
groups + static_cast<difference_type>(n / N));
|
||||
|
||||
return pbg;
|
||||
}
|
||||
|
||||
span<Bucket> raw()
|
||||
{
|
||||
BOOST_ASSERT(size_ == 0 || size_ < this->buckets_len());
|
||||
return span<Bucket>(boost::to_address(buckets), size_);
|
||||
}
|
||||
|
||||
size_type position(std::size_t hash) const
|
||||
{
|
||||
return size_policy::position(hash, size_index_);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
this->deallocate();
|
||||
size_index_ = 0;
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
void append_bucket_group(iterator itb) BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t const N = group::N;
|
||||
|
||||
bool const is_empty_bucket = (!itb->next);
|
||||
if (is_empty_bucket) {
|
||||
bucket_pointer pb = itb.p;
|
||||
group_pointer pbg = itb.pbg;
|
||||
|
||||
std::size_t n =
|
||||
static_cast<std::size_t>(boost::to_address(pb) - &buckets[0]);
|
||||
|
||||
bool const is_empty_group = (!pbg->bitmask);
|
||||
if (is_empty_group) {
|
||||
size_type const num_groups = this->groups_len();
|
||||
group_pointer last_group =
|
||||
groups + static_cast<difference_type>(num_groups - 1);
|
||||
|
||||
pbg->buckets =
|
||||
buckets + static_cast<difference_type>(N * (n / N));
|
||||
pbg->next = last_group->next;
|
||||
pbg->next->prev = pbg;
|
||||
pbg->prev = last_group;
|
||||
pbg->prev->next = pbg;
|
||||
}
|
||||
|
||||
pbg->bitmask |= set_bit(n % N);
|
||||
}
|
||||
}
|
||||
|
||||
void insert_node(iterator itb, node_pointer p) BOOST_NOEXCEPT
|
||||
{
|
||||
this->append_bucket_group(itb);
|
||||
|
||||
p->next = itb->next;
|
||||
itb->next = p;
|
||||
}
|
||||
|
||||
void insert_node_hint(
|
||||
iterator itb, node_pointer p, node_pointer hint) BOOST_NOEXCEPT
|
||||
{
|
||||
this->append_bucket_group(itb);
|
||||
|
||||
if (hint) {
|
||||
p->next = hint->next;
|
||||
hint->next = p;
|
||||
} else {
|
||||
p->next = itb->next;
|
||||
itb->next = p;
|
||||
}
|
||||
}
|
||||
|
||||
void extract_node(iterator itb, node_pointer p) BOOST_NOEXCEPT
|
||||
{
|
||||
node_pointer* pp = boost::addressof(itb->next);
|
||||
while ((*pp) != p)
|
||||
pp = boost::addressof((*pp)->next);
|
||||
*pp = p->next;
|
||||
if (!itb->next)
|
||||
unlink_bucket(itb);
|
||||
}
|
||||
|
||||
void extract_node_after(iterator itb, node_pointer* pp) BOOST_NOEXCEPT
|
||||
{
|
||||
*pp = (*pp)->next;
|
||||
if (!itb->next)
|
||||
unlink_bucket(itb);
|
||||
}
|
||||
|
||||
void unlink_empty_buckets() BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t const N = group::N;
|
||||
|
||||
group_pointer pbg = groups,
|
||||
last = groups + static_cast<difference_type>(
|
||||
this->groups_len() - 1);
|
||||
|
||||
for (; pbg != last; ++pbg) {
|
||||
if (!pbg->buckets) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (std::size_t n = 0; n < N; ++n) {
|
||||
bucket_pointer bs = pbg->buckets;
|
||||
bucket_type& b = bs[static_cast<std::ptrdiff_t>(n)];
|
||||
if (!b.next)
|
||||
pbg->bitmask &= reset_bit(n);
|
||||
}
|
||||
if (!pbg->bitmask && pbg->next)
|
||||
unlink_group(pbg);
|
||||
}
|
||||
|
||||
// do not check end bucket
|
||||
for (std::size_t n = 0; n < size_ % N; ++n) {
|
||||
if (!pbg->buckets[static_cast<std::ptrdiff_t>(n)].next)
|
||||
pbg->bitmask &= reset_bit(n);
|
||||
}
|
||||
}
|
||||
|
||||
void unlink_bucket(iterator itb)
|
||||
{
|
||||
typename iterator::bucket_pointer p = itb.p;
|
||||
typename iterator::bucket_group_pointer pbg = itb.pbg;
|
||||
if (!(pbg->bitmask &=
|
||||
reset_bit(static_cast<std::size_t>(p - pbg->buckets))))
|
||||
unlink_group(pbg);
|
||||
}
|
||||
|
||||
private:
|
||||
void unlink_group(group_pointer pbg)
|
||||
{
|
||||
pbg->next->prev = pbg->prev;
|
||||
pbg->prev->next = pbg->next;
|
||||
pbg->prev = pbg->next = group_pointer();
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_FCA_HPP
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright (C) 2005-2016 Daniel James
|
||||
// Copyright (C) 2022 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)
|
||||
|
||||
@@ -25,25 +26,18 @@ namespace boost {
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
|
||||
typedef boost::unordered::detail::pick_node<A, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::table<types> table;
|
||||
typedef boost::unordered::detail::map_extractor<value_type> extractor;
|
||||
|
||||
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
|
||||
typedef typename boost::allocator_void_pointer<value_allocator>::type
|
||||
void_pointer;
|
||||
|
||||
typedef boost::unordered::iterator_detail::iterator<node> iterator;
|
||||
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
|
||||
typedef boost::unordered::iterator_detail::l_iterator<node> l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node>
|
||||
cl_iterator;
|
||||
typedef boost::unordered::node_handle_map<
|
||||
node<value_type, void_pointer>, K, M, A>
|
||||
node_type;
|
||||
|
||||
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_map<node, K, M, A>
|
||||
insert_return_type;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef boost::unordered::insert_return_type_map<iterator, node_type> insert_return_type;
|
||||
};
|
||||
|
||||
template <typename K, typename M, typename H, typename P, typename A>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright (C) 2005-2016 Daniel James
|
||||
// Copyright (C) 2022 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)
|
||||
|
||||
@@ -24,24 +25,18 @@ namespace boost {
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
|
||||
typedef boost::unordered::detail::pick_node<A, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::table<types> table;
|
||||
typedef boost::unordered::detail::set_extractor<value_type> extractor;
|
||||
|
||||
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
|
||||
typedef typename boost::allocator_void_pointer<value_allocator>::type
|
||||
void_pointer;
|
||||
|
||||
typedef boost::unordered::iterator_detail::c_iterator<node> iterator;
|
||||
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node> l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node>
|
||||
cl_iterator;
|
||||
typedef boost::unordered::node_handle_set<
|
||||
node<value_type, void_pointer>, T, A>
|
||||
node_type;
|
||||
|
||||
typedef boost::unordered::node_handle_set<node, T, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_set<node, T, A>
|
||||
typedef typename table::c_iterator iterator;
|
||||
typedef boost::unordered::insert_return_type_set<iterator, node_type>
|
||||
insert_return_type;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2011 Daniel James.
|
||||
// Copyright (C) 2022 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)
|
||||
|
||||
@@ -57,8 +58,6 @@ namespace boost {
|
||||
typedef boost::unordered::detail::map<A, K, T, H, P> types;
|
||||
typedef typename types::value_allocator_traits value_allocator_traits;
|
||||
typedef typename types::table table;
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
typedef typename table::link_pointer link_pointer;
|
||||
|
||||
public:
|
||||
typedef typename value_allocator_traits::pointer pointer;
|
||||
@@ -97,7 +96,7 @@ namespace boost {
|
||||
|
||||
unordered_map(unordered_map const&);
|
||||
|
||||
#if defined(BOOST_UNORDERED_USE_MOVE) || \
|
||||
#if defined(BOOST_UNORDERED_USE_MOVE) || \
|
||||
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
unordered_map(BOOST_RV_REF(unordered_map) other)
|
||||
BOOST_NOEXCEPT_IF(table::nothrow_move_constructible)
|
||||
@@ -188,9 +187,9 @@ namespace boost {
|
||||
return table_.node_alloc();
|
||||
}
|
||||
|
||||
// iterators
|
||||
// // iterators
|
||||
|
||||
iterator begin() BOOST_NOEXCEPT { return iterator(table_.begin()); }
|
||||
iterator begin() BOOST_NOEXCEPT { return table_.begin(); }
|
||||
|
||||
const_iterator begin() const BOOST_NOEXCEPT
|
||||
{
|
||||
@@ -445,7 +444,7 @@ namespace boost {
|
||||
insert_return_type insert(BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
insert_return_type result;
|
||||
table_.move_insert_node_type_unique(np, result);
|
||||
table_.move_insert_node_type_unique((node_type&)np, result);
|
||||
return boost::move(result);
|
||||
}
|
||||
|
||||
@@ -728,8 +727,7 @@ namespace boost {
|
||||
size_type>::type
|
||||
erase(BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
return table_.erase_key_unique_impl(
|
||||
this->key_eq(), boost::forward<Key>(k));
|
||||
return table_.erase_key_unique_impl(boost::forward<Key>(k));
|
||||
}
|
||||
|
||||
BOOST_UNORDERED_DEPRECATED("Use erase instead")
|
||||
@@ -774,9 +772,7 @@ namespace boost {
|
||||
iterator>::type
|
||||
find(const Key& key)
|
||||
{
|
||||
return iterator(table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), key), key,
|
||||
this->key_eq()));
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -784,9 +780,7 @@ namespace boost {
|
||||
const_iterator>::type
|
||||
find(const Key& key) const
|
||||
{
|
||||
return const_iterator(table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), key), key,
|
||||
this->key_eq()));
|
||||
return const_iterator(table_.find(key));
|
||||
}
|
||||
|
||||
template <class CompatibleKey, class CompatibleHash,
|
||||
@@ -801,9 +795,7 @@ namespace boost {
|
||||
|
||||
bool contains(const key_type& k) const
|
||||
{
|
||||
return 0 != table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
return table_.find(k) != this->end();
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -811,9 +803,7 @@ namespace boost {
|
||||
bool>::type
|
||||
contains(const Key& k) const
|
||||
{
|
||||
return 0 != table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
return table_.find(k) != this->end();
|
||||
}
|
||||
|
||||
size_type count(const key_type&) const;
|
||||
@@ -823,14 +813,7 @@ namespace boost {
|
||||
size_type>::type
|
||||
count(const Key& k) const
|
||||
{
|
||||
std::size_t const key_hash =
|
||||
table::policy::apply_hash(this->hash_function(), k);
|
||||
|
||||
P const& eq = this->key_eq();
|
||||
|
||||
node_pointer p = table_.find_node_impl(key_hash, k, eq);
|
||||
|
||||
return (p ? 1 : 0);
|
||||
return (table_.find(k) != this->end() ? 1 : 0);
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type&);
|
||||
@@ -842,12 +825,13 @@ namespace boost {
|
||||
std::pair<iterator, iterator> >::type
|
||||
equal_range(const Key& key)
|
||||
{
|
||||
node_pointer p = table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), key), key,
|
||||
this->key_eq());
|
||||
iterator first = table_.find(key);
|
||||
iterator last = first;
|
||||
if (last != this->end()) {
|
||||
++last;
|
||||
}
|
||||
|
||||
return std::make_pair(
|
||||
iterator(p), iterator(p ? table::next_node(p) : p));
|
||||
return std::make_pair(first, last);
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -855,12 +839,13 @@ namespace boost {
|
||||
std::pair<const_iterator, const_iterator> >::type
|
||||
equal_range(const Key& key) const
|
||||
{
|
||||
node_pointer p = table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), key), key,
|
||||
this->key_eq());
|
||||
iterator first = table_.find(key);
|
||||
iterator last = first;
|
||||
if (last != this->end()) {
|
||||
++last;
|
||||
}
|
||||
|
||||
return std::make_pair(
|
||||
const_iterator(p), const_iterator(p ? table::next_node(p) : p));
|
||||
return std::make_pair(first, last);
|
||||
}
|
||||
|
||||
mapped_type& operator[](const key_type&);
|
||||
@@ -872,7 +857,7 @@ namespace boost {
|
||||
|
||||
size_type bucket_count() const BOOST_NOEXCEPT
|
||||
{
|
||||
return table_.bucket_count_;
|
||||
return table_.bucket_count();
|
||||
}
|
||||
|
||||
size_type max_bucket_count() const BOOST_NOEXCEPT
|
||||
@@ -889,16 +874,15 @@ namespace boost {
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.begin(n);
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return const_local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
local_iterator end(size_type) { return local_iterator(); }
|
||||
|
||||
const_local_iterator end(size_type) const
|
||||
{
|
||||
return const_local_iterator();
|
||||
@@ -906,7 +890,7 @@ namespace boost {
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return const_local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type) const
|
||||
@@ -1026,8 +1010,6 @@ namespace boost {
|
||||
typedef boost::unordered::detail::map<A, K, T, H, P> types;
|
||||
typedef typename types::value_allocator_traits value_allocator_traits;
|
||||
typedef typename types::table table;
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
typedef typename table::link_pointer link_pointer;
|
||||
|
||||
public:
|
||||
typedef typename value_allocator_traits::pointer pointer;
|
||||
@@ -1394,7 +1376,7 @@ namespace boost {
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
return node_type(table_.extract_by_key_impl(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -1437,8 +1419,7 @@ namespace boost {
|
||||
size_type>::type
|
||||
erase(BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
return table_.erase_key_equiv_impl(
|
||||
this->key_eq(), boost::forward<Key>(k));
|
||||
return table_.erase_key_equiv_impl(boost::forward<Key>(k));
|
||||
}
|
||||
|
||||
BOOST_UNORDERED_DEPRECATED("Use erase instead")
|
||||
@@ -1483,9 +1464,7 @@ namespace boost {
|
||||
iterator>::type
|
||||
find(const Key& key)
|
||||
{
|
||||
return iterator(table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), key), key,
|
||||
this->key_eq()));
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -1493,9 +1472,7 @@ namespace boost {
|
||||
const_iterator>::type
|
||||
find(const Key& key) const
|
||||
{
|
||||
return const_iterator(table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), key), key,
|
||||
this->key_eq()));
|
||||
return const_iterator(table_.find(key));
|
||||
}
|
||||
|
||||
template <class CompatibleKey, class CompatibleHash,
|
||||
@@ -1510,9 +1487,7 @@ namespace boost {
|
||||
|
||||
bool contains(key_type const& k) const
|
||||
{
|
||||
return 0 != table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
return table_.find(k) != this->end();
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -1520,9 +1495,7 @@ namespace boost {
|
||||
bool>::type
|
||||
contains(const Key& k) const
|
||||
{
|
||||
return 0 != table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
return table_.find(k) != this->end();
|
||||
}
|
||||
|
||||
size_type count(const key_type&) const;
|
||||
@@ -1532,11 +1505,7 @@ namespace boost {
|
||||
size_type>::type
|
||||
count(const Key& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
|
||||
return n ? table_.group_count(n) : 0;
|
||||
return table_.group_count(k);
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type&);
|
||||
@@ -1548,12 +1517,8 @@ namespace boost {
|
||||
std::pair<iterator, iterator> >::type
|
||||
equal_range(const Key& key)
|
||||
{
|
||||
node_pointer p = table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), key), key,
|
||||
this->key_eq());
|
||||
|
||||
return std::make_pair(
|
||||
iterator(p), iterator(p ? table_.next_group(p) : p));
|
||||
iterator p = table_.find(key);
|
||||
return std::make_pair(p, table_.next_group(key, p));
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -1561,19 +1526,16 @@ namespace boost {
|
||||
std::pair<const_iterator, const_iterator> >::type
|
||||
equal_range(const Key& key) const
|
||||
{
|
||||
node_pointer p = table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), key), key,
|
||||
this->key_eq());
|
||||
|
||||
iterator p = table_.find(key);
|
||||
return std::make_pair(
|
||||
const_iterator(p), const_iterator(p ? table_.next_group(p) : p));
|
||||
const_iterator(p), const_iterator(table_.next_group(key, p)));
|
||||
}
|
||||
|
||||
// bucket interface
|
||||
|
||||
size_type bucket_count() const BOOST_NOEXCEPT
|
||||
{
|
||||
return table_.bucket_count_;
|
||||
return table_.bucket_count();
|
||||
}
|
||||
|
||||
size_type max_bucket_count() const BOOST_NOEXCEPT
|
||||
@@ -1590,12 +1552,12 @@ namespace boost {
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return const_local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
local_iterator end(size_type) { return local_iterator(); }
|
||||
@@ -1607,7 +1569,7 @@ namespace boost {
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return const_local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type) const
|
||||
@@ -1730,7 +1692,7 @@ namespace boost {
|
||||
unordered_map::value_allocator_traits::
|
||||
select_on_container_copy_construction(other.get_allocator()))
|
||||
{
|
||||
if (other.table_.size_) {
|
||||
if (other.size()) {
|
||||
table_.copy_buckets(
|
||||
other.table_, boost::unordered::detail::true_type());
|
||||
}
|
||||
@@ -1894,29 +1856,25 @@ namespace boost {
|
||||
typename unordered_map<K, T, H, P, A>::iterator
|
||||
unordered_map<K, T, H, P, A>::erase(iterator position)
|
||||
{
|
||||
node_pointer node = table::get_node(position);
|
||||
BOOST_ASSERT(node);
|
||||
node_pointer next = table::next_node(node);
|
||||
table_.erase_nodes_unique(node, next);
|
||||
return iterator(next);
|
||||
const_iterator last = position;
|
||||
++last;
|
||||
return table_.erase_nodes_range(position, last);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
typename unordered_map<K, T, H, P, A>::iterator
|
||||
unordered_map<K, T, H, P, A>::erase(const_iterator position)
|
||||
{
|
||||
node_pointer node = table::get_node(position);
|
||||
BOOST_ASSERT(node);
|
||||
node_pointer next = table::next_node(node);
|
||||
table_.erase_nodes_unique(node, next);
|
||||
return iterator(next);
|
||||
const_iterator last = position;
|
||||
++last;
|
||||
return table_.erase_nodes_range(position, last);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
typename unordered_map<K, T, H, P, A>::size_type
|
||||
unordered_map<K, T, H, P, A>::erase(const key_type& k)
|
||||
{
|
||||
return table_.erase_key_unique_impl(this->key_eq(), k);
|
||||
return table_.erase_key_unique_impl(k);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -1924,11 +1882,7 @@ namespace boost {
|
||||
unordered_map<K, T, H, P, A>::erase(
|
||||
const_iterator first, const_iterator last)
|
||||
{
|
||||
node_pointer last_node = table::get_node(last);
|
||||
if (first == last)
|
||||
return iterator(last_node);
|
||||
table_.erase_nodes_unique(table::get_node(first), last_node);
|
||||
return iterator(last_node);
|
||||
return table_.erase_nodes_range(first, last);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -1998,14 +1952,14 @@ namespace boost {
|
||||
typename unordered_map<K, T, H, P, A>::iterator
|
||||
unordered_map<K, T, H, P, A>::find(const key_type& k)
|
||||
{
|
||||
return iterator(table_.find_node(k));
|
||||
return iterator(table_.find(k));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
typename unordered_map<K, T, H, P, A>::const_iterator
|
||||
unordered_map<K, T, H, P, A>::find(const key_type& k) const
|
||||
{
|
||||
return const_iterator(table_.find_node(k));
|
||||
return const_iterator(table_.find(k));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2015,8 +1969,7 @@ namespace boost {
|
||||
unordered_map<K, T, H, P, A>::find(CompatibleKey const& k,
|
||||
CompatibleHash const& hash, CompatiblePredicate const& eq)
|
||||
{
|
||||
return iterator(
|
||||
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
|
||||
return table_.transparent_find(k, hash, eq);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2026,8 +1979,7 @@ namespace boost {
|
||||
unordered_map<K, T, H, P, A>::find(CompatibleKey const& k,
|
||||
CompatibleHash const& hash, CompatiblePredicate const& eq) const
|
||||
{
|
||||
return const_iterator(
|
||||
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
|
||||
return table_.transparent_find(k, hash, eq);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2042,8 +1994,12 @@ namespace boost {
|
||||
typename unordered_map<K, T, H, P, A>::iterator>
|
||||
unordered_map<K, T, H, P, A>::equal_range(const key_type& k)
|
||||
{
|
||||
node_pointer n = table_.find_node(k);
|
||||
return std::make_pair(iterator(n), iterator(n ? table::next_node(n) : n));
|
||||
iterator first = table_.find(k);
|
||||
iterator second = first;
|
||||
if (second != this->end()) {
|
||||
++second;
|
||||
}
|
||||
return std::make_pair(first, second);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2051,9 +2007,12 @@ namespace boost {
|
||||
typename unordered_map<K, T, H, P, A>::const_iterator>
|
||||
unordered_map<K, T, H, P, A>::equal_range(const key_type& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node(k);
|
||||
return std::make_pair(
|
||||
const_iterator(n), const_iterator(n ? table::next_node(n) : n));
|
||||
iterator first = table_.find(k);
|
||||
iterator second = first;
|
||||
if (second != this->end()) {
|
||||
++second;
|
||||
}
|
||||
return std::make_pair(const_iterator(first), const_iterator(second));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2074,10 +2033,12 @@ namespace boost {
|
||||
typename unordered_map<K, T, H, P, A>::mapped_type&
|
||||
unordered_map<K, T, H, P, A>::at(const key_type& k)
|
||||
{
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
|
||||
if (table_.size_) {
|
||||
node_pointer n = table_.find_node(k);
|
||||
if (n)
|
||||
return n->value().second;
|
||||
node_pointer p = table_.find_node(k);
|
||||
if (p)
|
||||
return p->value().second;
|
||||
}
|
||||
|
||||
boost::throw_exception(
|
||||
@@ -2088,10 +2049,12 @@ namespace boost {
|
||||
typename unordered_map<K, T, H, P, A>::mapped_type const&
|
||||
unordered_map<K, T, H, P, A>::at(const key_type& k) const
|
||||
{
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
|
||||
if (table_.size_) {
|
||||
node_pointer n = table_.find_node(k);
|
||||
if (n)
|
||||
return n->value().second;
|
||||
node_pointer p = table_.find_node(k);
|
||||
if (p)
|
||||
return p->value().second;
|
||||
}
|
||||
|
||||
boost::throw_exception(
|
||||
@@ -2110,9 +2073,9 @@ namespace boost {
|
||||
template <class K, class T, class H, class P, class A>
|
||||
float unordered_map<K, T, H, P, A>::load_factor() const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(table_.bucket_count_ != 0);
|
||||
BOOST_ASSERT(table_.bucket_count() != 0);
|
||||
return static_cast<float>(table_.size_) /
|
||||
static_cast<float>(table_.bucket_count_);
|
||||
static_cast<float>(table_.bucket_count());
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2130,8 +2093,7 @@ namespace boost {
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void unordered_map<K, T, H, P, A>::reserve(size_type n)
|
||||
{
|
||||
table_.rehash(static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>(n) / table_.mlf_)));
|
||||
table_.reserve(n);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2377,22 +2339,20 @@ namespace boost {
|
||||
typename unordered_multimap<K, T, H, P, A>::iterator
|
||||
unordered_multimap<K, T, H, P, A>::erase(iterator position)
|
||||
{
|
||||
node_pointer node = table::get_node(position);
|
||||
BOOST_ASSERT(node);
|
||||
node_pointer next = table::next_node(node);
|
||||
table_.erase_nodes_equiv(node, next);
|
||||
return iterator(next);
|
||||
BOOST_ASSERT(position != this->end());
|
||||
iterator next = position;
|
||||
++next;
|
||||
return table_.erase_nodes_range(position, next);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
typename unordered_multimap<K, T, H, P, A>::iterator
|
||||
unordered_multimap<K, T, H, P, A>::erase(const_iterator position)
|
||||
{
|
||||
node_pointer node = table::get_node(position);
|
||||
BOOST_ASSERT(node);
|
||||
node_pointer next = table::next_node(node);
|
||||
table_.erase_nodes_equiv(node, next);
|
||||
return iterator(next);
|
||||
BOOST_ASSERT(position != this->end());
|
||||
const_iterator next = position;
|
||||
++next;
|
||||
return table_.erase_nodes_range(position, next);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2407,11 +2367,7 @@ namespace boost {
|
||||
unordered_multimap<K, T, H, P, A>::erase(
|
||||
const_iterator first, const_iterator last)
|
||||
{
|
||||
node_pointer last_node = table::get_node(last);
|
||||
if (first == last)
|
||||
return iterator(last_node);
|
||||
table_.erase_nodes_equiv(table::get_node(first), last_node);
|
||||
return iterator(last_node);
|
||||
return table_.erase_nodes_range(first, last);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2489,14 +2445,14 @@ namespace boost {
|
||||
typename unordered_multimap<K, T, H, P, A>::iterator
|
||||
unordered_multimap<K, T, H, P, A>::find(const key_type& k)
|
||||
{
|
||||
return iterator(table_.find_node(k));
|
||||
return iterator(table_.find(k));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
typename unordered_multimap<K, T, H, P, A>::const_iterator
|
||||
unordered_multimap<K, T, H, P, A>::find(const key_type& k) const
|
||||
{
|
||||
return const_iterator(table_.find_node(k));
|
||||
return const_iterator(table_.find(k));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2506,8 +2462,7 @@ namespace boost {
|
||||
unordered_multimap<K, T, H, P, A>::find(CompatibleKey const& k,
|
||||
CompatibleHash const& hash, CompatiblePredicate const& eq)
|
||||
{
|
||||
return iterator(
|
||||
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
|
||||
return table_.transparent_find(k, hash, eq);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2525,8 +2480,7 @@ namespace boost {
|
||||
typename unordered_multimap<K, T, H, P, A>::size_type
|
||||
unordered_multimap<K, T, H, P, A>::count(const key_type& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node(k);
|
||||
return n ? table_.group_count(n) : 0;
|
||||
return table_.group_count(k);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2534,9 +2488,8 @@ namespace boost {
|
||||
typename unordered_multimap<K, T, H, P, A>::iterator>
|
||||
unordered_multimap<K, T, H, P, A>::equal_range(const key_type& k)
|
||||
{
|
||||
node_pointer n = table_.find_node(k);
|
||||
return std::make_pair(
|
||||
iterator(n), iterator(n ? table_.next_group(n) : n));
|
||||
iterator n = table_.find(k);
|
||||
return std::make_pair(n, (n == end() ? n : table_.next_group(k, n)));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2544,9 +2497,9 @@ namespace boost {
|
||||
typename unordered_multimap<K, T, H, P, A>::const_iterator>
|
||||
unordered_multimap<K, T, H, P, A>::equal_range(const key_type& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node(k);
|
||||
return std::make_pair(
|
||||
const_iterator(n), const_iterator(n ? table_.next_group(n) : n));
|
||||
iterator n = table_.find(k);
|
||||
return std::make_pair(const_iterator(n),
|
||||
const_iterator(n == end() ? n : table_.next_group(k, n)));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2561,9 +2514,9 @@ namespace boost {
|
||||
template <class K, class T, class H, class P, class A>
|
||||
float unordered_multimap<K, T, H, P, A>::load_factor() const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(table_.bucket_count_ != 0);
|
||||
BOOST_ASSERT(table_.bucket_count() != 0);
|
||||
return static_cast<float>(table_.size_) /
|
||||
static_cast<float>(table_.bucket_count_);
|
||||
static_cast<float>(table_.bucket_count());
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2582,8 +2535,7 @@ namespace boost {
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void unordered_multimap<K, T, H, P, A>::reserve(size_type n)
|
||||
{
|
||||
table_.rehash(static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>(n) / table_.mlf_)));
|
||||
table_.reserve(n);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
@@ -2643,16 +2595,14 @@ namespace boost {
|
||||
template <class K2, class T2, class H2, class P2, class A2>
|
||||
friend class boost::unordered::unordered_multimap;
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A,
|
||||
std::pair<K const, T> >::type value_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
typedef typename boost::allocator_rebind<A, std::pair<K const, T> >::type
|
||||
value_allocator;
|
||||
|
||||
typedef N node;
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, node>::type
|
||||
node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<node_allocator>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
typedef typename boost::allocator_rebind<A, node>::type node_allocator;
|
||||
|
||||
typedef
|
||||
typename boost::allocator_pointer<node_allocator>::type node_pointer;
|
||||
|
||||
public:
|
||||
typedef K key_type;
|
||||
@@ -2681,8 +2631,8 @@ namespace boost {
|
||||
}
|
||||
|
||||
node_handle_map(BOOST_RV_REF(node_handle_map) n) BOOST_NOEXCEPT
|
||||
: ptr_(n.ptr_),
|
||||
alloc_(boost::move(n.alloc_))
|
||||
: ptr_(n.ptr_),
|
||||
alloc_(boost::move(n.alloc_))
|
||||
{
|
||||
n.ptr_ = node_pointer();
|
||||
}
|
||||
@@ -2690,8 +2640,8 @@ namespace boost {
|
||||
node_handle_map& operator=(BOOST_RV_REF(node_handle_map) n)
|
||||
{
|
||||
BOOST_ASSERT(!alloc_.has_value() ||
|
||||
value_allocator_traits::
|
||||
propagate_on_container_move_assignment::value ||
|
||||
boost::allocator_propagate_on_container_move_assignment<
|
||||
value_allocator>::type::value ||
|
||||
(n.alloc_.has_value() && alloc_ == n.alloc_));
|
||||
|
||||
if (ptr_) {
|
||||
@@ -2702,8 +2652,8 @@ namespace boost {
|
||||
}
|
||||
|
||||
if (!alloc_.has_value() ||
|
||||
value_allocator_traits::propagate_on_container_move_assignment::
|
||||
value) {
|
||||
boost::allocator_propagate_on_container_move_assignment<
|
||||
value_allocator>::type::value) {
|
||||
alloc_ = boost::move(n.alloc_);
|
||||
}
|
||||
ptr_ = n.ptr_;
|
||||
@@ -2731,14 +2681,17 @@ namespace boost {
|
||||
}
|
||||
|
||||
void swap(node_handle_map& n) BOOST_NOEXCEPT_IF(
|
||||
value_allocator_traits::propagate_on_container_swap::value ||
|
||||
value_allocator_traits::is_always_equal::value)
|
||||
boost::allocator_propagate_on_container_swap<
|
||||
value_allocator>::type::value ||
|
||||
boost::allocator_is_always_equal<value_allocator>::type::value)
|
||||
{
|
||||
BOOST_ASSERT(
|
||||
!alloc_.has_value() || !n.alloc_.has_value() ||
|
||||
value_allocator_traits::propagate_on_container_swap::value ||
|
||||
alloc_ == n.alloc_);
|
||||
if (value_allocator_traits::propagate_on_container_swap::value ||
|
||||
|
||||
BOOST_ASSERT(!alloc_.has_value() || !n.alloc_.has_value() ||
|
||||
boost::allocator_propagate_on_container_swap<
|
||||
value_allocator>::type::value ||
|
||||
alloc_ == n.alloc_);
|
||||
if (boost::allocator_propagate_on_container_swap<
|
||||
value_allocator>::type::value ||
|
||||
!alloc_.has_value() || !n.alloc_.has_value()) {
|
||||
boost::swap(alloc_, n.alloc_);
|
||||
}
|
||||
@@ -2753,25 +2706,25 @@ namespace boost {
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
template <class N, class K, class T, class A> struct insert_return_type_map
|
||||
template <class Iter, class NodeType> struct insert_return_type_map
|
||||
{
|
||||
private:
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_map)
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A,
|
||||
std::pair<K const, T> >::type value_allocator;
|
||||
typedef N node_;
|
||||
// typedef typename boost::allocator_rebind<A,
|
||||
// std::pair<K const, T> >::type value_allocator;
|
||||
// typedef N node_;
|
||||
|
||||
public:
|
||||
Iter position;
|
||||
bool inserted;
|
||||
boost::unordered::iterator_detail::iterator<node_> position;
|
||||
boost::unordered::node_handle_map<N, K, T, A> node;
|
||||
NodeType node;
|
||||
|
||||
insert_return_type_map() : inserted(false), position(), node() {}
|
||||
insert_return_type_map() : position(), inserted(false), node() {}
|
||||
|
||||
insert_return_type_map(BOOST_RV_REF(insert_return_type_map)
|
||||
x) BOOST_NOEXCEPT : inserted(x.inserted),
|
||||
position(x.position),
|
||||
x) BOOST_NOEXCEPT : position(x.position),
|
||||
inserted(x.inserted),
|
||||
node(boost::move(x.node))
|
||||
{
|
||||
}
|
||||
@@ -2785,9 +2738,9 @@ namespace boost {
|
||||
}
|
||||
};
|
||||
|
||||
template <class N, class K, class T, class A>
|
||||
void swap(insert_return_type_map<N, K, T, A>& x,
|
||||
insert_return_type_map<N, K, T, A>& y)
|
||||
template <class Iter, class NodeType>
|
||||
void swap(insert_return_type_map<Iter, NodeType>& x,
|
||||
insert_return_type_map<Iter, NodeType>& y)
|
||||
{
|
||||
boost::swap(x.node, y.node);
|
||||
boost::swap(x.inserted, y.inserted);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright (C) 2008-2011 Daniel James.
|
||||
// Copyright (C) 2022 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)
|
||||
|
||||
@@ -59,7 +60,7 @@ namespace boost {
|
||||
unordered_multimap<K, T, H, P, A>& c, Predicate pred);
|
||||
|
||||
template <class N, class K, class T, class A> class node_handle_map;
|
||||
template <class N, class K, class T, class A> struct insert_return_type_map;
|
||||
template <class Iter, class NodeType> struct insert_return_type_map;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_map;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2011 Daniel James.
|
||||
// Copyright (C) 2022 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)
|
||||
|
||||
@@ -55,8 +56,6 @@ namespace boost {
|
||||
typedef boost::unordered::detail::set<A, T, H, P> types;
|
||||
typedef typename types::value_allocator_traits value_allocator_traits;
|
||||
typedef typename types::table table;
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
typedef typename table::link_pointer link_pointer;
|
||||
|
||||
public:
|
||||
typedef typename value_allocator_traits::pointer pointer;
|
||||
@@ -68,9 +67,9 @@ namespace boost {
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename table::c_iterator iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::cl_iterator local_iterator;
|
||||
typedef typename table::cl_iterator const_local_iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
typedef typename types::insert_return_type insert_return_type;
|
||||
@@ -411,7 +410,7 @@ namespace boost {
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
return node_type(table_.extract_by_key_impl(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -455,8 +454,7 @@ namespace boost {
|
||||
size_type>::type
|
||||
erase(BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
return table_.erase_key_unique_impl(
|
||||
this->key_eq(), boost::forward<Key>(k));
|
||||
return table_.erase_key_unique_impl(boost::forward<Key>(k));
|
||||
}
|
||||
|
||||
BOOST_UNORDERED_DEPRECATED("Use erase instead")
|
||||
@@ -500,9 +498,7 @@ namespace boost {
|
||||
const_iterator>::type
|
||||
find(const Key& k) const
|
||||
{
|
||||
return const_iterator(table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq()));
|
||||
return const_iterator(table_.find(k));
|
||||
}
|
||||
|
||||
template <class CompatibleKey, class CompatibleHash,
|
||||
@@ -512,9 +508,7 @@ namespace boost {
|
||||
|
||||
bool contains(key_type const& k) const
|
||||
{
|
||||
return 0 != table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
return table_.find(k) != this->end();
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -522,9 +516,7 @@ namespace boost {
|
||||
bool>::type
|
||||
contains(const Key& k) const
|
||||
{
|
||||
return 0 != table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
return table_.find(k) != this->end();
|
||||
}
|
||||
|
||||
size_type count(const key_type&) const;
|
||||
@@ -534,11 +526,7 @@ namespace boost {
|
||||
size_type>::type
|
||||
count(const Key& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
|
||||
return n ? 1 : 0;
|
||||
return table_.find(k) != this->end() ? 1 : 0;
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(
|
||||
@@ -549,19 +537,20 @@ namespace boost {
|
||||
std::pair<const_iterator, const_iterator> >::type
|
||||
equal_range(Key const& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
iterator n = table_.find(k);
|
||||
iterator m = n;
|
||||
if (m != this->end()) {
|
||||
++m;
|
||||
}
|
||||
|
||||
return std::make_pair(
|
||||
const_iterator(n), const_iterator(n ? table::next_node(n) : n));
|
||||
return std::make_pair(const_iterator(n), const_iterator(m));
|
||||
}
|
||||
|
||||
// bucket interface
|
||||
|
||||
size_type bucket_count() const BOOST_NOEXCEPT
|
||||
{
|
||||
return table_.bucket_count_;
|
||||
return table_.bucket_count();
|
||||
}
|
||||
|
||||
size_type max_bucket_count() const BOOST_NOEXCEPT
|
||||
@@ -578,12 +567,12 @@ namespace boost {
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return const_local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
local_iterator end(size_type) { return local_iterator(); }
|
||||
@@ -595,7 +584,7 @@ namespace boost {
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return const_local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type) const
|
||||
@@ -684,8 +673,6 @@ namespace boost {
|
||||
typedef boost::unordered::detail::set<A, T, H, P> types;
|
||||
typedef typename types::value_allocator_traits value_allocator_traits;
|
||||
typedef typename types::table table;
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
typedef typename table::link_pointer link_pointer;
|
||||
|
||||
public:
|
||||
typedef typename value_allocator_traits::pointer pointer;
|
||||
@@ -697,9 +684,9 @@ namespace boost {
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename table::c_iterator iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::cl_iterator local_iterator;
|
||||
typedef typename table::cl_iterator const_local_iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
|
||||
@@ -1035,7 +1022,7 @@ namespace boost {
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
return node_type(table_.extract_by_key_impl(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -1076,7 +1063,7 @@ namespace boost {
|
||||
size_type>::type
|
||||
erase(const Key& k)
|
||||
{
|
||||
return table_.erase_key_equiv_impl(this->key_eq(), k);
|
||||
return table_.erase_key_equiv_impl(k);
|
||||
}
|
||||
|
||||
iterator erase(const_iterator, const_iterator);
|
||||
@@ -1121,9 +1108,7 @@ namespace boost {
|
||||
const_iterator>::type
|
||||
find(const Key& k) const
|
||||
{
|
||||
return const_iterator(table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq()));
|
||||
return table_.find(k);
|
||||
}
|
||||
|
||||
template <class CompatibleKey, class CompatibleHash,
|
||||
@@ -1133,9 +1118,7 @@ namespace boost {
|
||||
|
||||
bool contains(const key_type& k) const
|
||||
{
|
||||
return 0 != table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
return table_.find(k) != this->end();
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
@@ -1143,9 +1126,7 @@ namespace boost {
|
||||
bool>::type
|
||||
contains(const Key& k) const
|
||||
{
|
||||
return 0 != table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
return table_.find(k) != this->end();
|
||||
}
|
||||
|
||||
size_type count(const key_type&) const;
|
||||
@@ -1155,11 +1136,7 @@ namespace boost {
|
||||
size_type>::type
|
||||
count(const Key& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
|
||||
return n ? table_.group_count(n) : 0;
|
||||
return table_.group_count(k);
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(
|
||||
@@ -1170,19 +1147,16 @@ namespace boost {
|
||||
std::pair<const_iterator, const_iterator> >::type
|
||||
equal_range(const Key& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node_impl(
|
||||
table::policy::apply_hash(this->hash_function(), k), k,
|
||||
this->key_eq());
|
||||
|
||||
return std::make_pair(
|
||||
const_iterator(n), const_iterator(n ? table_.next_group(n) : n));
|
||||
iterator first = table_.find(k);
|
||||
iterator last = table_.next_group(k, first);
|
||||
return std::make_pair(const_iterator(first), const_iterator(last));
|
||||
}
|
||||
|
||||
// bucket interface
|
||||
|
||||
size_type bucket_count() const BOOST_NOEXCEPT
|
||||
{
|
||||
return table_.bucket_count_;
|
||||
return table_.bucket_count();
|
||||
}
|
||||
|
||||
size_type max_bucket_count() const BOOST_NOEXCEPT
|
||||
@@ -1199,12 +1173,12 @@ namespace boost {
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return const_local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
local_iterator end(size_type) { return local_iterator(); }
|
||||
@@ -1216,7 +1190,7 @@ namespace boost {
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(table_.begin(n), n, table_.bucket_count_);
|
||||
return const_local_iterator(table_.begin(n));
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type) const
|
||||
@@ -1319,7 +1293,7 @@ namespace boost {
|
||||
unordered_set::value_allocator_traits::
|
||||
select_on_container_copy_construction(other.get_allocator()))
|
||||
{
|
||||
if (other.table_.size_) {
|
||||
if (other.size()) {
|
||||
table_.copy_buckets(
|
||||
other.table_, boost::unordered::detail::true_type());
|
||||
}
|
||||
@@ -1483,29 +1457,23 @@ namespace boost {
|
||||
typename unordered_set<T, H, P, A>::iterator
|
||||
unordered_set<T, H, P, A>::erase(const_iterator position)
|
||||
{
|
||||
node_pointer node = table::get_node(position);
|
||||
BOOST_ASSERT(node);
|
||||
node_pointer next = table::next_node(node);
|
||||
table_.erase_nodes_unique(node, next);
|
||||
return iterator(next);
|
||||
const_iterator last = position;
|
||||
++last;
|
||||
return table_.erase_nodes_range(position, last);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
typename unordered_set<T, H, P, A>::size_type
|
||||
unordered_set<T, H, P, A>::erase(const key_type& k)
|
||||
{
|
||||
return table_.erase_key_unique_impl(this->key_eq(), k);
|
||||
return table_.erase_key_unique_impl(k);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
typename unordered_set<T, H, P, A>::iterator
|
||||
unordered_set<T, H, P, A>::erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
node_pointer last_node = table::get_node(last);
|
||||
if (first == last)
|
||||
return iterator(last_node);
|
||||
table_.erase_nodes_unique(table::get_node(first), last_node);
|
||||
return iterator(last_node);
|
||||
return table_.erase_nodes_range(first, last);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -1575,7 +1543,7 @@ namespace boost {
|
||||
typename unordered_set<T, H, P, A>::const_iterator
|
||||
unordered_set<T, H, P, A>::find(const key_type& k) const
|
||||
{
|
||||
return const_iterator(table_.find_node(k));
|
||||
return const_iterator(table_.find(k));
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -1585,8 +1553,7 @@ namespace boost {
|
||||
unordered_set<T, H, P, A>::find(CompatibleKey const& k,
|
||||
CompatibleHash const& hash, CompatiblePredicate const& eq) const
|
||||
{
|
||||
return const_iterator(
|
||||
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
|
||||
return table_.transparent_find(k, hash, eq);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -1601,9 +1568,12 @@ namespace boost {
|
||||
typename unordered_set<T, H, P, A>::const_iterator>
|
||||
unordered_set<T, H, P, A>::equal_range(const key_type& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node(k);
|
||||
return std::make_pair(
|
||||
const_iterator(n), const_iterator(n ? table::next_node(n) : n));
|
||||
iterator first = table_.find(k);
|
||||
iterator second = first;
|
||||
if (second != this->end()) {
|
||||
++second;
|
||||
}
|
||||
return std::make_pair(first, second);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -1618,9 +1588,9 @@ namespace boost {
|
||||
template <class T, class H, class P, class A>
|
||||
float unordered_set<T, H, P, A>::load_factor() const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(table_.bucket_count_ != 0);
|
||||
BOOST_ASSERT(table_.bucket_count() != 0);
|
||||
return static_cast<float>(table_.size_) /
|
||||
static_cast<float>(table_.bucket_count_);
|
||||
static_cast<float>(table_.bucket_count());
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -1638,8 +1608,7 @@ namespace boost {
|
||||
template <class T, class H, class P, class A>
|
||||
void unordered_set<T, H, P, A>::reserve(size_type n)
|
||||
{
|
||||
table_.rehash(static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>(n) / table_.mlf_)));
|
||||
table_.reserve(n);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -1883,11 +1852,11 @@ namespace boost {
|
||||
typename unordered_multiset<T, H, P, A>::iterator
|
||||
unordered_multiset<T, H, P, A>::erase(const_iterator position)
|
||||
{
|
||||
node_pointer node = table::get_node(position);
|
||||
BOOST_ASSERT(node);
|
||||
node_pointer next = table::next_node(node);
|
||||
table_.erase_nodes_equiv(node, next);
|
||||
return iterator(next);
|
||||
BOOST_ASSERT(position != this->end());
|
||||
iterator next = position;
|
||||
++next;
|
||||
table_.erase_nodes_range(position, next);
|
||||
return next;
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -1902,11 +1871,7 @@ namespace boost {
|
||||
unordered_multiset<T, H, P, A>::erase(
|
||||
const_iterator first, const_iterator last)
|
||||
{
|
||||
node_pointer last_node = table::get_node(last);
|
||||
if (first == last)
|
||||
return iterator(last_node);
|
||||
table_.erase_nodes_equiv(table::get_node(first), last_node);
|
||||
return iterator(last_node);
|
||||
return table_.erase_nodes_range(first, last);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -1984,7 +1949,7 @@ namespace boost {
|
||||
typename unordered_multiset<T, H, P, A>::const_iterator
|
||||
unordered_multiset<T, H, P, A>::find(const key_type& k) const
|
||||
{
|
||||
return const_iterator(table_.find_node(k));
|
||||
return const_iterator(table_.find(k));
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -1994,16 +1959,14 @@ namespace boost {
|
||||
unordered_multiset<T, H, P, A>::find(CompatibleKey const& k,
|
||||
CompatibleHash const& hash, CompatiblePredicate const& eq) const
|
||||
{
|
||||
return const_iterator(
|
||||
table_.find_node_impl(table::policy::apply_hash(hash, k), k, eq));
|
||||
return table_.transparent_find(k, hash, eq);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
typename unordered_multiset<T, H, P, A>::size_type
|
||||
unordered_multiset<T, H, P, A>::count(const key_type& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node(k);
|
||||
return n ? table_.group_count(n) : 0;
|
||||
return table_.group_count(k);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -2011,9 +1974,9 @@ namespace boost {
|
||||
typename unordered_multiset<T, H, P, A>::const_iterator>
|
||||
unordered_multiset<T, H, P, A>::equal_range(const key_type& k) const
|
||||
{
|
||||
node_pointer n = table_.find_node(k);
|
||||
return std::make_pair(
|
||||
const_iterator(n), const_iterator(n ? table_.next_group(n) : n));
|
||||
iterator n = table_.find(k);
|
||||
return std::make_pair(const_iterator(n),
|
||||
const_iterator(n == end() ? n : table_.next_group(k, n)));
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -2028,9 +1991,9 @@ namespace boost {
|
||||
template <class T, class H, class P, class A>
|
||||
float unordered_multiset<T, H, P, A>::load_factor() const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(table_.bucket_count_ != 0);
|
||||
BOOST_ASSERT(table_.bucket_count() != 0);
|
||||
return static_cast<float>(table_.size_) /
|
||||
static_cast<float>(table_.bucket_count_);
|
||||
static_cast<float>(table_.bucket_count());
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -2048,8 +2011,7 @@ namespace boost {
|
||||
template <class T, class H, class P, class A>
|
||||
void unordered_multiset<T, H, P, A>::reserve(size_type n)
|
||||
{
|
||||
table_.rehash(static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>(n) / table_.mlf_)));
|
||||
table_.reserve(n);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
@@ -2217,25 +2179,25 @@ namespace boost {
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
template <typename N, typename T, typename A> struct insert_return_type_set
|
||||
template <class Iter, class NodeType> struct insert_return_type_set
|
||||
{
|
||||
private:
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_set)
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, T>::type
|
||||
value_allocator;
|
||||
typedef N node_;
|
||||
// typedef typename boost::unordered::detail::rebind_wrap<A, T>::type
|
||||
// value_allocator;
|
||||
// typedef N node_;
|
||||
|
||||
public:
|
||||
Iter position;
|
||||
bool inserted;
|
||||
boost::unordered::iterator_detail::c_iterator<node_> position;
|
||||
boost::unordered::node_handle_set<N, T, A> node;
|
||||
NodeType node;
|
||||
|
||||
insert_return_type_set() : inserted(false), position(), node() {}
|
||||
insert_return_type_set() : position(), inserted(false), node() {}
|
||||
|
||||
insert_return_type_set(BOOST_RV_REF(insert_return_type_set)
|
||||
x) BOOST_NOEXCEPT : inserted(x.inserted),
|
||||
position(x.position),
|
||||
x) BOOST_NOEXCEPT : position(x.position),
|
||||
inserted(x.inserted),
|
||||
node(boost::move(x.node))
|
||||
{
|
||||
}
|
||||
@@ -2249,9 +2211,9 @@ namespace boost {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename N, typename T, typename A>
|
||||
template <class Iter, class NodeType>
|
||||
void swap(
|
||||
insert_return_type_set<N, T, A>& x, insert_return_type_set<N, T, A>& y)
|
||||
insert_return_type_set<Iter, NodeType>& x, insert_return_type_set<Iter, NodeType>& y)
|
||||
{
|
||||
boost::swap(x.node, y.node);
|
||||
boost::swap(x.inserted, y.inserted);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright (C) 2008-2011 Daniel James.
|
||||
// Copyright (C) 2022 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)
|
||||
|
||||
@@ -57,7 +58,7 @@ namespace boost {
|
||||
unordered_multiset<K, H, P, A>& c, Predicate pred);
|
||||
|
||||
template <class N, class T, class A> class node_handle_set;
|
||||
template <class N, class T, class A> struct insert_return_type_set;
|
||||
template <class Iter, class NodeType> struct insert_return_type_set;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_set;
|
||||
|
||||
+2
-2
@@ -70,13 +70,13 @@ test-suite unordered
|
||||
[ run unordered/rehash_tests.cpp ]
|
||||
[ run unordered/equality_tests.cpp ]
|
||||
[ run unordered/swap_tests.cpp ]
|
||||
[ run unordered/detail_tests.cpp ]
|
||||
# [ run unordered/detail_tests.cpp ]
|
||||
[ run unordered/deduction_tests.cpp ]
|
||||
[ run unordered/scoped_allocator.cpp : : : <toolset>msvc-14.0:<build>no ]
|
||||
[ run unordered/transparent_tests.cpp ]
|
||||
[ run unordered/reserve_tests.cpp ]
|
||||
[ run unordered/contains_tests.cpp ]
|
||||
[ run unordered/mix_policy.cpp ]
|
||||
# [ run unordered/mix_policy.cpp ]
|
||||
[ run unordered/erase_if.cpp ]
|
||||
[ run unordered/scary_tests.cpp ]
|
||||
|
||||
|
||||
Reference in new issue
Block a user