Fixed std::initializer_list assignment issues for open-addressing containers (#277)

* fixed #276

* used range insert, stylistic this->

* assigned non-empty std::initializer_lists
This commit is contained in:
joaquintides
2024-09-02 18:56:13 +02:00
committed by GitHub
parent 21937249c4
commit cd9a592f00
10 changed files with 185 additions and 33 deletions

View File

@@ -5,11 +5,16 @@
#include "helpers.hpp"
#include "../helpers/replace_allocator.hpp"
#include "../objects/non_default_ctble_allocator.hpp"
#include <boost/unordered/concurrent_flat_map.hpp>
#include <boost/unordered/concurrent_flat_set.hpp>
#include <boost/unordered/concurrent_node_map.hpp>
#include <boost/unordered/concurrent_node_set.hpp>
#include <vector>
#if defined(__clang__) && defined(__has_warning)
#if __has_warning("-Wself-assign-overloaded")
@@ -882,6 +887,28 @@ namespace {
check_raii_counts();
}
template <class X, class GF>
void initializer_list_assign_gh276(
X*, GF gen_factory, test::random_generator rg)
{
// https://github.com/boostorg/unordered/issues/276
using replaced_allocator_container = test::replace_allocator<
X, test::non_default_ctble_allocator<int> >;
using replaced_allocator_type =
typename replaced_allocator_container::allocator_type;
auto gen = gen_factory.template get<X>();
auto values = make_random_values(4, [&] { return gen(rg); });
replaced_allocator_container
x(replaced_allocator_type(0)),
y(values.begin(), values.end(), replaced_allocator_type(0));
x = {values[0], values[1], values[2], values[3]};
BOOST_TEST(x == y);
}
template <class X, class GF>
void insert_and_assign(X*, GF gen_factory, test::random_generator rg)
{
@@ -1112,6 +1139,12 @@ UNORDERED_TEST(
((test_map_and_init_list)(test_node_map_and_init_list)
(test_set_and_init_list)(test_node_set_and_init_list)))
UNORDERED_TEST(
initializer_list_assign_gh276,
((test_map)(test_node_map)(test_set)(test_node_set))
((value_type_generator_factory))
((default_generator)))
UNORDERED_TEST(
insert_and_assign,
((test_map)(test_node_map)(test_set)(test_node_set))

View File

@@ -0,0 +1,44 @@
// Copyright 2024 Joaquin M Lopez Munz.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_TEST_REPLACE_ALLOCATOR
#define BOOST_UNORDERED_TEST_REPLACE_ALLOCATOR
#include <boost/core/allocator_access.hpp>
#include <utility>
namespace test {
template <typename Container, typename Allocator>
struct replace_allocator_impl;
template <typename Container, typename Allocator>
using replace_allocator =
typename replace_allocator_impl<Container, Allocator>::type;
template <
typename K, typename H, typename P, typename A,
template <typename, typename, typename, typename> class Set,
typename Allocator
>
struct replace_allocator_impl<Set<K, H, P, A>, Allocator>
{
using type = Set<
K, H, P, boost::allocator_rebind_t<Allocator, K> >;
};
template <
typename K, typename H, typename T, typename P, typename A,
template <typename, typename, typename, typename, typename> class Map,
typename Allocator
>
struct replace_allocator_impl<Map<K, T, H, P, A>, Allocator>
{
using type = Map<
K, T, H, P,
boost::allocator_rebind_t<Allocator, std::pair<K const, T> > >;
};
} // namespace test
#endif // !defined(BOOST_UNORDERED_TEST_REPLACE_ALLOCATOR)

View File

@@ -0,0 +1,46 @@
// Copyright 2024 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)
#if !defined(BOOST_UNORDERED_TEST_NON_DEFAULT_CTBLE_ALLOCATOR_HEADER)
#define BOOST_UNORDERED_TEST_NON_DEFAULT_CTBLE_ALLOCATOR_HEADER
#include <memory>
namespace test
{
template <class T> struct non_default_ctble_allocator
{
typedef T value_type;
non_default_ctble_allocator(int) {}
template <class U>
non_default_ctble_allocator(const non_default_ctble_allocator<U>&) {}
template<class U>
bool operator==(non_default_ctble_allocator<U> const &) const noexcept
{
return true;
}
template<class U>
bool operator!=(non_default_ctble_allocator<U> const &) const noexcept
{
return false;
}
T* allocate(std::size_t n)
{
return std::allocator<T>().allocate(n);
}
void deallocate(T* p, std::size_t n)
{
std::allocator<T>().deallocate(p, n);
}
};
}
#endif

View File

@@ -7,12 +7,16 @@
#include "../helpers/unordered.hpp"
#include "../helpers/test.hpp"
#include "../helpers/replace_allocator.hpp"
#include "../objects/test.hpp"
#include "../objects/cxx11_allocator.hpp"
#include "../objects/non_default_ctble_allocator.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include "../helpers/equivalent.hpp"
#include <vector>
#if defined(BOOST_MSVC)
#pragma warning(disable : 4127) // conditional expression is constant
#endif
@@ -288,6 +292,27 @@ namespace assign_tests {
}
#endif
}
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "gh276\n";
{
// https://github.com/boostorg/unordered/issues/276
using value_type = typename T::value_type;
using replaced_allocator_container = test::replace_allocator<
T, test::non_default_ctble_allocator<int> >;
using replaced_allocator_type =
typename replaced_allocator_container::allocator_type;
test::random_values<T> v(4, generator);
std::vector<value_type> vv(v.begin(), v.end());
replaced_allocator_container
x(replaced_allocator_type(0)),
y(vv.begin(), vv.begin() + 4, replaced_allocator_type(0));
x = {vv[0], vv[1], vv[2], vv[3]};
BOOST_TEST(x == y);
}
}
using test::default_generator;

View File

@@ -20,7 +20,8 @@
#endif
#include "../helpers/test.hpp"
#include "../helpers/replace_allocator.hpp"
#include <boost/config/workaround.hpp>
#include <boost/core/allocator_access.hpp>
#include <memory>
@@ -82,42 +83,12 @@ namespace {
bool operator!=(pocx_allocator const& rhs) const { return x_ != rhs.x_; }
};
template <typename Container, typename Allocator>
struct replace_allocator_impl;
template <typename Container, typename Allocator>
using replace_allocator =
typename replace_allocator_impl<Container, Allocator>::type;
template <
typename K, typename H, typename P, typename A,
template <typename, typename, typename, typename> class Set,
typename Allocator
>
struct replace_allocator_impl<Set<K, H, P, A>, Allocator>
{
using type = Set<
K, H, P, boost::allocator_rebind_t<Allocator, K> >;
};
template <
typename K, typename H, typename T, typename P, typename A,
template <typename, typename, typename, typename, typename> class Map,
typename Allocator
>
struct replace_allocator_impl<Map<K, T, H, P, A>, Allocator>
{
using type = Map<
K, T, H, P,
boost::allocator_rebind_t<Allocator, std::pair<K const, T> > >;
};
template<typename X, typename Allocator>
void node_handle_allocator_tests(
X*, std::pair<Allocator, Allocator> allocators)
{
using value_type = typename X::value_type;
using replaced_allocator_container = replace_allocator<X, Allocator>;
using replaced_allocator_container = test::replace_allocator<X, Allocator>;
using node_type = typename replaced_allocator_container::node_type;
replaced_allocator_container x1(allocators.first);
@@ -143,7 +114,7 @@ namespace {
X*, std::pair<Allocator, Allocator> allocators)
{
using value_type = typename X::value_type;
using replaced_allocator_container = replace_allocator<X, Allocator>;
using replaced_allocator_container = test::replace_allocator<X, Allocator>;
using node_type = typename replaced_allocator_container::node_type;
replaced_allocator_container x1(allocators.first), x2(allocators.second);