Skip to content

Commit

Permalink
Fix constructors for custom container
Browse files Browse the repository at this point in the history
Previously I (wrongly) used containers for the construction of maps when
a custom container was specified. That's not really how it is intended,
the parameter should still be an allocator.

This fixes that issues, so now its possible to copy/move etc. maps when
a custom container is used. That container needs the constructors that
accept an allocator.

I had to bump version by a major number to 2.0.0 because this is an
incompatible API change.
  • Loading branch information
martinus committed Oct 8, 2022
1 parent 0304ad3 commit a7ece06
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 40 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.12)
project("unordered_dense"
VERSION 1.4.0
VERSION 2.0.0
DESCRIPTION "A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion"
HOMEPAGE_URL "https://github.com/martinus/unordered_dense")

Expand Down
61 changes: 27 additions & 34 deletions include/ankerl/unordered_dense.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
///////////////////////// ankerl::unordered_dense::{map, set} /////////////////////////

// A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion.
// Version 1.4.0
// Version 2.0.0
// https://github.com/martinus/unordered_dense
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Expand Down Expand Up @@ -30,8 +30,8 @@
#define ANKERL_UNORDERED_DENSE_H

// see https://semver.org/spec/v2.0.0.html
#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 1 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes
#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 4 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality
#define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 2 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes
#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality
#define ANKERL_UNORDERED_DENSE_VERSION_PATCH 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes

// API versioning with inline namespace, see https://www.foonathan.net/2018/11/inline-namespaces/
Expand Down Expand Up @@ -749,48 +749,44 @@ class table {
explicit table(size_t /*bucket_count*/,
Hash const& hash = Hash(),
KeyEqual const& equal = KeyEqual(),
AllocatorOrContainer const& alloc_or_container = AllocatorOrContainer())
allocator_type const& alloc_or_container = allocator_type())
: m_values(alloc_or_container)
, m_hash(hash)
, m_equal(equal) {
// If alloc_or_container is a container with elements, we don't want the data that was in it
m_values.clear();
}
, m_equal(equal) {}

table(size_t bucket_count, AllocatorOrContainer const& alloc_or_container)
: table(bucket_count, Hash(), KeyEqual(), alloc_or_container) {}
table(size_t bucket_count, allocator_type const& alloc)
: table(bucket_count, Hash(), KeyEqual(), alloc) {}

table(size_t bucket_count, Hash const& hash, AllocatorOrContainer const& alloc_or_container)
: table(bucket_count, hash, KeyEqual(), alloc_or_container) {}
table(size_t bucket_count, Hash const& hash, allocator_type const& alloc)
: table(bucket_count, hash, KeyEqual(), alloc) {}

explicit table(AllocatorOrContainer const& alloc_or_container)
: table(0, Hash(), KeyEqual(), alloc_or_container) {}
explicit table(allocator_type const& alloc)
: table(0, Hash(), KeyEqual(), alloc) {}

template <class InputIt>
table(InputIt first,
InputIt last,
size_type bucket_count = 0,
Hash const& hash = Hash(),
KeyEqual const& equal = KeyEqual(),
AllocatorOrContainer const& alloc_or_container = AllocatorOrContainer())
: table(bucket_count, hash, equal, alloc_or_container) {
allocator_type const& alloc = allocator_type())
: table(bucket_count, hash, equal, alloc) {
insert(first, last);
}

template <class InputIt>
table(InputIt first, InputIt last, size_type bucket_count, AllocatorOrContainer const& alloc_or_container)
: table(first, last, bucket_count, Hash(), KeyEqual(), alloc_or_container) {}
table(InputIt first, InputIt last, size_type bucket_count, allocator_type const& alloc)
: table(first, last, bucket_count, Hash(), KeyEqual(), alloc) {}

template <class InputIt>
table(
InputIt first, InputIt last, size_type bucket_count, Hash const& hash, AllocatorOrContainer const& alloc_or_container)
: table(first, last, bucket_count, hash, KeyEqual(), alloc_or_container) {}
table(InputIt first, InputIt last, size_type bucket_count, Hash const& hash, allocator_type const& alloc)
: table(first, last, bucket_count, hash, KeyEqual(), alloc) {}

table(table const& other)
: table(other, other.m_values.get_allocator()) {}

