Coverage Report

Created: 2026-02-26 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/immer/immer/detail/arrays/no_capacity.hpp
Line
Count
Source
1
//
2
// immer: immutable data structures for C++
3
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
4
//
5
// This software is distributed under the Boost Software License, Version 1.0.
6
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
7
//
8
9
#pragma once
10
11
#include <immer/algorithm.hpp>
12
#include <immer/config.hpp>
13
#include <immer/detail/arrays/node.hpp>
14
15
#include <cassert>
16
#include <cstddef>
17
#include <stdexcept>
18
19
namespace immer {
20
namespace detail {
21
namespace arrays {
22
23
template <typename T, typename MemoryPolicy>
24
struct no_capacity
25
{
26
    using node_t = node<T, MemoryPolicy>;
27
    using edit_t = typename MemoryPolicy::transience_t::edit;
28
    using size_t = std::size_t;
29
30
    node_t* ptr;
31
    size_t size;
32
33
    static const no_capacity& empty()
34
28.9k
    {
35
28.9k
        static const no_capacity empty_{
36
28.9k
            node_t::make_n(0),
37
28.9k
            0,
38
28.9k
        };
39
28.9k
        return empty_;
40
28.9k
    }
41
42
    no_capacity(node_t* p, size_t s)
43
53.8k
        : ptr{p}
44
53.8k
        , size{s}
45
53.8k
    {
46
53.8k
    }
47
48
    no_capacity(const no_capacity& other)
49
28.9k
        : no_capacity{other.ptr, other.size}
50
28.9k
    {
51
28.9k
        inc();
52
28.9k
    }
53
54
    no_capacity(no_capacity&& other)
55
24.9k
        : no_capacity{empty()}
56
24.9k
    {
57
24.9k
        swap(*this, other);
58
24.9k
    }
59
60
    no_capacity& operator=(const no_capacity& other)
61
    {
62
        auto next = other;
63
        swap(*this, next);
64
        return *this;
65
    }
66
67
    no_capacity& operator=(no_capacity&& other)
68
24.9k
    {
69
24.9k
        swap(*this, other);
70
24.9k
        return *this;
71
24.9k
    }
72
73
    friend void swap(no_capacity& x, no_capacity& y)
74
49.9k
    {
75
49.9k
        using std::swap;
76
49.9k
        swap(x.ptr, y.ptr);
77
49.9k
        swap(x.size, y.size);
78
49.9k
    }
79
80
53.8k
    ~no_capacity() { dec(); }
81
82
    void inc()
83
28.9k
    {
84
28.9k
        using immer::detail::get;
85
28.9k
        ptr->refs().inc();
86
28.9k
    }
87
88
    void dec()
89
53.8k
    {
90
53.8k
        using immer::detail::get;
91
53.8k
        if (ptr->refs().dec())
92
0
            node_t::delete_n(ptr, size, size);
93
53.8k
    }
94
95
    T* data() { return ptr->data(); }
96
    const T* data() const { return ptr->data(); }
97
98
    T* data_mut(edit_t e)
99
    {
100
        if (!ptr->can_mutate(e))
101
            ptr = node_t::copy_e(e, size, ptr, size);
102
        return data();
103
    }
104
105
    template <typename Iter,
106
              typename Sent,
107
              std::enable_if_t<is_forward_iterator_v<Iter> &&
108
                                   compatible_sentinel_v<Iter, Sent>,
109
                               bool> = true>
110
    static no_capacity from_range(Iter first, Sent last)
111
    {
112
        auto count = static_cast<size_t>(detail::distance(first, last));
113
        if (count == 0)
114
            return empty();
115
        else
116
            return {
117
                node_t::copy_n(count, first, last),
118
                count,
119
            };
120
    }
121
122
    static no_capacity from_fill(size_t n, T v)
123
    {
124
        return {node_t::fill_n(n, v), n};
125
    }
126
127
    template <typename U>
128
    static no_capacity from_initializer_list(std::initializer_list<U> values)
129
    {
130
        using namespace std;
131
        return from_range(begin(values), end(values));
132
    }
133
134
    template <typename Fn>
135
    void for_each_chunk(Fn&& fn) const
136
    {
137
        std::forward<Fn>(fn)(data(), data() + size);
138
    }
139
140
    template <typename Fn>
141
    bool for_each_chunk_p(Fn&& fn) const
142
    {
143
        return std::forward<Fn>(fn)(data(), data() + size);
144
    }
145
146
    const T& get(std::size_t index) const { return data()[index]; }
147
148
    const T& get_check(std::size_t index) const
149
    {
150
        if (index >= size)
151
            IMMER_THROW(std::out_of_range{"out of range"});
152
        return data()[index];
153
    }
154
155
    bool equals(const no_capacity& other) const
156
    {
157
        return ptr == other.ptr ||
158
               (size == other.size &&
159
                std::equal(data(), data() + size, other.data()));
160
    }
161
162
    no_capacity push_back(T value) const
163
7.95k
    {
164
7.95k
        auto p = node_t::copy_n(size + 1, ptr, size);
165
7.95k
        IMMER_TRY {
166
7.95k
            new (p->data() + size) T(std::move(value));
167
7.95k
            return {p, size + 1};
168
7.95k
        }
169
7.95k
        IMMER_CATCH (...) {
170
0
            node_t::delete_n(p, size, size + 1);
171
0
            IMMER_RETHROW;
172
0
        }
173
7.95k
    }
174
175
    no_capacity assoc(std::size_t idx, T value) const
176
    {
177
        auto p = node_t::copy_n(size, ptr, size);
178
        IMMER_TRY {
179
            p->data()[idx] = std::move(value);
180
            return {p, size};
181
        }
182
        IMMER_CATCH (...) {
183
            node_t::delete_n(p, size, size);
184
            IMMER_RETHROW;
185
        }
186
    }
187
188
    template <typename Fn>
189
    no_capacity update(std::size_t idx, Fn&& op) const
190
10.1k
    {
191
10.1k
        auto p = node_t::copy_n(size, ptr, size);
192
10.1k
        IMMER_TRY {
193
10.1k
            auto& elem = p->data()[idx];
194
10.1k
            elem       = std::forward<Fn>(op)(std::move(elem));
195
10.1k
            return {p, size};
196
10.1k
        }
197
10.1k
        IMMER_CATCH (...) {
198
0
            node_t::delete_n(p, size, size);
199
0
            IMMER_RETHROW;
200
0
        }
201
10.1k
    }
202
203
    no_capacity take(std::size_t sz) const
204
2.22k
    {
205
2.22k
        auto p = node_t::copy_n(sz, ptr, sz);
206
2.22k
        return {p, sz};
207
2.22k
    }
208
};
209
210
} // namespace arrays
211
} // namespace detail
212
} // namespace immer