Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forward allocators as allocator_type #22

Merged
merged 7 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions docs/tied_sequence.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ using const_reverse_iterator = std::reverse_iterator<const_iterator>;

```cpp
constexpr tied_sequence();
constexpr explicit tied_sequence(allocator_type const&);
```

**Exceptions**
Expand All @@ -58,17 +57,18 @@ No exception only if for all sequences meet all of
- `std::is_nothrow_default_constructible_v<Sequence> == true`

```cpp
constexpr explicit tied_sequence(allocator_type const& alloc) noexcept;
constexpr explicit tied_sequence(typename Sequences::allocator_type const&... alloc) noexcept;
```

Construct sequences form corresponding allocator.

```cpp
constexpr tied_sequence(size_type count, value_type const& value);
constexpr tied_sequence(size_type count, value_type const& value, allocator_type const&);
constexpr tied_sequence(size_type count, value_type const& value, allocator_type const& alloc);
constexpr tied_sequence(size_type count, value_type const& value, typename Sequences::allocator_type const&... alloc);
constexpr tied_sequence(size_type count);
constexpr tied_sequence(size_type count, allocator_type const&);
constexpr tied_sequence(size_type count, allocator_type const& alloc);
constexpr tied_sequence(size_type count, typename Sequences::allocator_type const&... alloc);
```

Expand All @@ -79,7 +79,7 @@ template <typename InputIterator>
constexpr tied_sequence(InputIterator first, InputIterator last);

template <typename InputIterator>
constexpr tied_sequence(InputIterator first, InputIterator last, allocator_type const&);
constexpr tied_sequence(InputIterator first, InputIterator last, allocator_type const& alloc);

template <typename InputIterator>
constexpr tied_sequence(InputIterator first, InputIterator last, typename Sequences::allocator_type const&... alloc);
Expand All @@ -94,15 +94,15 @@ Construct containers from `[first, last)`.

```cpp
constexpr tied_sequence(tied_sequence const& other);
constexpr tied_sequence(tied_sequence const& other, allocator_type const&);
constexpr tied_sequence(tied_sequence const& other, allocator_type const& alloc);
constexpr tied_sequence(tied_sequence const& other, typename Sequences::allocator_type const&... alloc);
```

Copy from other.

```cpp
constexpr tied_sequence(tied_sequence&& other);
constexpr tied_sequence(tied_sequence&& other, allocator_type const&);
constexpr tied_sequence(tied_sequence&& other, allocator_type const& alloc);
constexpr tied_sequence(tied_sequence&& other, typename Sequences::allocator_type const&... alloc);
```

Expand All @@ -111,7 +111,7 @@ Move entire elements from other.

```cpp
constexpr tied_sequence(std::initializer_list<value_type> init);
constexpr tied_sequence(std::initializer_list<value_type> init, allocator_type const&);
constexpr tied_sequence(std::initializer_list<value_type> init, allocator_type const& alloc);
constexpr tied_sequence(std::initializer_list<value_type> init, typename Sequences::allocator_type const&... alloc);
```

