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/memory_policy.hpp> |
12 | #include <immer/detail/arrays/with_capacity.hpp> |
13 | |
14 | namespace immer { |
15 | |
16 | template <typename T, typename MemoryPolicy> |
17 | class array; |
18 | |
19 | /*! |
20 | * Mutable version of `immer::array`. |
21 | * |
22 | * @rst |
23 | * |
24 | * Refer to :doc:`transients` to learn more about when and how to use |
25 | * the mutable versions of immutable containers. |
26 | * |
27 | * @endrst |
28 | */ |
29 | template <typename T, typename MemoryPolicy = default_memory_policy> |
30 | class array_transient |
31 | : MemoryPolicy::transience_t::owner |
32 | { |
33 | using impl_t = detail::arrays::with_capacity<T, MemoryPolicy>; |
34 | using impl_no_capacity_t = detail::arrays::no_capacity<T, MemoryPolicy>; |
35 | using owner_t = typename MemoryPolicy::transience_t::owner; |
36 | |
37 | public: |
38 | using value_type = T; |
39 | using reference = const T&; |
40 | using size_type = std::size_t; |
41 | using difference_type = std::ptrdiff_t; |
42 | using const_reference = const T&; |
43 | |
44 | using iterator = const T*; |
45 | using const_iterator = iterator; |
46 | using reverse_iterator = std::reverse_iterator<iterator>; |
47 | |
48 | using memory_policy = MemoryPolicy; |
49 | using persistent_type = array<T, MemoryPolicy>; |
50 | |
51 | /*! |
52 | * Default constructor. It creates a mutable array of `size() == |
53 | * 0`. It does not allocate memory and its complexity is |
54 | * @f$ O(1) @f$. |
55 | */ |
56 | array_transient() = default; |
57 | |
58 | /*! |
59 | * Returns an iterator pointing at the first element of the |
60 | * collection. It does not allocate memory and its complexity is |
61 | * @f$ O(1) @f$. |
62 | */ |
63 | IMMER_NODISCARD iterator begin() const { return impl_.data(); } |
64 | |
65 | /*! |
66 | * Returns an iterator pointing just after the last element of the |
67 | * collection. It does not allocate and its complexity is @f$ O(1) @f$. |
68 | */ |
69 | IMMER_NODISCARD iterator end() const { return impl_.data() + impl_.size; } |
70 | |
71 | /*! |
72 | * Returns an iterator that traverses the collection backwards, |
73 | * pointing at the first element of the reversed collection. It |
74 | * does not allocate memory and its complexity is @f$ O(1) @f$. |
75 | */ |
76 | IMMER_NODISCARD reverse_iterator rbegin() const { return reverse_iterator{end()}; } |
77 | |
78 | /*! |
79 | * Returns an iterator that traverses the collection backwards, |
80 | * pointing after the last element of the reversed collection. It |
81 | * does not allocate memory and its complexity is @f$ O(1) @f$. |
82 | */ |
83 | IMMER_NODISCARD reverse_iterator rend() const { return reverse_iterator{begin()}; } |
84 | |
85 | /*! |
86 | * Returns the number of elements in the container. It does |
87 | * not allocate memory and its complexity is @f$ O(1) @f$. |
88 | */ |
89 | IMMER_NODISCARD std::size_t size() const { return impl_.size; } |
90 | |
91 | /*! |
92 | * Returns `true` if there are no elements in the container. It |
93 | * does not allocate memory and its complexity is @f$ O(1) @f$. |
94 | */ |
95 | IMMER_NODISCARD bool empty() const { return impl_.size == 0; } |
96 | |
97 | /*! |
98 | * Access the raw data. |
99 | */ |
100 | IMMER_NODISCARD const T* data() const { return impl_.data(); } |
101 | |
102 | /*! |
103 | * Provide mutable access to the raw underlaying data. |
104 | */ |
105 | IMMER_NODISCARD T* data_mut() { return impl_.data_mut(*this); } |
106 | |
107 | /*! |
108 | * Access the last element. |
109 | */ |
110 | IMMER_NODISCARD const T& back() const { return data()[size() - 1]; } |
111 | |
112 | /*! |
113 | * Access the first element. |
114 | */ |
115 | IMMER_NODISCARD const T& front() const { return data()[0]; } |
116 | |
117 | /*! |
118 | * Returns a `const` reference to the element at position `index`. |
119 | * It is undefined when @f$ 0 index \geq size() @f$. It does not |
120 | * allocate memory and its complexity is *effectively* @f$ O(1) |
121 | * @f$. |
122 | */ |
123 | reference operator[] (size_type index) const |
124 | { return impl_.get(index); } |
125 | |
126 | /*! |
127 | * Returns a `const` reference to the element at position |
128 | * `index`. It throws an `std::out_of_range` exception when @f$ |
129 | * index \geq size() @f$. It does not allocate memory and its |
130 | * complexity is *effectively* @f$ O(1) @f$. |
131 | */ |
132 | reference at(size_type index) const |
133 | { return impl_.get_check(index); } |
134 | |
135 | /*! |
136 | * Inserts `value` at the end. It may allocate memory and its |
137 | * complexity is *effectively* @f$ O(1) @f$. |
138 | */ |
139 | void push_back(value_type value) |
140 | { impl_.push_back_mut(*this, std::move(value)); } |
141 | |
142 | /*! |
143 | * Sets to the value `value` at position `idx`. |
144 | * Undefined for `index >= size()`. |
145 | * It may allocate memory and its complexity is |
146 | * *effectively* @f$ O(1) @f$. |
147 | */ |
148 | void set(size_type index, value_type value) |
149 | { impl_.assoc_mut(*this, index, std::move(value)); } |
150 | |
151 | /*! |
152 | * Updates the array to contain the result of the expression |
153 | * `fn((*this)[idx])` at position `idx`. |
154 | * Undefined for `0 >= size()`. |
155 | * It may allocate memory and its complexity is |
156 | * *effectively* @f$ O(1) @f$. |
157 | */ |
158 | template <typename FnT> |
159 | void update(size_type index, FnT&& fn) |
160 | { impl_.update_mut(*this, index, std::forward<FnT>(fn)); } |
161 | |
162 | /*! |
163 | * Resizes the array to only contain the first `min(elems, size())` |
164 | * elements. It may allocate memory and its complexity is |
165 | * *effectively* @f$ O(1) @f$. |
166 | */ |
167 | void take(size_type elems) |
168 | { impl_.take_mut(*this, elems); } |
169 | |
170 | /*! |
171 | * Returns an @a immutable form of this container, an |
172 | * `immer::array`. |
173 | */ |
174 | IMMER_NODISCARD persistent_type persistent() & |
175 | { |
176 | this->owner_t::operator=(owner_t{}); |
177 | return persistent_type{ impl_ }; |
178 | } |
179 | IMMER_NODISCARD persistent_type persistent() && |
180 | { return persistent_type{ std::move(impl_) }; } |
181 | |
182 | private: |
183 | friend persistent_type; |
184 | |
185 | array_transient(impl_t impl) |
186 | : impl_(std::move(impl)) |
187 | {} |
188 | |
189 | impl_t impl_ = impl_t::empty(); |
190 | }; |
191 | |
192 | } // namespace immer |
193 | |