update boost
This commit is contained in:
849
linx64/include/boost/unordered/detail/fca.hpp
Normal file
849
linx64/include/boost/unordered/detail/fca.hpp
Normal file
@@ -0,0 +1,849 @@
|
||||
// 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/unordered/detail/prime_fmod.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>
|
||||
#include <boost/move/core.hpp>
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/swap.hpp>
|
||||
#include <boost/type_traits/aligned_storage.hpp>
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
|
||||
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:
|
||||
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 Bucket value_type;
|
||||
typedef typename boost::pointer_traits<bucket_pointer>::difference_type
|
||||
difference_type;
|
||||
typedef Bucket& reference;
|
||||
typedef Bucket* pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
bucket_pointer p;
|
||||
bucket_group_pointer pbg;
|
||||
|
||||
public:
|
||||
grouped_bucket_iterator() : p(), pbg() {}
|
||||
|
||||
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
|
||||
pointer operator->() const BOOST_NOEXCEPT
|
||||
{
|
||||
return boost::to_address(p);
|
||||
}
|
||||
|
||||
grouped_bucket_iterator& operator++() BOOST_NOEXCEPT
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
grouped_bucket_iterator operator++(int) BOOST_NOEXCEPT
|
||||
{
|
||||
grouped_bucket_iterator old = *this;
|
||||
increment();
|
||||
return old;
|
||||
}
|
||||
|
||||
bool operator==(
|
||||
grouped_bucket_iterator const& other) const BOOST_NOEXCEPT
|
||||
{
|
||||
return equal(other);
|
||||
}
|
||||
|
||||
bool operator!=(
|
||||
grouped_bucket_iterator const& other) const BOOST_NOEXCEPT
|
||||
{
|
||||
return !equal(other);
|
||||
}
|
||||
|
||||
private:
|
||||
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
|
||||
{
|
||||
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() {}
|
||||
|
||||
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
|
||||
|
||||
pointer operator->() const BOOST_NOEXCEPT
|
||||
{
|
||||
return boost::to_address(p);
|
||||
}
|
||||
|
||||
grouped_local_bucket_iterator& operator++() BOOST_NOEXCEPT
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
grouped_local_bucket_iterator operator++(int) BOOST_NOEXCEPT
|
||||
{
|
||||
grouped_local_bucket_iterator old = *this;
|
||||
increment();
|
||||
return old;
|
||||
}
|
||||
|
||||
bool operator==(
|
||||
grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
|
||||
{
|
||||
return equal(other);
|
||||
}
|
||||
|
||||
bool operator!=(
|
||||
grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
|
||||
{
|
||||
return !equal(other);
|
||||
}
|
||||
|
||||
private:
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
reference operator*() const BOOST_NOEXCEPT { return dereference(); }
|
||||
|
||||
pointer operator->() const BOOST_NOEXCEPT
|
||||
{
|
||||
return boost::to_address(p);
|
||||
}
|
||||
|
||||
const_grouped_local_bucket_iterator& operator++() BOOST_NOEXCEPT
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_grouped_local_bucket_iterator operator++(int) BOOST_NOEXCEPT
|
||||
{
|
||||
const_grouped_local_bucket_iterator old = *this;
|
||||
increment();
|
||||
return old;
|
||||
}
|
||||
|
||||
bool operator==(
|
||||
const_grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
|
||||
{
|
||||
return equal(other);
|
||||
}
|
||||
|
||||
bool operator!=(
|
||||
const_grouped_local_bucket_iterator const& other) const BOOST_NOEXCEPT
|
||||
{
|
||||
return !equal(other);
|
||||
}
|
||||
|
||||
private:
|
||||
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:
|
||||
static std::size_t bucket_count_for(std::size_t num_buckets)
|
||||
{
|
||||
if (num_buckets == 0) {
|
||||
return 0;
|
||||
}
|
||||
return size_policy::size(size_policy::size_index(num_buckets));
|
||||
}
|
||||
|
||||
grouped_bucket_array()
|
||||
: empty_value<node_allocator_type>(
|
||||
empty_init_t(), node_allocator_type()),
|
||||
size_index_(0), size_(0), buckets(), groups()
|
||||
{
|
||||
}
|
||||
|
||||
grouped_bucket_array(size_type n, const Allocator& al)
|
||||
: empty_value<node_allocator_type>(empty_init_t(), al),
|
||||
size_index_(0),
|
||||
size_(0), buckets(), groups()
|
||||
{
|
||||
if (n == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_index_ = size_policy::size_index(n);
|
||||
size_ = size_policy::size(size_index_);
|
||||
|
||||
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 size_ == 0 ? end() : ++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
|
||||
{
|
||||
if (size_ == 0) {
|
||||
return this->end(n);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (size_ > 0) {
|
||||
std::size_t const N = group::N;
|
||||
|
||||
iterator pbg(buckets + static_cast<difference_type>(n),
|
||||
groups + static_cast<difference_type>(n / N));
|
||||
|
||||
return pbg;
|
||||
} else {
|
||||
return this->end();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
1324
linx64/include/boost/unordered/detail/foa/concurrent_table.hpp
Normal file
1324
linx64/include/boost/unordered/detail/foa/concurrent_table.hpp
Normal file
File diff suppressed because it is too large
Load Diff
2119
linx64/include/boost/unordered/detail/foa/core.hpp
Normal file
2119
linx64/include/boost/unordered/detail/foa/core.hpp
Normal file
File diff suppressed because it is too large
Load Diff
60
linx64/include/boost/unordered/detail/foa/element_type.hpp
Normal file
60
linx64/include/boost/unordered/detail/foa/element_type.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/* Copyright 2023 Christian Mazakas.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_ELEMENT_TYPE_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_ELEMENT_TYPE_HPP
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
namespace foa{
|
||||
|
||||
template<class T>
|
||||
struct element_type
|
||||
{
|
||||
using value_type=T;
|
||||
value_type* p;
|
||||
|
||||
/*
|
||||
* we use a deleted copy constructor here so the type is no longer
|
||||
* trivially copy-constructible which inhibits our memcpy
|
||||
* optimizations when copying the tables
|
||||
*/
|
||||
element_type() = default;
|
||||
element_type(value_type* p_):p(p_){}
|
||||
element_type(element_type const&) = delete;
|
||||
element_type(element_type&& rhs) noexcept
|
||||
{
|
||||
p = rhs.p;
|
||||
rhs.p = nullptr;
|
||||
}
|
||||
|
||||
element_type& operator=(element_type const&)=delete;
|
||||
element_type& operator=(element_type&& rhs)noexcept
|
||||
{
|
||||
if (this!=&rhs){
|
||||
p=rhs.p;
|
||||
rhs.p=nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(element_type& rhs)noexcept
|
||||
{
|
||||
auto tmp=p;
|
||||
p=rhs.p;
|
||||
rhs.p=tmp;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_FOA_ELEMENT_TYPE_HPP
|
||||
73
linx64/include/boost/unordered/detail/foa/flat_map_types.hpp
Normal file
73
linx64/include/boost/unordered/detail/foa/flat_map_types.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (C) 2023 Christian Mazakas
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP
|
||||
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
namespace foa {
|
||||
template <class Key, class T> struct flat_map_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using raw_key_type = typename std::remove_const<Key>::type;
|
||||
using raw_mapped_type = typename std::remove_const<T>::type;
|
||||
|
||||
using init_type = std::pair<raw_key_type, raw_mapped_type>;
|
||||
using moved_type = std::pair<raw_key_type&&, raw_mapped_type&&>;
|
||||
using value_type = std::pair<Key const, T>;
|
||||
|
||||
using element_type = value_type;
|
||||
|
||||
static value_type& value_from(element_type& x) { return x; }
|
||||
|
||||
template <class K, class V>
|
||||
static raw_key_type const& extract(std::pair<K, V> const& kv)
|
||||
{
|
||||
return kv.first;
|
||||
}
|
||||
|
||||
static moved_type move(init_type& x)
|
||||
{
|
||||
return {std::move(x.first), std::move(x.second)};
|
||||
}
|
||||
|
||||
static moved_type move(element_type& x)
|
||||
{
|
||||
// TODO: we probably need to launder here
|
||||
return {std::move(const_cast<raw_key_type&>(x.first)),
|
||||
std::move(const_cast<raw_mapped_type&>(x.second))};
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, init_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, value_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, init_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, value_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
};
|
||||
} // namespace foa
|
||||
} // namespace detail
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_FOA_FLAT_MAP_TYPES_HPP
|
||||
44
linx64/include/boost/unordered/detail/foa/flat_set_types.hpp
Normal file
44
linx64/include/boost/unordered/detail/foa/flat_set_types.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (C) 2023 Christian Mazakas
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP
|
||||
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
namespace foa {
|
||||
template <class Key> struct flat_set_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using init_type = Key;
|
||||
using value_type = Key;
|
||||
|
||||
static Key const& extract(value_type const& key) { return key; }
|
||||
|
||||
using element_type = value_type;
|
||||
|
||||
static Key& value_from(element_type& x) { return x; }
|
||||
|
||||
static element_type&& move(element_type& x) { return std::move(x); }
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, value_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, value_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
};
|
||||
} // namespace foa
|
||||
} // namespace detail
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_FOA_FLAT_SET_TYPES_HPP
|
||||
35
linx64/include/boost/unordered/detail/foa/ignore_wshadow.hpp
Normal file
35
linx64/include/boost/unordered/detail/foa/ignore_wshadow.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(BOOST_GCC)
|
||||
#if !defined(BOOST_UNORDERED_DETAIL_RESTORE_WSHADOW)
|
||||
/* GCC's -Wshadow triggers at scenarios like this:
|
||||
*
|
||||
* struct foo{};
|
||||
* template<typename Base>
|
||||
* struct derived:Base
|
||||
* {
|
||||
* void f(){int foo;}
|
||||
* };
|
||||
*
|
||||
* derived<foo>x;
|
||||
* x.f(); // declaration of "foo" in derived::f shadows base type "foo"
|
||||
*
|
||||
* This makes shadowing warnings unavoidable in general when a class template
|
||||
* derives from user-provided classes, as is the case with foa::table_core
|
||||
* deriving from empty_value.
|
||||
*/
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
210
linx64/include/boost/unordered/detail/foa/node_handle.hpp
Normal file
210
linx64/include/boost/unordered/detail/foa/node_handle.hpp
Normal file
@@ -0,0 +1,210 @@
|
||||
/* Copyright 2023 Christian Mazakas.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
namespace foa{
|
||||
|
||||
template <class Iterator,class NodeType>
|
||||
struct insert_return_type
|
||||
{
|
||||
Iterator position;
|
||||
bool inserted;
|
||||
NodeType node;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
union opt_storage {
|
||||
BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS T t_;
|
||||
|
||||
opt_storage(){}
|
||||
~opt_storage(){}
|
||||
};
|
||||
|
||||
template <class TypePolicy,class Allocator>
|
||||
struct node_handle_base
|
||||
{
|
||||
protected:
|
||||
using type_policy=TypePolicy;
|
||||
using element_type=typename type_policy::element_type;
|
||||
|
||||
public:
|
||||
using allocator_type = Allocator;
|
||||
|
||||
private:
|
||||
using node_value_type=typename type_policy::value_type;
|
||||
element_type p_;
|
||||
BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS opt_storage<Allocator> a_;
|
||||
|
||||
protected:
|
||||
node_value_type& data()noexcept
|
||||
{
|
||||
return *(p_.p);
|
||||
}
|
||||
|
||||
node_value_type const& data()const noexcept
|
||||
{
|
||||
return *(p_.p);
|
||||
}
|
||||
|
||||
element_type& element()noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return p_;
|
||||
}
|
||||
|
||||
element_type const& element()const noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return p_;
|
||||
}
|
||||
|
||||
Allocator& al()noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return a_.t_;
|
||||
}
|
||||
|
||||
Allocator const& al()const noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return a_.t_;
|
||||
}
|
||||
|
||||
void emplace(element_type&& x,Allocator a)
|
||||
{
|
||||
BOOST_ASSERT(empty());
|
||||
auto* p=x.p;
|
||||
p_.p=p;
|
||||
new(&a_.t_)Allocator(a);
|
||||
x.p=nullptr;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
a_.t_.~Allocator();
|
||||
p_.p=nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr node_handle_base()noexcept:p_{nullptr}{}
|
||||
|
||||
node_handle_base(node_handle_base&& nh) noexcept
|
||||
{
|
||||
p_.p = nullptr;
|
||||
if (!nh.empty()){
|
||||
emplace(std::move(nh.p_),nh.al());
|
||||
nh.reset();
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_base& operator=(node_handle_base&& nh)noexcept
|
||||
{
|
||||
if(this!=&nh){
|
||||
if(empty()){
|
||||
if(nh.empty()){ /* empty(), nh.empty() */
|
||||
/* nothing to do */
|
||||
}else{ /* empty(), !nh.empty() */
|
||||
emplace(std::move(nh.p_),std::move(nh.al()));
|
||||
nh.reset();
|
||||
}
|
||||
}else{
|
||||
if(nh.empty()){ /* !empty(), nh.empty() */
|
||||
type_policy::destroy(al(),&p_);
|
||||
reset();
|
||||
}else{ /* !empty(), !nh.empty() */
|
||||
bool const pocma=
|
||||
boost::allocator_propagate_on_container_move_assignment<
|
||||
Allocator>::type::value;
|
||||
|
||||
BOOST_ASSERT(pocma||al()==nh.al());
|
||||
|
||||
type_policy::destroy(al(),&p_);
|
||||
if(pocma){
|
||||
al()=std::move(nh.al());
|
||||
}
|
||||
|
||||
p_=std::move(nh.p_);
|
||||
nh.reset();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(empty()){ /* empty(), nh.empty() */
|
||||
/* nothing to do */
|
||||
}else{ /* !empty(), !nh.empty() */
|
||||
type_policy::destroy(al(),&p_);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~node_handle_base()
|
||||
{
|
||||
if(!empty()){
|
||||
type_policy::destroy(al(),&p_);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
allocator_type get_allocator()const noexcept{return al();}
|
||||
explicit operator bool()const noexcept{ return !empty();}
|
||||
BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_.p==nullptr;}
|
||||
|
||||
void swap(node_handle_base& nh) noexcept(
|
||||
boost::allocator_is_always_equal<Allocator>::type::value||
|
||||
boost::allocator_propagate_on_container_swap<Allocator>::type::value)
|
||||
{
|
||||
if(this!=&nh){
|
||||
if(empty()){
|
||||
if(nh.empty()) {
|
||||
/* nothing to do here */
|
||||
} else {
|
||||
emplace(std::move(nh.p_), nh.al());
|
||||
nh.reset();
|
||||
}
|
||||
}else{
|
||||
if(nh.empty()){
|
||||
nh.emplace(std::move(p_),al());
|
||||
reset();
|
||||
}else{
|
||||
bool const pocs=
|
||||
boost::allocator_propagate_on_container_swap<
|
||||
Allocator>::type::value;
|
||||
|
||||
BOOST_ASSERT(pocs || al()==nh.al());
|
||||
|
||||
using std::swap;
|
||||
p_.swap(nh.p_);
|
||||
if(pocs)swap(al(),nh.al());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
friend
|
||||
void swap(node_handle_base& lhs,node_handle_base& rhs)
|
||||
noexcept(noexcept(lhs.swap(rhs)))
|
||||
{
|
||||
return lhs.swap(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
|
||||
132
linx64/include/boost/unordered/detail/foa/node_map_types.hpp
Normal file
132
linx64/include/boost/unordered/detail/foa/node_map_types.hpp
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright (C) 2023 Christian Mazakas
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP
|
||||
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/core/pointer_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
namespace foa {
|
||||
template <class Key, class T> struct node_map_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using raw_key_type = typename std::remove_const<Key>::type;
|
||||
using raw_mapped_type = typename std::remove_const<T>::type;
|
||||
|
||||
using init_type = std::pair<raw_key_type, raw_mapped_type>;
|
||||
using value_type = std::pair<Key const, T>;
|
||||
using moved_type = std::pair<raw_key_type&&, raw_mapped_type&&>;
|
||||
|
||||
using element_type = foa::element_type<value_type>;
|
||||
|
||||
static value_type& value_from(element_type const& x)
|
||||
{
|
||||
return *(x.p);
|
||||
}
|
||||
|
||||
template <class K, class V>
|
||||
static raw_key_type const& extract(std::pair<K, V> const& kv)
|
||||
{
|
||||
return kv.first;
|
||||
}
|
||||
|
||||
static raw_key_type const& extract(element_type const& kv)
|
||||
{
|
||||
return kv.p->first;
|
||||
}
|
||||
|
||||
static element_type&& move(element_type& x) { return std::move(x); }
|
||||
static moved_type move(init_type& x)
|
||||
{
|
||||
return {std::move(x.first), std::move(x.second)};
|
||||
}
|
||||
|
||||
static moved_type move(value_type& x)
|
||||
{
|
||||
return {std::move(const_cast<raw_key_type&>(x.first)),
|
||||
std::move(const_cast<raw_mapped_type&>(x.second))};
|
||||
}
|
||||
|
||||
template <class A>
|
||||
static void construct(A&, element_type* p, element_type&& x) noexcept
|
||||
{
|
||||
p->p = x.p;
|
||||
x.p = nullptr;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
static void construct(
|
||||
A& al, element_type* p, element_type const& copy)
|
||||
{
|
||||
construct(al, p, *copy.p);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, init_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, value_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
{
|
||||
p->p = boost::to_address(boost::allocator_allocate(al, 1));
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::allocator_construct(al, p->p, std::forward<Args>(args)...);
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
using pointer_type = typename boost::allocator_pointer<A>::type;
|
||||
using pointer_traits = boost::pointer_traits<pointer_type>;
|
||||
|
||||
boost::allocator_deallocate(
|
||||
al, pointer_traits::pointer_to(*(p->p)), 1);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, value_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, init_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
|
||||
template <class A>
|
||||
static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
if (p->p) {
|
||||
using pointer_type = typename boost::allocator_pointer<A>::type;
|
||||
using pointer_traits = boost::pointer_traits<pointer_type>;
|
||||
|
||||
destroy(al, p->p);
|
||||
boost::allocator_deallocate(
|
||||
al, pointer_traits::pointer_to(*(p->p)), 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace foa
|
||||
} // namespace detail
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_TYPES_HPP
|
||||
95
linx64/include/boost/unordered/detail/foa/node_set_types.hpp
Normal file
95
linx64/include/boost/unordered/detail/foa/node_set_types.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (C) 2023 Christian Mazakas
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP
|
||||
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/core/pointer_traits.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
namespace foa {
|
||||
|
||||
template <class Key> struct node_set_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using init_type = Key;
|
||||
using value_type = Key;
|
||||
|
||||
static Key const& extract(value_type const& key) { return key; }
|
||||
|
||||
using element_type = foa::element_type<value_type>;
|
||||
|
||||
static value_type& value_from(element_type const& x) { return *x.p; }
|
||||
static Key const& extract(element_type const& k) { return *k.p; }
|
||||
static element_type&& move(element_type& x) { return std::move(x); }
|
||||
static value_type&& move(value_type& x) { return std::move(x); }
|
||||
|
||||
template <class A>
|
||||
static void construct(
|
||||
A& al, element_type* p, element_type const& copy)
|
||||
{
|
||||
construct(al, p, *copy.p);
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
static void construct(
|
||||
Allocator&, element_type* p, element_type&& x) noexcept
|
||||
{
|
||||
p->p = x.p;
|
||||
x.p = nullptr;
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, value_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
{
|
||||
p->p = boost::to_address(boost::allocator_allocate(al, 1));
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::allocator_construct(al, p->p, std::forward<Args>(args)...);
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<typename boost::allocator_pointer<
|
||||
A>::type>::pointer_to(*p->p),
|
||||
1);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, value_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
|
||||
template <class A>
|
||||
static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
if (p->p) {
|
||||
destroy(al, p->p);
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<typename boost::allocator_pointer<
|
||||
A>::type>::pointer_to(*(p->p)),
|
||||
1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace foa
|
||||
} // namespace detail
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_FOA_NODE_SET_TYPES_HPP
|
||||
@@ -0,0 +1,11 @@
|
||||
/* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#define BOOST_UNORDERED_DETAIL_RESTORE_WSHADOW
|
||||
#include <boost/unordered/detail/foa/ignore_wshadow.hpp>
|
||||
#undef BOOST_UNORDERED_DETAIL_RESTORE_WSHADOW
|
||||
179
linx64/include/boost/unordered/detail/foa/rw_spinlock.hpp
Normal file
179
linx64/include/boost/unordered/detail/foa/rw_spinlock.hpp
Normal file
@@ -0,0 +1,179 @@
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_RW_SPINLOCK_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_RW_SPINLOCK_HPP_INCLUDED
|
||||
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/core/yield_primitives.hpp>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
namespace foa{
|
||||
|
||||
class rw_spinlock
|
||||
{
|
||||
private:
|
||||
|
||||
// bit 31: locked exclusive
|
||||
// bit 30: writer pending
|
||||
// bit 29..0: reader lock count
|
||||
|
||||
static constexpr std::uint32_t locked_exclusive_mask = 1u << 31; // 0x8000'0000
|
||||
static constexpr std::uint32_t writer_pending_mask = 1u << 30; // 0x4000'0000
|
||||
static constexpr std::uint32_t reader_lock_count_mask = writer_pending_mask - 1; // 0x3FFF'FFFF
|
||||
|
||||
std::atomic<std::uint32_t> state_ = {};
|
||||
|
||||
private:
|
||||
|
||||
// Effects: Provides a hint to the implementation that the current thread
|
||||
// has been unable to make progress for k+1 iterations.
|
||||
|
||||
static void yield( unsigned k ) noexcept
|
||||
{
|
||||
unsigned const sleep_every = 1024; // see below
|
||||
|
||||
k %= sleep_every;
|
||||
|
||||
if( k < 5 )
|
||||
{
|
||||
// Intel recommendation from the Optimization Reference Manual
|
||||
// Exponentially increase number of PAUSE instructions each
|
||||
// iteration until reaching a maximum which is approximately
|
||||
// one timeslice long (2^4 == 16 in our case)
|
||||
|
||||
unsigned const pause_count = 1u << k;
|
||||
|
||||
for( unsigned i = 0; i < pause_count; ++i )
|
||||
{
|
||||
boost::core::sp_thread_pause();
|
||||
}
|
||||
}
|
||||
else if( k < sleep_every - 1 )
|
||||
{
|
||||
// Once the maximum number of PAUSE instructions is reached,
|
||||
// we switch to yielding the timeslice immediately
|
||||
|
||||
boost::core::sp_thread_yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
// After `sleep_every` iterations of no progress, we sleep,
|
||||
// to avoid a deadlock if a lower priority thread has the lock
|
||||
|
||||
boost::core::sp_thread_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool try_lock_shared() noexcept
|
||||
{
|
||||
std::uint32_t st = state_.load( std::memory_order_relaxed );
|
||||
|
||||
if( st >= reader_lock_count_mask )
|
||||
{
|
||||
// either bit 31 set, bit 30 set, or reader count is max
|
||||
return false;
|
||||
}
|
||||
|
||||
std::uint32_t newst = st + 1;
|
||||
return state_.compare_exchange_strong( st, newst, std::memory_order_acquire, std::memory_order_relaxed );
|
||||
}
|
||||
|
||||
void lock_shared() noexcept
|
||||
{
|
||||
for( unsigned k = 0; ; ++k )
|
||||
{
|
||||
std::uint32_t st = state_.load( std::memory_order_relaxed );
|
||||
|
||||
if( st < reader_lock_count_mask )
|
||||
{
|
||||
std::uint32_t newst = st + 1;
|
||||
if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return;
|
||||
}
|
||||
|
||||
yield( k );
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared() noexcept
|
||||
{
|
||||
// pre: locked shared, not locked exclusive
|
||||
|
||||
state_.fetch_sub( 1, std::memory_order_release );
|
||||
|
||||
// if the writer pending bit is set, there's a writer waiting
|
||||
// let it acquire the lock; it will clear the bit on unlock
|
||||
}
|
||||
|
||||
bool try_lock() noexcept
|
||||
{
|
||||
std::uint32_t st = state_.load( std::memory_order_relaxed );
|
||||
|
||||
if( st & locked_exclusive_mask )
|
||||
{
|
||||
// locked exclusive
|
||||
return false;
|
||||
}
|
||||
|
||||
if( st & reader_lock_count_mask )
|
||||
{
|
||||
// locked shared
|
||||
return false;
|
||||
}
|
||||
|
||||
std::uint32_t newst = locked_exclusive_mask;
|
||||
return state_.compare_exchange_strong( st, newst, std::memory_order_acquire, std::memory_order_relaxed );
|
||||
}
|
||||
|
||||
void lock() noexcept
|
||||
{
|
||||
for( unsigned k = 0; ; ++k )
|
||||
{
|
||||
std::uint32_t st = state_.load( std::memory_order_relaxed );
|
||||
|
||||
if( st & locked_exclusive_mask )
|
||||
{
|
||||
// locked exclusive, spin
|
||||
}
|
||||
else if( ( st & reader_lock_count_mask ) == 0 )
|
||||
{
|
||||
// not locked exclusive, not locked shared, try to lock
|
||||
|
||||
std::uint32_t newst = locked_exclusive_mask;
|
||||
if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return;
|
||||
}
|
||||
else if( st & writer_pending_mask )
|
||||
{
|
||||
// writer pending bit already set, nothing to do
|
||||
}
|
||||
else
|
||||
{
|
||||
// locked shared, set writer pending bit
|
||||
|
||||
std::uint32_t newst = st | writer_pending_mask;
|
||||
state_.compare_exchange_weak( st, newst, std::memory_order_relaxed, std::memory_order_relaxed );
|
||||
}
|
||||
|
||||
yield( k );
|
||||
}
|
||||
}
|
||||
|
||||
void unlock() noexcept
|
||||
{
|
||||
// pre: locked exclusive, not locked shared
|
||||
state_.store( 0, std::memory_order_release );
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace foa */
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_FOA_RW_SPINLOCK_HPP_INCLUDED
|
||||
556
linx64/include/boost/unordered/detail/foa/table.hpp
Normal file
556
linx64/include/boost/unordered/detail/foa/table.hpp
Normal file
@@ -0,0 +1,556 @@
|
||||
/* Fast open-addressing hash table.
|
||||
*
|
||||
* Copyright 2022-2023 Joaquin M Lopez Munoz.
|
||||
* Copyright 2023 Christian Mazakas.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_TABLE_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_TABLE_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/unordered/detail/foa/core.hpp>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
namespace foa{
|
||||
|
||||
/* use plain integrals for group metadata storage */
|
||||
|
||||
template<typename Integral>
|
||||
struct plain_integral
|
||||
{
|
||||
operator Integral()const{return n;}
|
||||
void operator=(Integral m){n=m;}
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_GCC,>=50000 && BOOST_GCC<60000)
|
||||
void operator|=(Integral m){n=static_cast<Integral>(n|m);}
|
||||
void operator&=(Integral m){n=static_cast<Integral>(n&m);}
|
||||
#else
|
||||
void operator|=(Integral m){n|=m;}
|
||||
void operator&=(Integral m){n&=m;}
|
||||
#endif
|
||||
|
||||
Integral n;
|
||||
};
|
||||
|
||||
struct plain_size_control
|
||||
{
|
||||
std::size_t ml;
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
template<typename,typename,typename,typename>
|
||||
class table;
|
||||
|
||||
/* table_iterator keeps two pointers:
|
||||
*
|
||||
* - A pointer p to the element slot.
|
||||
* - A pointer pc to the n-th byte of the associated group metadata, where n
|
||||
* is the position of the element in the group.
|
||||
*
|
||||
* A simpler solution would have been to keep a pointer p to the element, a
|
||||
* pointer pg to the group, and the position n, but that would increase
|
||||
* sizeof(table_iterator) by 4/8 bytes. In order to make this compact
|
||||
* representation feasible, it is required that group objects are aligned
|
||||
* to their size, so that we can recover pg and n as
|
||||
*
|
||||
* - n = pc%sizeof(group)
|
||||
* - pg = pc-n
|
||||
*
|
||||
* (for explanatory purposes pg and pc are treated above as if they were memory
|
||||
* addresses rather than pointers).
|
||||
*
|
||||
* p = nullptr is conventionally used to mark end() iterators.
|
||||
*/
|
||||
|
||||
/* internal conversion from const_iterator to iterator */
|
||||
struct const_iterator_cast_tag{};
|
||||
|
||||
template<typename TypePolicy,typename Group,bool Const>
|
||||
class table_iterator
|
||||
{
|
||||
using type_policy=TypePolicy;
|
||||
using table_element_type=typename type_policy::element_type;
|
||||
using group_type=Group;
|
||||
static constexpr auto N=group_type::N;
|
||||
static constexpr auto regular_layout=group_type::regular_layout;
|
||||
|
||||
public:
|
||||
using difference_type=std::ptrdiff_t;
|
||||
using value_type=typename type_policy::value_type;
|
||||
using pointer=
|
||||
typename std::conditional<Const,value_type const*,value_type*>::type;
|
||||
using reference=
|
||||
typename std::conditional<Const,value_type const&,value_type&>::type;
|
||||
using iterator_category=std::forward_iterator_tag;
|
||||
using element_type=
|
||||
typename std::conditional<Const,value_type const,value_type>::type;
|
||||
|
||||
table_iterator()=default;
|
||||
template<bool Const2,typename std::enable_if<!Const2>::type* =nullptr>
|
||||
table_iterator(const table_iterator<TypePolicy,Group,Const2>& x):
|
||||
pc{x.pc},p{x.p}{}
|
||||
table_iterator(
|
||||
const_iterator_cast_tag, const table_iterator<TypePolicy,Group,true>& x):
|
||||
pc{x.pc},p{x.p}{}
|
||||
|
||||
inline reference operator*()const noexcept
|
||||
{return type_policy::value_from(*p);}
|
||||
inline pointer operator->()const noexcept
|
||||
{return std::addressof(type_policy::value_from(*p));}
|
||||
inline table_iterator& operator++()noexcept{increment();return *this;}
|
||||
inline table_iterator operator++(int)noexcept
|
||||
{auto x=*this;increment();return x;}
|
||||
friend inline bool operator==(
|
||||
const table_iterator& x,const table_iterator& y)
|
||||
{return x.p==y.p;}
|
||||
friend inline bool operator!=(
|
||||
const table_iterator& x,const table_iterator& y)
|
||||
{return !(x==y);}
|
||||
|
||||
private:
|
||||
template<typename,typename,bool> friend class table_iterator;
|
||||
template<typename> friend class table_erase_return_type;
|
||||
template<typename,typename,typename,typename> friend class table;
|
||||
|
||||
table_iterator(Group* pg,std::size_t n,const table_element_type* p_):
|
||||
pc{reinterpret_cast<unsigned char*>(const_cast<group_type*>(pg))+n},
|
||||
p{const_cast<table_element_type*>(p_)}
|
||||
{}
|
||||
|
||||
inline void increment()noexcept
|
||||
{
|
||||
BOOST_ASSERT(p!=nullptr);
|
||||
increment(std::integral_constant<bool,regular_layout>{});
|
||||
}
|
||||
|
||||
inline void increment(std::true_type /* regular layout */)noexcept
|
||||
{
|
||||
for(;;){
|
||||
++p;
|
||||
if(reinterpret_cast<uintptr_t>(pc)%sizeof(group_type)==N-1){
|
||||
pc+=sizeof(group_type)-(N-1);
|
||||
break;
|
||||
}
|
||||
++pc;
|
||||
if(!group_type::is_occupied(pc))continue;
|
||||
if(BOOST_UNLIKELY(group_type::is_sentinel(pc)))p=nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
for(;;){
|
||||
int mask=reinterpret_cast<group_type*>(pc)->match_occupied();
|
||||
if(mask!=0){
|
||||
auto n=unchecked_countr_zero(mask);
|
||||
if(BOOST_UNLIKELY(reinterpret_cast<group_type*>(pc)->is_sentinel(n))){
|
||||
p=nullptr;
|
||||
}
|
||||
else{
|
||||
pc+=n;
|
||||
p+=n;
|
||||
}
|
||||
return;
|
||||
}
|
||||
pc+=sizeof(group_type);
|
||||
p+=N;
|
||||
}
|
||||
}
|
||||
|
||||
inline void increment(std::false_type /* interleaved */)noexcept
|
||||
{
|
||||
std::size_t n0=reinterpret_cast<uintptr_t>(pc)%sizeof(group_type);
|
||||
pc-=n0;
|
||||
|
||||
int mask=(
|
||||
reinterpret_cast<group_type*>(pc)->match_occupied()>>(n0+1))<<(n0+1);
|
||||
if(!mask){
|
||||
do{
|
||||
pc+=sizeof(group_type);
|
||||
p+=N;
|
||||
}
|
||||
while((mask=reinterpret_cast<group_type*>(pc)->match_occupied())==0);
|
||||
}
|
||||
|
||||
auto n=unchecked_countr_zero(mask);
|
||||
if(BOOST_UNLIKELY(reinterpret_cast<group_type*>(pc)->is_sentinel(n))){
|
||||
p=nullptr;
|
||||
}
|
||||
else{
|
||||
pc+=n;
|
||||
p-=n0;
|
||||
p+=n;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *pc=nullptr;
|
||||
table_element_type *p=nullptr;
|
||||
};
|
||||
|
||||
/* Returned by table::erase([const_]iterator) to avoid iterator increment
|
||||
* if discarded.
|
||||
*/
|
||||
|
||||
template<typename Iterator>
|
||||
class table_erase_return_type;
|
||||
|
||||
template<typename TypePolicy,typename Group,bool Const>
|
||||
class table_erase_return_type<table_iterator<TypePolicy,Group,Const>>
|
||||
{
|
||||
using iterator=table_iterator<TypePolicy,Group,Const>;
|
||||
using const_iterator=table_iterator<TypePolicy,Group,true>;
|
||||
|
||||
public:
|
||||
/* can't delete it because VS in pre-C++17 mode needs to see it for RVO */
|
||||
table_erase_return_type(const table_erase_return_type&);
|
||||
|
||||
operator iterator()const noexcept
|
||||
{
|
||||
auto it=pos;
|
||||
it.increment(); /* valid even if *it was erased */
|
||||
return iterator(const_iterator_cast_tag{},it);
|
||||
}
|
||||
|
||||
template<
|
||||
bool dependent_value=false,
|
||||
typename std::enable_if<!Const||dependent_value>::type* =nullptr
|
||||
>
|
||||
operator const_iterator()const noexcept{return this->operator iterator();}
|
||||
|
||||
private:
|
||||
template<typename,typename,typename,typename> friend class table;
|
||||
|
||||
table_erase_return_type(const_iterator pos_):pos{pos_}{}
|
||||
table_erase_return_type& operator=(const table_erase_return_type&)=delete;
|
||||
|
||||
const_iterator pos;
|
||||
};
|
||||
|
||||
/* foa::table interface departs in a number of ways from that of C++ unordered
|
||||
* associative containers because it's not for end-user consumption
|
||||
* (boost::unordered_(flat|node)_(map|set) wrappers complete it as
|
||||
* appropriate).
|
||||
*
|
||||
* The table supports two main modes of operation: flat and node-based. In the
|
||||
* flat case, buckets directly store elements. For node-based, buckets store
|
||||
* pointers to individually heap-allocated elements.
|
||||
*
|
||||
* For both flat and node-based:
|
||||
*
|
||||
* - begin() is not O(1).
|
||||
* - No bucket API.
|
||||
* - Load factor is fixed and can't be set by the user.
|
||||
*
|
||||
* For flat only:
|
||||
*
|
||||
* - value_type must be moveable.
|
||||
* - Pointer stability is not kept under rehashing.
|
||||
* - No extract API.
|
||||
*
|
||||
* try_emplace, erase and find support heterogeneous lookup by default,
|
||||
* that is, without checking for any ::is_transparent typedefs --the
|
||||
* checking is done by boost::unordered_(flat|node)_(map|set).
|
||||
*/
|
||||
|
||||
template <typename TypePolicy,typename Hash,typename Pred,typename Allocator>
|
||||
using table_core_impl=
|
||||
table_core<TypePolicy,group15<plain_integral>,table_arrays,
|
||||
plain_size_control,Hash,Pred,Allocator>;
|
||||
|
||||
#include <boost/unordered/detail/foa/ignore_wshadow.hpp>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
template<typename TypePolicy,typename Hash,typename Pred,typename Allocator>
|
||||
class table:table_core_impl<TypePolicy,Hash,Pred,Allocator>
|
||||
{
|
||||
using super=table_core_impl<TypePolicy,Hash,Pred,Allocator>;
|
||||
using type_policy=typename super::type_policy;
|
||||
using group_type=typename super::group_type;
|
||||
using super::N;
|
||||
using prober=typename super::prober;
|
||||
using locator=typename super::locator;
|
||||
|
||||
public:
|
||||
using key_type=typename super::key_type;
|
||||
using init_type=typename super::init_type;
|
||||
using value_type=typename super::value_type;
|
||||
using element_type=typename super::element_type;
|
||||
|
||||
private:
|
||||
static constexpr bool has_mutable_iterator=
|
||||
!std::is_same<key_type,value_type>::value;
|
||||
|
||||
public:
|
||||
using hasher=typename super::hasher;
|
||||
using key_equal=typename super::key_equal;
|
||||
using allocator_type=typename super::allocator_type;
|
||||
using pointer=typename super::pointer;
|
||||
using const_pointer=typename super::const_pointer;
|
||||
using reference=typename super::reference;
|
||||
using const_reference=typename super::const_reference;
|
||||
using size_type=typename super::size_type;
|
||||
using difference_type=typename super::difference_type;
|
||||
using const_iterator=table_iterator<type_policy,group_type,true>;
|
||||
using iterator=typename std::conditional<
|
||||
has_mutable_iterator,
|
||||
table_iterator<type_policy,group_type,false>,
|
||||
const_iterator>::type;
|
||||
using erase_return_type=table_erase_return_type<iterator>;
|
||||
|
||||
table(
|
||||
std::size_t n=default_bucket_count,const Hash& h_=Hash(),
|
||||
const Pred& pred_=Pred(),const Allocator& al_=Allocator()):
|
||||
super{n,h_,pred_,al_}
|
||||
{}
|
||||
|
||||
table(const table& x)=default;
|
||||
table(table&& x)=default;
|
||||
table(const table& x,const Allocator& al_):super{x,al_}{}
|
||||
table(table&& x,const Allocator& al_):super{std::move(x),al_}{}
|
||||
~table()=default;
|
||||
|
||||
table& operator=(const table& x)=default;
|
||||
table& operator=(table&& x)=default;
|
||||
|
||||
using super::get_allocator;
|
||||
|
||||
iterator begin()noexcept
|
||||
{
|
||||
iterator it{this->arrays.groups,0,this->arrays.elements};
|
||||
if(this->arrays.elements&&
|
||||
!(this->arrays.groups[0].match_occupied()&0x1))++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
const_iterator begin()const noexcept
|
||||
{return const_cast<table*>(this)->begin();}
|
||||
iterator end()noexcept{return {};}
|
||||
const_iterator end()const noexcept{return const_cast<table*>(this)->end();}
|
||||
const_iterator cbegin()const noexcept{return begin();}
|
||||
const_iterator cend()const noexcept{return end();}
|
||||
|
||||
using super::empty;
|
||||
using super::size;
|
||||
using super::max_size;
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace(Args&&... args)
|
||||
{
|
||||
auto x=alloc_make_insert_type<type_policy>(
|
||||
this->al(),std::forward<Args>(args)...);
|
||||
return emplace_impl(type_policy::move(x.value()));
|
||||
}
|
||||
|
||||
template<typename Key,typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> try_emplace(
|
||||
Key&& x,Args&&... args)
|
||||
{
|
||||
return emplace_impl(
|
||||
try_emplace_args_t{},std::forward<Key>(x),std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool>
|
||||
insert(const init_type& x){return emplace_impl(x);}
|
||||
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool>
|
||||
insert(init_type&& x){return emplace_impl(std::move(x));}
|
||||
|
||||
/* template<typename=void> tilts call ambiguities in favor of init_type */
|
||||
|
||||
template<typename=void>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool>
|
||||
insert(const value_type& x){return emplace_impl(x);}
|
||||
|
||||
template<typename=void>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool>
|
||||
insert(value_type&& x){return emplace_impl(std::move(x));}
|
||||
|
||||
template<typename T=element_type>
|
||||
BOOST_FORCEINLINE
|
||||
typename std::enable_if<
|
||||
!std::is_same<T,value_type>::value,
|
||||
std::pair<iterator,bool>
|
||||
>::type
|
||||
insert(element_type&& x){return emplace_impl(std::move(x));}
|
||||
|
||||
template<
|
||||
bool dependent_value=false,
|
||||
typename std::enable_if<
|
||||
has_mutable_iterator||dependent_value>::type* =nullptr
|
||||
>
|
||||
erase_return_type erase(iterator pos)noexcept
|
||||
{return erase(const_iterator(pos));}
|
||||
|
||||
BOOST_FORCEINLINE
|
||||
erase_return_type erase(const_iterator pos)noexcept
|
||||
{
|
||||
super::erase(pos.pc,pos.p);
|
||||
return {pos};
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
BOOST_FORCEINLINE
|
||||
auto erase(Key&& x) -> typename std::enable_if<
|
||||
!std::is_convertible<Key,iterator>::value&&
|
||||
!std::is_convertible<Key,const_iterator>::value, std::size_t>::type
|
||||
{
|
||||
auto it=find(x);
|
||||
if(it!=end()){
|
||||
erase(it);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void swap(table& x)
|
||||
noexcept(noexcept(std::declval<super&>().swap(std::declval<super&>())))
|
||||
{
|
||||
super::swap(x);
|
||||
}
|
||||
|
||||
using super::clear;
|
||||
|
||||
element_type extract(const_iterator pos)
|
||||
{
|
||||
BOOST_ASSERT(pos!=end());
|
||||
erase_on_exit e{*this,pos};
|
||||
(void)e;
|
||||
return std::move(*pos.p);
|
||||
}
|
||||
|
||||
// TODO: should we accept different allocator too?
|
||||
template<typename Hash2,typename Pred2>
|
||||
void merge(table<TypePolicy,Hash2,Pred2,Allocator>& x)
|
||||
{
|
||||
x.for_all_elements([&,this](group_type* pg,unsigned int n,element_type* p){
|
||||
erase_on_exit e{x,{pg,n,p}};
|
||||
if(!emplace_impl(type_policy::move(*p)).second)e.rollback();
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Hash2,typename Pred2>
|
||||
void merge(table<TypePolicy,Hash2,Pred2,Allocator>&& x){merge(x);}
|
||||
|
||||
using super::hash_function;
|
||||
using super::key_eq;
|
||||
|
||||
template<typename Key>
|
||||
BOOST_FORCEINLINE iterator find(const Key& x)
|
||||
{
|
||||
return make_iterator(super::find(x));
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
BOOST_FORCEINLINE const_iterator find(const Key& x)const
|
||||
{
|
||||
return const_cast<table*>(this)->find(x);
|
||||
}
|
||||
|
||||
using super::capacity;
|
||||
using super::load_factor;
|
||||
using super::max_load_factor;
|
||||
using super::max_load;
|
||||
using super::rehash;
|
||||
using super::reserve;
|
||||
|
||||
template<typename Predicate>
|
||||
friend std::size_t erase_if(table& x,Predicate& pr)
|
||||
{
|
||||
using value_reference=typename std::conditional<
|
||||
std::is_same<key_type,value_type>::value,
|
||||
const_reference,
|
||||
reference
|
||||
>::type;
|
||||
|
||||
std::size_t s=x.size();
|
||||
x.for_all_elements(
|
||||
[&](group_type* pg,unsigned int n,element_type* p){
|
||||
if(pr(const_cast<value_reference>(type_policy::value_from(*p)))){
|
||||
x.super::erase(pg,n,p);
|
||||
}
|
||||
});
|
||||
return std::size_t(s-x.size());
|
||||
}
|
||||
|
||||
friend bool operator==(const table& x,const table& y)
|
||||
{
|
||||
return static_cast<const super&>(x)==static_cast<const super&>(y);
|
||||
}
|
||||
|
||||
friend bool operator!=(const table& x,const table& y){return !(x==y);}
|
||||
|
||||
private:
|
||||
struct erase_on_exit
|
||||
{
|
||||
erase_on_exit(table& x_,const_iterator it_):x{x_},it{it_}{}
|
||||
~erase_on_exit(){if(!rollback_)x.erase(it);}
|
||||
|
||||
void rollback(){rollback_=true;}
|
||||
|
||||
table& x;
|
||||
const_iterator it;
|
||||
bool rollback_=false;
|
||||
};
|
||||
|
||||
static inline iterator make_iterator(const locator& l)noexcept
|
||||
{
|
||||
return {l.pg,l.n,l.p};
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_impl(Args&&... args)
|
||||
{
|
||||
const auto &k=this->key_from(std::forward<Args>(args)...);
|
||||
auto hash=this->hash_for(k);
|
||||
auto pos0=this->position_for(hash);
|
||||
auto loc=super::find(k,pos0,hash);
|
||||
|
||||
if(loc){
|
||||
return {make_iterator(loc),false};
|
||||
}
|
||||
if(BOOST_LIKELY(this->size_ctrl.size<this->size_ctrl.ml)){
|
||||
return {
|
||||
make_iterator(
|
||||
this->unchecked_emplace_at(pos0,hash,std::forward<Args>(args)...)),
|
||||
true
|
||||
};
|
||||
}
|
||||
else{
|
||||
return {
|
||||
make_iterator(
|
||||
this->unchecked_emplace_with_rehash(
|
||||
hash,std::forward<Args>(args)...)),
|
||||
true
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4714 */
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/foa/restore_wshadow.hpp>
|
||||
|
||||
} /* namespace foa */
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
/* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_TUPLE_ROTATE_RIGHT_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_TUPLE_ROTATE_RIGHT_HPP
|
||||
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/integer_sequence.hpp>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
namespace foa{
|
||||
|
||||
template<typename Tuple>
|
||||
using tuple_rotate_right_return_type=mp11::mp_rotate_right_c<
|
||||
typename std::remove_cv<typename std::remove_reference<Tuple>::type>::type,
|
||||
1
|
||||
>;
|
||||
|
||||
template<std::size_t... Is,typename Tuple>
|
||||
tuple_rotate_right_return_type<Tuple>
|
||||
tuple_rotate_right_aux(mp11::index_sequence<Is...>,Tuple&& x)
|
||||
{
|
||||
return tuple_rotate_right_return_type<Tuple>{
|
||||
std::get<(Is+sizeof...(Is)-1)%sizeof...(Is)>(std::forward<Tuple>(x))...};
|
||||
}
|
||||
|
||||
template<typename Tuple>
|
||||
tuple_rotate_right_return_type<Tuple> tuple_rotate_right(Tuple&& x)
|
||||
{
|
||||
using RawTuple=typename std::remove_cv<
|
||||
typename std::remove_reference<Tuple>::type>::type;
|
||||
|
||||
return tuple_rotate_right_aux(
|
||||
mp11::make_index_sequence<std::tuple_size<RawTuple>::value>{},
|
||||
std::forward<Tuple>(x));
|
||||
}
|
||||
|
||||
} /* namespace foa */
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright (C) 2008-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)
|
||||
|
||||
@@ -31,7 +32,7 @@
|
||||
// 2012 = VC+11 = BOOST_MSVC 1700 Hopefully!
|
||||
// I have no idea when Dinkumware added it, probably a lot
|
||||
// earlier than this check.
|
||||
#if BOOST_LIB_STD_DINKUMWARE >= BOOST_VERSION_NUMBER(6, 50, 0) || \
|
||||
#if BOOST_LIB_STD_DINKUMWARE >= BOOST_VERSION_NUMBER(6, 10, 0) || \
|
||||
BOOST_COMP_MSVC >= BOOST_VERSION_NUMBER(17, 0, 0)
|
||||
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
|
||||
#endif
|
||||
@@ -60,4 +61,90 @@ namespace boost {
|
||||
}
|
||||
}
|
||||
|
||||
// BOOST_UNORDERED_EMPLACE_LIMIT = The maximum number of parameters in
|
||||
// emplace (not including things like hints). Don't set it to a lower value, as
|
||||
// that might break something.
|
||||
|
||||
#if !defined BOOST_UNORDERED_EMPLACE_LIMIT
|
||||
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Configuration
|
||||
//
|
||||
// Unless documented elsewhere these configuration macros should be considered
|
||||
// an implementation detail, I'll try not to break them, but you never know.
|
||||
|
||||
// Use Sun C++ workarounds
|
||||
// I'm not sure which versions of the compiler require these workarounds, so
|
||||
// I'm just using them of everything older than the current test compilers
|
||||
// (as of May 2017).
|
||||
|
||||
#if !defined(BOOST_UNORDERED_SUN_WORKAROUNDS1)
|
||||
#if BOOST_COMP_SUNPRO && BOOST_COMP_SUNPRO < BOOST_VERSION_NUMBER(5, 20, 0)
|
||||
#define BOOST_UNORDERED_SUN_WORKAROUNDS1 1
|
||||
#else
|
||||
#define BOOST_UNORDERED_SUN_WORKAROUNDS1 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// BOOST_UNORDERED_TUPLE_ARGS
|
||||
//
|
||||
// Maximum number of std::tuple members to support, or 0 if std::tuple
|
||||
// isn't avaiable. More are supported when full C++11 is used.
|
||||
|
||||
// Already defined, so do nothing
|
||||
#if defined(BOOST_UNORDERED_TUPLE_ARGS)
|
||||
|
||||
// Assume if we have C++11 tuple it's properly variadic,
|
||||
// and just use a max number of 10 arguments.
|
||||
#elif !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#define BOOST_UNORDERED_TUPLE_ARGS 10
|
||||
|
||||
// Visual C++ has a decent enough tuple for piecewise construction,
|
||||
// so use that if available, using _VARIADIC_MAX for the maximum
|
||||
// number of parameters. Note that this comes after the check
|
||||
// for a full C++11 tuple.
|
||||
#elif defined(BOOST_MSVC)
|
||||
#if !BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
|
||||
#define BOOST_UNORDERED_TUPLE_ARGS 0
|
||||
#elif defined(_VARIADIC_MAX)
|
||||
#define BOOST_UNORDERED_TUPLE_ARGS _VARIADIC_MAX
|
||||
#else
|
||||
#define BOOST_UNORDERED_TUPLE_ARGS 5
|
||||
#endif
|
||||
|
||||
// Assume that we don't have std::tuple
|
||||
#else
|
||||
#define BOOST_UNORDERED_TUPLE_ARGS 0
|
||||
#endif
|
||||
|
||||
#if BOOST_UNORDERED_TUPLE_ARGS
|
||||
#include <tuple>
|
||||
#endif
|
||||
|
||||
// BOOST_UNORDERED_CXX11_CONSTRUCTION
|
||||
//
|
||||
// Use C++11 construction, requires variadic arguments, good construct support
|
||||
// in allocator_traits and piecewise construction of std::pair
|
||||
// Otherwise allocators aren't used for construction/destruction
|
||||
|
||||
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT && \
|
||||
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && BOOST_UNORDERED_TUPLE_ARGS
|
||||
#if BOOST_COMP_SUNPRO && BOOST_LIB_STD_GNU
|
||||
// Sun C++ std::pair piecewise construction doesn't seem to be exception safe.
|
||||
// (At least for Sun C++ 12.5 using libstdc++).
|
||||
#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
|
||||
#elif BOOST_COMP_GNUC && BOOST_COMP_GNUC < BOOST_VERSION_NUMBER(4, 7, 0)
|
||||
// Piecewise construction in GCC 4.6 doesn't work for uncopyable types.
|
||||
#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
|
||||
#elif !defined(BOOST_NO_CXX11_ALLOCATOR)
|
||||
#define BOOST_UNORDERED_CXX11_CONSTRUCTION 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_UNORDERED_CXX11_CONSTRUCTION)
|
||||
#define BOOST_UNORDERED_CXX11_CONSTRUCTION 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
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>
|
||||
|
||||
129
linx64/include/boost/unordered/detail/mulx.hpp
Normal file
129
linx64/include/boost/unordered/detail/mulx.hpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#ifndef BOOST_UNORDERED_DETAIL_MULX_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_MULX_HPP
|
||||
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Copyright 2022 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
|
||||
// Bit mixer based on the mulx primitive
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__)
|
||||
|
||||
__forceinline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
boost::uint64_t r2;
|
||||
boost::uint64_t r = _umul128( x, y, &r2 );
|
||||
return r ^ r2;
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__)
|
||||
|
||||
__forceinline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
boost::uint64_t r = x * y;
|
||||
boost::uint64_t r2 = __umulh( x, y );
|
||||
return r ^ r2;
|
||||
}
|
||||
|
||||
#elif defined(__SIZEOF_INT128__)
|
||||
|
||||
inline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
__uint128_t r = (__uint128_t)x * y;
|
||||
return (boost::uint64_t)r ^ (boost::uint64_t)( r >> 64 );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
boost::uint64_t x1 = (boost::uint32_t)x;
|
||||
boost::uint64_t x2 = x >> 32;
|
||||
|
||||
boost::uint64_t y1 = (boost::uint32_t)y;
|
||||
boost::uint64_t y2 = y >> 32;
|
||||
|
||||
boost::uint64_t r3 = x2 * y2;
|
||||
|
||||
boost::uint64_t r2a = x1 * y2;
|
||||
|
||||
r3 += r2a >> 32;
|
||||
|
||||
boost::uint64_t r2b = x2 * y1;
|
||||
|
||||
r3 += r2b >> 32;
|
||||
|
||||
boost::uint64_t r1 = x1 * y1;
|
||||
|
||||
boost::uint64_t r2 = (r1 >> 32) + (boost::uint32_t)r2a + (boost::uint32_t)r2b;
|
||||
|
||||
r1 = (r2 << 32) + (boost::uint32_t)r1;
|
||||
r3 += r2 >> 32;
|
||||
|
||||
return r1 ^ r3;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline boost::uint32_t mulx32( boost::uint32_t x, boost::uint32_t y )
|
||||
{
|
||||
boost::uint64_t r = (boost::uint64_t)x * y;
|
||||
|
||||
#if defined(__MSVC_RUNTIME_CHECKS)
|
||||
|
||||
return (boost::uint32_t)(r & UINT32_MAX) ^ (boost::uint32_t)(r >> 32);
|
||||
|
||||
#else
|
||||
|
||||
return (boost::uint32_t)r ^ (boost::uint32_t)(r >> 32);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SIZE_MAX)
|
||||
#if ((((SIZE_MAX >> 16) >> 16) >> 16) >> 15) != 0
|
||||
#define BOOST_UNORDERED_64B_ARCHITECTURE /* >64 bits assumed as 64 bits */
|
||||
#endif
|
||||
#elif defined(UINTPTR_MAX) /* used as proxy for std::size_t */
|
||||
#if ((((UINTPTR_MAX >> 16) >> 16) >> 16) >> 15) != 0
|
||||
#define BOOST_UNORDERED_64B_ARCHITECTURE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
inline std::size_t mulx( std::size_t x ) noexcept
|
||||
{
|
||||
#if defined(BOOST_UNORDERED_64B_ARCHITECTURE)
|
||||
|
||||
// multiplier is phi
|
||||
return (std::size_t)mulx64( (boost::uint64_t)x, 0x9E3779B97F4A7C15ull );
|
||||
|
||||
#else /* 32 bits assumed */
|
||||
|
||||
// multiplier from https://arxiv.org/abs/2001.05304
|
||||
return mulx32( x, 0xE817FB2Du );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_64B_ARCHITECTURE
|
||||
#undef BOOST_UNORDERED_64B_ARCHITECTURE
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_UNORDERED_DETAIL_MULX_HPP
|
||||
44
linx64/include/boost/unordered/detail/narrow_cast.hpp
Normal file
44
linx64/include/boost/unordered/detail/narrow_cast.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/* Copyright 2022 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_NARROW_CAST_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_NARROW_CAST_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
|
||||
template<typename To,typename From>
|
||||
BOOST_CONSTEXPR To narrow_cast(From x) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT(boost::is_integral<From>::value);
|
||||
BOOST_STATIC_ASSERT(boost::is_integral<To>::value);
|
||||
BOOST_STATIC_ASSERT(sizeof(From)>=sizeof(To));
|
||||
|
||||
return static_cast<To>(
|
||||
x
|
||||
|
||||
#if defined(__MSVC_RUNTIME_CHECKS)
|
||||
/* Avoids VS's "Run-Time Check Failure #1 - A cast to a smaller data type
|
||||
* has caused a loss of data."
|
||||
*/
|
||||
&static_cast<typename boost::make_unsigned<To>::type>(~static_cast<To>(0))
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
263
linx64/include/boost/unordered/detail/prime_fmod.hpp
Normal file
263
linx64/include/boost/unordered/detail/prime_fmod.hpp
Normal file
@@ -0,0 +1,263 @@
|
||||
// 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_PRIME_FMOD_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_PRIME_FMOD_HPP
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/preprocessor/seq/enum.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
#include <boost/unordered/detail/narrow_cast.hpp>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
|
||||
#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_UNORDERED_FCA_HAS_64B_SIZE_T) && defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
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_HAS_64B_SIZE_T)
|
||||
static boost::uint64_t inv_sizes32[];
|
||||
static std::size_t const inv_sizes32_len;
|
||||
#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */
|
||||
|
||||
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_HAS_64B_SIZE_T)
|
||||
// We emulate the techniques taken from:
|
||||
// Faster Remainder by Direct Computation: Applications to Compilers and
|
||||
// Software Libraries
|
||||
// https://arxiv.org/abs/1902.01961
|
||||
//
|
||||
// In essence, use fancy math to directly calculate the remainder (aka
|
||||
// modulo) exploiting how compilers transform division
|
||||
//
|
||||
|
||||
static inline boost::uint64_t get_remainder(
|
||||
boost::uint64_t fractional, boost::uint32_t d)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
// use MSVC intrinsics when available to avoid promotion to 128 bits
|
||||
|
||||
return __umulh(fractional, d);
|
||||
#elif defined(BOOST_HAS_INT128)
|
||||
return static_cast<boost::uint64_t>(
|
||||
((boost::uint128_type)fractional * d) >> 64);
|
||||
#else
|
||||
// portable implementation in the absence of boost::uint128_type on 64
|
||||
// bits, which happens at least in GCC 4.5 and prior
|
||||
|
||||
boost::uint64_t r1 = (fractional & UINT32_MAX) * d;
|
||||
boost::uint64_t r2 = (fractional >> 32) * d;
|
||||
r2 += r1 >> 32;
|
||||
return r2 >> 32;
|
||||
#endif /* defined(_MSC_VER) */
|
||||
}
|
||||
|
||||
static inline boost::uint32_t fast_modulo(
|
||||
boost::uint32_t a, boost::uint64_t M, boost::uint32_t d)
|
||||
{
|
||||
boost::uint64_t fractional = M * a;
|
||||
return (boost::uint32_t)(get_remainder(fractional, d));
|
||||
}
|
||||
#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */
|
||||
|
||||
static inline std::size_t position(
|
||||
std::size_t hash, std::size_t size_index)
|
||||
{
|
||||
#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 fast_modulo(
|
||||
narrow_cast<boost::uint32_t>(hash) + narrow_cast<boost::uint32_t>(hash >> 32),
|
||||
inv_sizes32[size_index], boost::uint32_t(sizes[size_index]));
|
||||
} else {
|
||||
return positions[size_index - sizes_under_32bit](hash);
|
||||
}
|
||||
#else
|
||||
return positions[size_index](hash);
|
||||
#endif /* defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T) */
|
||||
}
|
||||
}; // 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_HAS_64B_SIZE_T)
|
||||
// clang-format off
|
||||
template <class T>
|
||||
boost::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 */,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
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_HAS_64B_SIZE_T) */
|
||||
|
||||
#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_HAS_64B_SIZE_T)
|
||||
BOOST_PP_SEQ_FOR_EACH(BOOST_UNORDERED_PRIME_FMOD_POSITIONS_ELEMENT, ~,
|
||||
BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT)
|
||||
#else
|
||||
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_32BIT
|
||||
#undef BOOST_UNORDERED_PRIME_FMOD_SIZES_32BIT_INCOMPLETE
|
||||
} // namespace detail
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_PRIME_FMOD_HPP
|
||||
21
linx64/include/boost/unordered/detail/requires_cxx11.hpp
Normal file
21
linx64/include/boost/unordered/detail/requires_cxx11.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BOOST_UNORDERED_DETAIL_REQUIRES_CXX11_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_REQUIRES_CXX11_HPP_INCLUDED
|
||||
|
||||
// Copyright 2023 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
|
||||
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \
|
||||
defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \
|
||||
defined(BOOST_NO_CXX11_DECLTYPE) || \
|
||||
defined(BOOST_NO_CXX11_CONSTEXPR) || \
|
||||
defined(BOOST_NO_CXX11_NOEXCEPT)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE("C++03 support is deprecated in Boost.Unordered 1.82 and will be removed in Boost.Unordered 1.84.")
|
||||
|
||||
#endif
|
||||
|
||||
#endif // #ifndef BOOST_UNORDERED_DETAIL_REQUIRES_CXX11_HPP_INCLUDED
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
122
linx64/include/boost/unordered/detail/type_traits.hpp
Normal file
122
linx64/include/boost/unordered/detail/type_traits.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// 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_TYPE_TRAITS_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_TYPE_TRAITS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/make_void.hpp>
|
||||
#include <boost/type_traits/type_identity.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
|
||||
#include <boost/type_traits/enable_if.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#endif
|
||||
|
||||
// BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||
|
||||
#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES)
|
||||
#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
|
||||
#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES)
|
||||
#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 0
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Type checkers used for the transparent member functions added by C++20
|
||||
// and up
|
||||
|
||||
template <class, class = void>
|
||||
struct is_transparent : public boost::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_transparent<T,
|
||||
typename boost::make_void<typename T::is_transparent>::type>
|
||||
: public boost::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class, class Hash, class KeyEqual> struct are_transparent
|
||||
{
|
||||
static bool const value =
|
||||
is_transparent<Hash>::value && is_transparent<KeyEqual>::value;
|
||||
};
|
||||
|
||||
template <class Key, class UnorderedMap> struct transparent_non_iterable
|
||||
{
|
||||
typedef typename UnorderedMap::hasher hash;
|
||||
typedef typename UnorderedMap::key_equal key_equal;
|
||||
typedef typename UnorderedMap::iterator iterator;
|
||||
typedef typename UnorderedMap::const_iterator const_iterator;
|
||||
|
||||
static bool const value =
|
||||
are_transparent<Key, hash, key_equal>::value &&
|
||||
!boost::is_convertible<Key, iterator>::value &&
|
||||
!boost::is_convertible<Key, const_iterator>::value;
|
||||
};
|
||||
|
||||
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||
// https://eel.is/c++draft/container.requirements#container.alloc.reqmts-34
|
||||
// https://eel.is/c++draft/container.requirements#unord.req.general-243
|
||||
|
||||
template <class InputIterator>
|
||||
constexpr bool const is_input_iterator_v =
|
||||
!boost::is_integral<InputIterator>::value;
|
||||
|
||||
template <class A, class = void> struct is_allocator
|
||||
{
|
||||
constexpr static bool const value = false;
|
||||
};
|
||||
|
||||
template <class A>
|
||||
struct is_allocator<A,
|
||||
boost::void_t<typename A::value_type,
|
||||
decltype(std::declval<A&>().allocate(std::size_t{}))> >
|
||||
{
|
||||
constexpr static bool const value = true;
|
||||
};
|
||||
|
||||
template <class A>
|
||||
constexpr bool const is_allocator_v = is_allocator<A>::value;
|
||||
|
||||
template <class H>
|
||||
constexpr bool const is_hash_v =
|
||||
!boost::is_integral<H>::value && !is_allocator_v<H>;
|
||||
|
||||
template <class P> constexpr bool const is_pred_v = !is_allocator_v<P>;
|
||||
|
||||
template <typename T>
|
||||
using iter_key_t =
|
||||
typename std::iterator_traits<T>::value_type::first_type;
|
||||
template <typename T>
|
||||
using iter_val_t =
|
||||
typename std::iterator_traits<T>::value_type::second_type;
|
||||
template <typename T>
|
||||
using iter_to_alloc_t =
|
||||
typename std::pair<iter_key_t<T> const, iter_val_t<T> >;
|
||||
#endif
|
||||
} // namespace detail
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_TYPE_TRAITS_HPP
|
||||
75
linx64/include/boost/unordered/detail/xmx.hpp
Normal file
75
linx64/include/boost/unordered/detail/xmx.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/* 32b/64b xmx mix function.
|
||||
*
|
||||
* Copyright 2022 Peter Dimov.
|
||||
* Copyright 2022 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_XMX_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_XMX_HPP
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
|
||||
/* Bit mixer for improvement of statistical properties of hash functions.
|
||||
* The implementation is different on 64bit and 32bit architectures:
|
||||
*
|
||||
* - 64bit: same as xmx function in
|
||||
* http://jonkagstrom.com/bit-mixer-construction/index.html
|
||||
* - 32bit: generated by Hash Function Prospector
|
||||
* (https://github.com/skeeto/hash-prospector) and selected as the
|
||||
* best overall performer in benchmarks of Boost.Unordered flat containers.
|
||||
* Score assigned by Hash Prospector: 333.7934929677524
|
||||
*/
|
||||
|
||||
#if defined(SIZE_MAX)
|
||||
#if ((((SIZE_MAX >> 16) >> 16) >> 16) >> 15) != 0
|
||||
#define BOOST_UNORDERED_64B_ARCHITECTURE /* >64 bits assumed as 64 bits */
|
||||
#endif
|
||||
#elif defined(UINTPTR_MAX) /* used as proxy for std::size_t */
|
||||
#if ((((UINTPTR_MAX >> 16) >> 16) >> 16) >> 15) != 0
|
||||
#define BOOST_UNORDERED_64B_ARCHITECTURE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static inline std::size_t xmx(std::size_t x)noexcept
|
||||
{
|
||||
#if defined(BOOST_UNORDERED_64B_ARCHITECTURE)
|
||||
|
||||
boost::uint64_t z=(boost::uint64_t)x;
|
||||
|
||||
z^=z>>23;
|
||||
z*=0xff51afd7ed558ccdull;
|
||||
z^=z>>23;
|
||||
|
||||
return (std::size_t)z;
|
||||
|
||||
#else /* 32 bits assumed */
|
||||
|
||||
x^=x>>18;
|
||||
x*=0x56b5aaadu;
|
||||
x^=x>>16;
|
||||
|
||||
return x;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_64B_ARCHITECTURE
|
||||
#undef BOOST_UNORDERED_64B_ARCHITECTURE
|
||||
#endif
|
||||
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user