Coverage Report

Created: 2025-08-29 06:17

/src/immer/immer/flex_vector_transient.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/detail/rbts/rrbtree.hpp>
12
#include <immer/detail/rbts/rrbtree_iterator.hpp>
13
#include <immer/memory_policy.hpp>
14
15
namespace immer {
16
17
template <typename T,
18
          typename MemoryPolicy,
19
          detail::rbts::bits_t B,
20
          detail::rbts::bits_t BL>
21
class flex_vector;
22
23
template <typename T,
24
          typename MemoryPolicy,
25
          detail::rbts::bits_t B,
26
          detail::rbts::bits_t BL>
27
class vector_transient;
28
29
/*!
30
 * Mutable version of `immer::flex_vector`.
31
 *
32
 * @rst
33
 *
34
 * Refer to :doc:`transients` to learn more about when and how to use
35
 * the mutable versions of immutable containers.
36
 *
37
 * @endrst
38
 */
39
template <typename T,
40
          typename MemoryPolicy  = default_memory_policy,
41
          detail::rbts::bits_t B = default_bits,
42
          detail::rbts::bits_t BL =
43
              detail::rbts::derive_bits_leaf<T, MemoryPolicy, B>>
44
class flex_vector_transient : MemoryPolicy::transience_t::owner
45
{
46
    using impl_t  = detail::rbts::rrbtree<T, MemoryPolicy, B, BL>;
47
    using base_t  = typename MemoryPolicy::transience_t::owner;
48
    using owner_t = typename MemoryPolicy::transience_t::owner;
49
50
public:
51
    static constexpr auto bits      = B;
52
    static constexpr auto bits_leaf = BL;
53
    using memory_policy             = MemoryPolicy;
54
55
    using value_type      = T;
56
    using reference       = const T&;
57
    using size_type       = detail::rbts::size_t;
58
    using difference_type = std::ptrdiff_t;
59
    using const_reference = const T&;
60
61
    using iterator = detail::rbts::rrbtree_iterator<T, MemoryPolicy, B, BL>;
62
    using const_iterator   = iterator;
63
    using reverse_iterator = std::reverse_iterator<iterator>;
64
65
    using persistent_type = flex_vector<T, MemoryPolicy, B, BL>;
66
67
    /*!
68
     * Default constructor.  It creates a flex_vector of `size() == 0`.  It
69
     * does not allocate memory and its complexity is @f$ O(1) @f$.
70
     */
71
44.0k
    flex_vector_transient() = default;
72
73
    /*!
74
     * Default constructor.  It creates a flex_vector with the same
75
     * contents as `v`.  It does not allocate memory and is
76
     * @f$ O(1) @f$.
77
     */
78
    flex_vector_transient(vector_transient<T, MemoryPolicy, B, BL> v)
79
        : base_t{std::move(static_cast<base_t&>(v))}
80
        , impl_{v.impl_.size,
81
                v.impl_.shift,
82
                v.impl_.root->inc(),
83
                v.impl_.tail->inc()}
84
    {
85
    }
86
87
    /*!
88
     * Returns an iterator pointing at the first element of the
89
     * collection. It does not allocate memory and its complexity is
90
     * @f$ O(1) @f$.
91
     */
92
    IMMER_NODISCARD iterator begin() const { return {impl_}; }
93
94
    /*!
95
     * Returns an iterator pointing just after the last element of the
96
     * collection. It does not allocate and its complexity is @f$ O(1) @f$.
97
     */
98
    IMMER_NODISCARD iterator end() const
99
    {
100
        return {impl_, typename iterator::end_t{}};
101
    }
102
103
    /*!
104
     * Returns an iterator that traverses the collection backwards,
105
     * pointing at the first element of the reversed collection. It
106
     * does not allocate memory and its complexity is @f$ O(1) @f$.
107
     */
108
    IMMER_NODISCARD reverse_iterator rbegin() const
109
    {
110
        return reverse_iterator{end()};
111
    }
112
113
    /*!
114
     * Returns an iterator that traverses the collection backwards,
115
     * pointing after the last element of the reversed collection. It
116
     * does not allocate memory and its complexity is @f$ O(1) @f$.
117
     */
118
    IMMER_NODISCARD reverse_iterator rend() const
119
    {
120
        return reverse_iterator{begin()};
121
    }
122
123
    /*!
124
     * Returns the number of elements in the container.  It does
125
     * not allocate memory and its complexity is @f$ O(1) @f$.
126
     */
127
4.61M
    IMMER_NODISCARD size_type size() const { return impl_.size; }
128
129
    /*!
130
     * Returns `true` if there are no elements in the container.  It
131
     * does not allocate memory and its complexity is @f$ O(1) @f$.
132
     */
133
    IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
134
135
    /*!
136
     * Returns a `const` reference to the element at position `index`.
137
     * It is undefined when @f$ 0 index \geq size() @f$.  It does not
138
     * allocate memory and its complexity is *effectively* @f$ O(1)
139
     * @f$.
140
     */
141
    reference operator[](size_type index) const { return impl_.get(index); }
142
143
    /*!
144
     * Returns a `const` reference to the element at position
145
     * `index`. It throws an `std::out_of_range` exception when @f$
146
     * index \geq size() @f$.  It does not allocate memory and its
147
     * complexity is *effectively* @f$ O(1) @f$.
148
     */
149
    reference at(size_type index) const { return impl_.get_check(index); }
150
151
    /*!
152
     * Inserts `value` at the end.  It may allocate memory and its
153
     * complexity is *effectively* @f$ O(1) @f$.
154
     */
155
    void push_back(value_type value)
156
50.5k
    {
157
50.5k
        impl_.push_back_mut(*this, std::move(value));
158
50.5k
    }
159
160
    /*!
161
     * Sets to the value `value` at position `idx`.
162
     * Undefined for `index >= size()`.
163
     * It may allocate memory and its complexity is
164
     * *effectively* @f$ O(1) @f$.
165
     */
166
    void set(size_type index, value_type value)
167
    {
168
        impl_.assoc_mut(*this, index, std::move(value));
169
    }
170
171
    /*!
172
     * Updates the vector to contain the result of the expression
173
     * `fn((*this)[idx])` at position `idx`.
174
     * Undefined for `0 >= size()`.
175
     * It may allocate memory and its complexity is
176
     * *effectively* @f$ O(1) @f$.
177
     */
178
    template <typename FnT>
179
    void update(size_type index, FnT&& fn)
180
10.0k
    {
181
10.0k
        impl_.update_mut(*this, index, std::forward<FnT>(fn));
182
10.0k
    }
183
184
    /*!
185
     * Resizes the vector to only contain the first `min(elems, size())`
186
     * elements. It may allocate memory and its complexity is
187
     * *effectively* @f$ O(1) @f$.
188
     */
189
36.0k
    void take(size_type elems) { impl_.take_mut(*this, elems); }
190
191
    /*!
192
     * Removes the first the first `min(elems, size())`
193
     * elements. It may allocate memory and its complexity is
194
     * *effectively* @f$ O(1) @f$.
195
     */
196
    void drop(size_type elems) { impl_.drop_mut(*this, elems); }
197
198
    /*!
199
     * Appends the contents of the `r` at the end.  It may allocate
200
     * memory and its complexity is:
201
     * @f$ O(log(max(size_r, size_l))) @f$
202
     */
203
    void append(flex_vector_transient& r)
204
2.23M
    {
205
2.23M
        r.owner_t::operator=(owner_t{});
206
2.23M
        concat_mut_l(impl_, *this, r.impl_);
207
2.23M
    }
208
    void append(flex_vector_transient&& r)
209
5.55k
    {
210
5.55k
        concat_mut_lr_l(impl_, *this, r.impl_, r);
211
5.55k
    }
212
213
    /*!
214
     * Prepends the contents of the `l` at the beginning.  It may
215
     * allocate memory and its complexity is:
216
     * @f$ O(log(max(size_r, size_l))) @f$
217
     */
218
    void prepend(flex_vector_transient& l)
219
35.6k
    {
220
35.6k
        l.owner_t::operator=(owner_t{});
221
35.6k
        concat_mut_r(l.impl_, impl_, *this);
222
35.6k
    }
223
    void prepend(flex_vector_transient&& l)
224
4.29k
    {
225
4.29k
        concat_mut_lr_r(l.impl_, l, impl_, *this);
226
4.29k
    }
227
228
    /*!
229
     * Returns an @a immutable form of this container, an
230
     * `immer::flex_vector`.
231
     */
232
    IMMER_NODISCARD persistent_type persistent() &
233
24.1k
    {
234
24.1k
        this->owner_t::operator=(owner_t{});
235
24.1k
        return impl_;
236
24.1k
    }
237
    IMMER_NODISCARD persistent_type persistent() && { return std::move(impl_); }
238
239
private:
240
    friend persistent_type;
241
242
    flex_vector_transient(impl_t impl)
243
95.9k
        : impl_(std::move(impl))
244
95.9k
    {
245
95.9k
    }
246
247
    impl_t impl_ = {};
248
};
249
250
} // namespace immer