table(table const& other, AllocatorOrContainer const& alloc_or_container)
: m_values(other.m_values, alloc_or_container)
table(table const& other, allocator_type const& alloc)
: m_values(other.m_values, alloc)
, m_max_load_factor(other.m_max_load_factor)
, m_hash(other.m_hash)
, m_equal(other.m_equal) {
Expand All @@ -800,8 +796,8 @@ class table {
table(table&& other) noexcept
: table(std::move(other), other.m_values.get_allocator()) {}

table(table&& other, AllocatorOrContainer const& alloc_or_container) noexcept
: m_values(std::move(other.m_values), alloc_or_container)
table(table&& other, allocator_type const& alloc) noexcept
: m_values(std::move(other.m_values), alloc)
, m_buckets(std::exchange(other.m_buckets, nullptr))
, m_num_buckets(std::exchange(other.m_num_buckets, 0))
, m_max_bucket_capacity(std::exchange(other.m_max_bucket_capacity, 0))
Expand All @@ -816,19 +812,16 @@ class table {
size_t bucket_count = 0,
Hash const& hash = Hash(),
KeyEqual const& equal = KeyEqual(),
AllocatorOrContainer const& alloc_or_container = AllocatorOrContainer())
: table(bucket_count, hash, equal, alloc_or_container) {
allocator_type const& alloc = allocator_type())
: table(bucket_count, hash, equal, alloc) {
insert(ilist);
}

table(std::initializer_list<value_type> ilist, size_type bucket_count, AllocatorOrContainer const& alloc_or_container)
: table(ilist, bucket_count, Hash(), KeyEqual(), alloc_or_container) {}
table(std::initializer_list<value_type> ilist, size_type bucket_count, allocator_type const& alloc)
: table(ilist, bucket_count, Hash(), KeyEqual(), alloc) {}

table(std::initializer_list<value_type> init,
size_type bucket_count,
Hash const& hash,
AllocatorOrContainer const& alloc_or_container)
: table(init, bucket_count, hash, KeyEqual(), alloc_or_container) {}
table(std::initializer_list<value_type> init, size_type bucket_count, Hash const& hash, allocator_type const& alloc)
: table(init, bucket_count, hash, KeyEqual(), alloc) {}

~table() {
auto ba = bucket_alloc(m_values.get_allocator());
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#

project('unordered_dense', 'cpp',
version: '1.4.0',
version: '2.0.0',
license: 'MIT',
default_options : ['cpp_std=c++17', 'warning_level=3', 'werror=true'])

Expand Down
6 changes: 6 additions & 0 deletions test/unit/custom_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ TEST_CASE("custom_container") {

REQUIRE(std::is_same_v<std::deque<std::pair<int, std::string>>, typename map_t::value_container_type>);
std::deque<std::pair<int, std::string>> container = std::move(map).extract();

auto m2 = map_t();
m2 = map;

auto map2 = map;
std::swap(map2, map);
}
2 changes: 1 addition & 1 deletion test/unit/custom_container_boost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ TEST_CASE("boost_container_vector") {
using map_t =
ankerl::unordered_dense::map<int, std::string, ankerl::unordered_dense::hash<int>, std::equal_to<int>, shmem_vector>;

auto map = map_t{shmem_vector{shmem_allocator{segment.get_segment_manager()}}};
auto map = map_t{shmem_allocator{segment.get_segment_manager()}};

for (int i = 0; i < 100; ++i) {
map.try_emplace(i, std::to_string(i));
Expand Down
6 changes: 3 additions & 3 deletions test/unit/namespace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

#include <doctest.h>

static_assert(std::is_same_v<ankerl::unordered_dense::v1_4_0::map<int, int>, ankerl::unordered_dense::map<int, int>>);
static_assert(std::is_same_v<ankerl::unordered_dense::v1_4_0::hash<int>, ankerl::unordered_dense::hash<int>>);
static_assert(std::is_same_v<ankerl::unordered_dense::v2_0_0::map<int, int>, ankerl::unordered_dense::map<int, int>>);
static_assert(std::is_same_v<ankerl::unordered_dense::v2_0_0::hash<int>, ankerl::unordered_dense::hash<int>>);

TEST_CASE("version_namespace") {
auto map = ankerl::unordered_dense::v1_4_0::map<int, int>{};
auto map = ankerl::unordered_dense::v2_0_0::map<int, int>{};
REQUIRE(map.empty());
}

0 comments on commit a7ece06

Please sign in to comment.