1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
//
// immer: immutable data structures for C++
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
//
// This software is distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
//
#pragma once
#include <immer/detail/combine_standard_layout.hpp>
#include <immer/detail/type_traits.hpp>
#include <immer/detail/util.hpp>
#include <limits>
namespace immer {
namespace detail {
namespace arrays {
template <typename T, typename MemoryPolicy>
struct node
{
using memory = MemoryPolicy;
using heap = typename MemoryPolicy::heap::type;
using transience = typename memory::transience_t;
using refs_t = typename memory::refcount;
using ownee_t = typename transience::ownee;
using node_t = node;
using edit_t = typename transience::edit;
struct data_t
{
aligned_storage_for<T> buffer;
};
using impl_t = combine_standard_layout_t<data_t, refs_t, ownee_t>;
impl_t impl;
constexpr static std::size_t sizeof_n(size_t count)
{
return immer_offsetof(impl_t, d.buffer) +
sizeof(T) * (count == 0 ? 1 : count);
}
refs_t& refs() const { return auto_const_cast(get<refs_t>(impl)); }
const ownee_t& ownee() const { return get<ownee_t>(impl); }
ownee_t& ownee() { return get<ownee_t>(impl); }
const T* data() const { return reinterpret_cast<const T*>(&impl.d.buffer); }
T* data() { return reinterpret_cast<T*>(&impl.d.buffer); }
bool can_mutate(edit_t e) const
{
return refs().unique() || ownee().can_mutate(e);
}
static void delete_n(node_t* p, size_t sz, size_t cap)
{
destroy_n(p->data(), sz);
heap::deallocate(sizeof_n(cap), p);
}
static node_t* make_n(size_t n)
{
return new (heap::allocate(sizeof_n(n))) node_t{};
}
static node_t* make_e(edit_t e, size_t n)
{
auto p = make_n(n);
p->ownee() = e;
return p;
}
static node_t* fill_n(size_t n, T v)
{
auto p = make_n(n);
try {
std::uninitialized_fill_n(p->data(), n, v);
return p;
} catch (...) {
heap::deallocate(sizeof_n(n), p);
throw;
}
}
template <typename Iter,
typename Sent,
std::enable_if_t<detail::compatible_sentinel_v<Iter, Sent>,
bool> = true>
static node_t* copy_n(size_t n, Iter first, Sent last)
{
auto p = make_n(n);
try {
uninitialized_copy(first, last, p->data());
return p;
} catch (...) {
heap::deallocate(sizeof_n(n), p);
throw;
}
}
static node_t* copy_n(size_t n, node_t* p, size_t count)
{
return copy_n(n, p->data(), p->data() + count);
}
template <typename Iter>
static node_t* copy_e(edit_t e, size_t n, Iter first, Iter last)
{
auto p = copy_n(n, first, last);
p->ownee() = e;
return p;
}
static node_t* copy_e(edit_t e, size_t n, node_t* p, size_t count)
{
return copy_e(e, n, p->data(), p->data() + count);
}
};
} // namespace arrays
} // namespace detail
} // namespace immer
|