Expand Down Expand Up @@ -594,3 +594,12 @@ constexpr typename tied_sequence<Sequences...>::size_type erase_if(tied_sequence
```

Erase every elements which `pred` returned true.

### forward\_allocator
Flast marked this conversation as resolved.
Show resolved Hide resolved

```cpp
template <typename... Allocators>
/* unspecified */ forward_allocator(Allocators&&... alloc);
```

Forward allocators as `tied_sequence::allocator_type`.
45 changes: 38 additions & 7 deletions flat_map/__memory.hpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,58 @@
// Copyright (c) 2021 Kohei Takahashi
// Copyright (c) 2021,2024 Kohei Takahashi
// This software is released under the MIT License, see LICENSE.

#pragma once

#include <memory>
#include <new>
#include <tuple>
#include <type_traits>

namespace flat_map::detail
namespace flat_map
{

struct fake_allocator
namespace detail
{
template <typename>
struct rebind { using other = fake_allocator; };

template <typename AllocatorTuple>
struct fake_allocator : private AllocatorTuple
{
template <typename U>
struct rebind { using other = fake_allocator<U>; };

using value_type = void;

fake_allocator() noexcept(std::is_nothrow_default_constructible_v<AllocatorTuple>) = default;

fake_allocator(fake_allocator const&) noexcept(std::is_nothrow_copy_constructible_v<AllocatorTuple>) = default;
fake_allocator(fake_allocator&&) noexcept(std::is_nothrow_move_constructible_v<AllocatorTuple>) = default;

explicit fake_allocator(AllocatorTuple const& tuple) noexcept(std::is_nothrow_copy_constructible_v<AllocatorTuple>) : AllocatorTuple{tuple} { }
explicit fake_allocator(AllocatorTuple&& tuple) noexcept(std::is_nothrow_move_constructible_v<AllocatorTuple>) : AllocatorTuple{std::move(tuple)} { }

template <typename... Allocators>
explicit fake_allocator(std::allocator_arg_t, Allocators&&... allocs) noexcept : AllocatorTuple{std::forward<Allocators>(allocs)...} { }

fake_allocator& operator=(fake_allocator const&) noexcept(std::is_nothrow_copy_assignable_v<AllocatorTuple>) = default;
fake_allocator& operator=(fake_allocator&&) noexcept(std::is_nothrow_move_assignable_v<AllocatorTuple>) = default;

template <std::size_t I> decltype(auto) get() noexcept { return std::get<I>(static_cast<AllocatorTuple&>(*this)); }
template <std::size_t I> decltype(auto) get() const noexcept { return std::get<I>(static_cast<AllocatorTuple const&>(*this)); }

[[noreturn]]
void* allocate(std::size_t) { throw std::bad_alloc(); }
constexpr void deallocate(void*, std::size_t) { }

constexpr bool operator==(fake_allocator) const { return true; }
constexpr bool operator!=(fake_allocator) const { return false; }
constexpr bool operator==(fake_allocator const& other) const noexcept { return static_cast<AllocatorTuple const&>(*this) == static_cast<AllocatorTuple const&>(other); }
constexpr bool operator!=(fake_allocator const& other) const noexcept { return !operator==(other); }
};

} // namespace flat_map::detail

template <typename... Allocators>
auto forward_allocator(Allocators&&... alloc) noexcept
{
return detail::fake_allocator<std::tuple<Allocators...>>{std::allocator_arg, std::forward<Allocators>(alloc)...};
}

} // namespace flat_map
59 changes: 46 additions & 13 deletions flat_map/tied_sequence.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021,2023 Kohei Takahashi
// Copyright (c) 2021,2023-2024 Kohei Takahashi
// This software is released under the MIT License, see LICENSE.

#pragma once
Expand Down Expand Up @@ -282,7 +282,7 @@ class tied_sequence

public:
using value_type = std::tuple<typename Sequences::value_type...>;
using allocator_type = detail::fake_allocator;
using allocator_type = detail::fake_allocator<std::tuple<typename Sequences::allocator_type...>>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = std::tuple<typename Sequences::reference...>;
Expand All @@ -295,6 +295,22 @@ class tied_sequence
using const_reverse_iterator = std::reverse_iterator<const_iterator>;

private:
template <std::size_t... N>
constexpr tied_sequence(std::index_sequence<N...>, allocator_type const& alloc)
: _seq{alloc.template get<N>()...} { }

template <std::size_t... N>
constexpr tied_sequence(std::index_sequence<N...>, size_type count, allocator_type const& alloc)
: _seq{Sequences(count, alloc.template get<N>())...} { }

template <std::size_t... N, typename T>
constexpr tied_sequence(std::index_sequence<N...>, size_type count, T&& value, allocator_type const& alloc)
: _seq{Sequences(count, std::get<N>(std::forward<T>(value)), alloc.template get<N>())...} { }

template <std::size_t... N, typename T>
constexpr tied_sequence(std::index_sequence<N...>, T&& value, allocator_type const& alloc)
: _seq{Sequences(std::get<N>(std::forward<T>(value)), alloc.template get<N>())...} { }

template <std::size_t... N, typename T>
constexpr tied_sequence(std::index_sequence<N...>, size_type count, T&& value, typename Sequences::allocator_type const&... alloc)
: _seq{Sequences(count, std::get<N>(std::forward<T>(value)), alloc)...} { }
Expand All @@ -303,6 +319,10 @@ class tied_sequence
constexpr tied_sequence(std::index_sequence<N...>, T&& value, typename Sequences::allocator_type const&... alloc)
: _seq{Sequences(std::get<N>(std::forward<T>(value)), alloc)...} { }

template <typename InputIterator, std::size_t... N>
constexpr tied_sequence(std::index_sequence<N...> indices, InputIterator first, InputIterator last, allocator_type const& alloc)
: tied_sequence{indices, typename std::iterator_traits<InputIterator>::iterator_category{}, first, last, alloc.template get<N>()...} { }

template <typename InputIterator, std::size_t... N>
constexpr tied_sequence(std::index_sequence<N...>, std::input_iterator_tag, InputIterator, InputIterator, typename Sequences::allocator_type const&...)
{
Expand All @@ -314,6 +334,10 @@ class tied_sequence
constexpr tied_sequence(std::index_sequence<N...>, std::forward_iterator_tag, ForwardIterator first, ForwardIterator last, typename Sequences::allocator_type const&... alloc)
: _seq{Sequences(detail::unzip<N>(first), detail::unzip<N>(last), alloc)...} { }

template <std::size_t... N>
constexpr tied_sequence(std::index_sequence<N...>, std::initializer_list<value_type> init, allocator_type const& alloc)
: tied_sequence{init, alloc.template get<N>()...} { }

public:
constexpr tied_sequence() noexcept((std::is_nothrow_default_constructible_v<Sequences> && ...))
#if FLAT_MAP_WORKAROUND(FLAT_MAP_COMPILER_GCC, < FLAT_MAP_COMPILER_VERSION(10,0,0))
Expand All @@ -322,22 +346,24 @@ class tied_sequence
= default;
#endif

constexpr explicit tied_sequence(allocator_type const&) noexcept(std::is_nothrow_default_constructible_v<tied_sequence>) : tied_sequence() { }
constexpr explicit tied_sequence(allocator_type const& alloc) noexcept
: tied_sequence(std::index_sequence_for<Sequences...>{}, alloc) { }

constexpr explicit tied_sequence(typename Sequences::allocator_type const&... alloc) noexcept : _seq{alloc...} { }

constexpr tied_sequence(size_type count, value_type const& value)
: tied_sequence(count, value, typename Sequences::allocator_type{}...) { }

constexpr tied_sequence(size_type count, value_type const& value, allocator_type const&)
: tied_sequence(count, value) { }
constexpr tied_sequence(size_type count, value_type const& value, allocator_type const& alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, count, value, alloc) { }

constexpr tied_sequence(size_type count, value_type const& value, typename Sequences::allocator_type const&... alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, count, value, alloc...) { }

constexpr tied_sequence(size_type count) : tied_sequence(count, typename Sequences::allocator_type{}...) { }

constexpr tied_sequence(size_type count, allocator_type const&) : tied_sequence(count) { }
constexpr tied_sequence(size_type count, allocator_type const& alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, count, alloc) { }

constexpr tied_sequence(size_type count, typename Sequences::allocator_type const&... alloc)
: _seq{Sequences(count, alloc)...} { }
Expand All @@ -347,30 +373,34 @@ class tied_sequence
: tied_sequence(first, last, typename Sequences::allocator_type{}...) { }

template <typename InputIterator>
constexpr tied_sequence(InputIterator first, InputIterator last, allocator_type const&) : tied_sequence(first, last) { }
constexpr tied_sequence(InputIterator first, InputIterator last, allocator_type const& alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, first, last, alloc) { }

template <typename InputIterator>
constexpr tied_sequence(InputIterator first, InputIterator last, typename Sequences::allocator_type const&... alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, typename std::iterator_traits<InputIterator>::iterator_category{}, first, last, alloc...) { }

constexpr tied_sequence(tied_sequence const&) = default;

constexpr tied_sequence(tied_sequence const& other, allocator_type const&) : tied_sequence(other) { }
constexpr tied_sequence(tied_sequence const& other, allocator_type const& alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, other._seq, alloc) { }

constexpr tied_sequence(tied_sequence const& other, typename Sequences::allocator_type const&... alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, other, alloc...) { }
: tied_sequence(std::index_sequence_for<Sequences...>{}, other._seq, alloc...) { }

constexpr tied_sequence(tied_sequence&&) noexcept = default;

constexpr tied_sequence(tied_sequence&& other, allocator_type const&) : tied_sequence(std::move(other)) { }
constexpr tied_sequence(tied_sequence&& other, allocator_type const& alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, std::move(other._seq), alloc) { }

constexpr tied_sequence(tied_sequence&& other, typename Sequences::allocator_type const&... alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, std::move(other), alloc...) { }
: tied_sequence(std::index_sequence_for<Sequences...>{}, std::move(other._seq), alloc...) { }

constexpr tied_sequence(std::initializer_list<value_type> init)
: tied_sequence(init, typename Sequences::allocator_type{}...) { }

constexpr tied_sequence(std::initializer_list<value_type> init, allocator_type const&) : tied_sequence(init) { }
constexpr tied_sequence(std::initializer_list<value_type> init, allocator_type const& alloc)
: tied_sequence(std::index_sequence_for<Sequences...>{}, init, alloc) { }

constexpr tied_sequence(std::initializer_list<value_type> init, typename Sequences::allocator_type const&... alloc)
: tied_sequence(init.begin(), init.end(), alloc...) { }
Expand Down Expand Up @@ -419,7 +449,10 @@ class tied_sequence

constexpr void assign(std::initializer_list<value_type> ilist) { *this = ilist; }

constexpr allocator_type get_allocator() const noexcept { return {}; }
constexpr allocator_type get_allocator() const noexcept
{
return std::apply([](auto&... seqs) { return allocator_type{std::allocator_arg, seqs.get_allocator()...}; }, _seq);
}

constexpr reference at(size_type pos)
{
Expand Down
15 changes: 2 additions & 13 deletions test/test_case/deduction_guide.ipp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021,2023 Kohei Takahashi
// Copyright (c) 2021,2023-2024 Kohei Takahashi
// This software is released under the MIT License, see LICENSE.

#include <catch2/catch_test_macros.hpp>
Expand All @@ -7,18 +7,7 @@
#include <functional>

#include "config.hpp"

template <typename T>
struct stateful_allocator : public std::allocator<T>
{
std::string state;

// Hide std::allocator::rebind for C++17 mode.
template <typename U>
struct rebind { using other = stateful_allocator<U>; };

stateful_allocator(char const* state) : state{state} {};
};
#include "memory.hpp"

TEST_CASE("deduction guide", "[deduction guide]")
{
Expand Down
30 changes: 30 additions & 0 deletions test/test_case/memory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) 2024 Kohei Takahashi
// This software is released under the MIT License, see LICENSE.

#pragma once

template <typename T>
struct stateful_allocator : public std::allocator<T>
{
std::string state;

// Hide std::allocator::rebind for C++17 mode.
template <typename U>
struct rebind { using other = stateful_allocator<U>; };

stateful_allocator() : state{"unspecified state"} {}

stateful_allocator(char const* state) : state{state} {}

stateful_allocator(stateful_allocator const&) noexcept = default;
stateful_allocator(stateful_allocator&&) noexcept = default;

stateful_allocator& operator=(stateful_allocator const&) noexcept = default;
stateful_allocator& operator=(stateful_allocator&&) noexcept = default;

template <typename U>
stateful_allocator(stateful_allocator<U> const& other) noexcept : state{other.state} { }

template <typename U>
stateful_allocator(stateful_allocator<U>&& other) noexcept : state{std::move(other.state)} { }
};
Loading