Sequoia
Loading...
Searching...
No Matches
MonotonicSequence.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2019. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
8#pragma once
9
17
18#include <vector>
19
20namespace sequoia::maths
21{
22 struct unsafe_t {};
23
24 template<class T, class C, class Compare> class monotonic_sequence_base
25 {
26 public:
27 using value_type = T;
28 using container_type = C;
29 using compare_type = Compare;
30 using size_type = typename C::size_type;
31
32 using const_iterator = typename C::const_iterator;
33 using const_reverse_iterator = typename C::const_reverse_iterator;
34
35 constexpr monotonic_sequence_base() = default;
36
37 constexpr monotonic_sequence_base(std::initializer_list<T> list) : monotonic_sequence_base{static_type{}, list}
38 {}
39
40 constexpr monotonic_sequence_base(C c) : m_Sequence{std::move(c)}
41 {
42 check();
43 }
44
45 constexpr monotonic_sequence_base(const monotonic_sequence_base&) = default;
46
47 [[nodiscard]]
48 constexpr size_type size() const noexcept { return m_Sequence.size(); }
49
50 [[nodiscard]]
51 constexpr bool empty() const noexcept { return m_Sequence.empty(); }
52
53 [[nodiscard]]
54 constexpr const_iterator begin() const noexcept { return m_Sequence.begin(); }
55
56 [[nodiscard]]
57 constexpr const_iterator end() const noexcept { return m_Sequence.end(); }
58
59 [[nodiscard]]
60 constexpr const_iterator cbegin() const noexcept { return m_Sequence.cbegin(); }
61
62 [[nodiscard]]
63 constexpr const_iterator cend() const noexcept { return m_Sequence.cend(); }
64
65 [[nodiscard]]
66 constexpr const_reverse_iterator rbegin() const noexcept { return m_Sequence.rbegin(); }
67
68 [[nodiscard]]
69 constexpr const_reverse_iterator rend() const noexcept { return m_Sequence.rend(); }
70
71 [[nodiscard]]
72 constexpr const_reverse_iterator crbegin() const noexcept { return m_Sequence.crbegin(); }
73
74 [[nodiscard]]
75 constexpr const_reverse_iterator crend() const noexcept { return m_Sequence.crend(); }
76
77 [[nodiscard]]
78 constexpr const T& operator[](const size_type i) const { return m_Sequence[i]; }
79
80 [[nodiscard]]
81 constexpr const T& back() const { return *(end() - 1); }
82
83 [[nodiscard]]
84 constexpr const T& front() const { return *begin(); }
85
86 template<class UnaryOp>
87 constexpr void mutate(const_iterator first, const_iterator last, UnaryOp op)
88 {
89 if(first != last)
90 {
91 auto tmp{m_Sequence};
92 auto f{tmp.begin() + std::ranges::distance(cbegin(), first)};
93 auto l{tmp.begin() + std::ranges::distance(cbegin(), last)};
94
95 for(auto i{f}; i != l; ++i)
96 {
97 *i = op(*i);
98 }
99
100 if(f != tmp.begin()) --f;
101 if(l != tmp.end()) ++l;
102
103 while((f != l) && (f + 1) != tmp.end())
104 {
105 if(Compare{}(*f, *(f+1)))
106 throw std::logic_error("monotonic_sequence::mutate - monotonicity violated");
107
108 ++f;
109 }
110
111 m_Sequence = std::move(tmp);
112 }
113 }
114
115 template<class UnaryOp>
116 constexpr void mutate(unsafe_t, const_iterator first, const_iterator last, UnaryOp op)
117 {
118 while(first != last)
119 {
120 auto pos{m_Sequence.begin() + std::ranges::distance(cbegin(), first++)};
121 *pos = op(*pos);
122 }
123 }
124
125 [[nodiscard]]
126 friend bool operator==(const monotonic_sequence_base& lhs, const monotonic_sequence_base& rhs) noexcept = default;
127
128 protected:
129 template<alloc Allocator>
130 constexpr explicit monotonic_sequence_base(const Allocator& allocator) noexcept
131 : m_Sequence(allocator)
132 {}
133
134 template<alloc Allocator>
135 constexpr monotonic_sequence_base(std::initializer_list<T> list, const Allocator& allocator)
136 : m_Sequence{list, allocator}
137 {
138 check();
139 }
140
141 constexpr monotonic_sequence_base(monotonic_sequence_base&&) noexcept = default;
142
143 template<alloc Allocator>
144 constexpr monotonic_sequence_base(const monotonic_sequence_base& s, const Allocator& allocator)
145 : m_Sequence{s.m_Sequence, allocator}
146 {}
147
148 template<alloc Allocator>
149 constexpr monotonic_sequence_base(monotonic_sequence_base&& s, const Allocator& allocator)
150 : m_Sequence{std::move(s.m_Sequence), allocator}
151 {}
152
153 ~monotonic_sequence_base() = default;
154
155 constexpr monotonic_sequence_base& operator=(const monotonic_sequence_base&) = default;
156 constexpr monotonic_sequence_base& operator=(monotonic_sequence_base&&) = default;
157
158 constexpr void swap(monotonic_sequence_base& other) noexcept(impl::noexcept_spec_v<C>)
159 {
160 std::ranges::swap(m_Sequence, other.m_Sequence);
161 }
162
163 auto get_allocator() const
164 {
165 return m_Sequence.get_allocator();
166 }
167
168 void push_back(T v)
169 {
170 if(!m_Sequence.empty() && Compare{}(m_Sequence.back(), v))
171 throw std::logic_error{"monotonic_sequence_base::push_back - monotonicity violated"};
172
173 m_Sequence.push_back(std::move(v));
174 }
175
176 const_iterator insert(const_iterator pos, T v)
177 {
178 if(((pos != cend()) && Compare{}(v, *pos)) || ((pos != cbegin()) && Compare{}(*(pos-1), v)))
179 {
180 throw std::logic_error{"monotonic_sequence_base::insert - monotonicity violated"};
181 }
182
183 return m_Sequence.insert(pos, std::move(v));
184 }
185
186 const_iterator erase(const_iterator pos)
187 {
188 return m_Sequence.erase(pos);
189 }
190
191 const_iterator erase(const_iterator first, const_iterator last)
192 {
193 return m_Sequence.erase(first, last);
194 }
195
196 void reserve(const size_type new_cap)
197 {
198 m_Sequence.reserve(new_cap);
199 }
200
201 size_type capacity() const noexcept
202 {
203 return m_Sequence.capacity();
204 }
205
206 void shrink_to_fit()
207 {
208 m_Sequence.shrink_to_fit();
209 }
210
211 void clear() noexcept
212 {
213 m_Sequence.clear();
214 }
215
216 private:
218
219 C m_Sequence;
220
221 constexpr monotonic_sequence_base(std::false_type, std::initializer_list<T> list) : m_Sequence{list}
222 {
223 check();
224 }
225
226 constexpr monotonic_sequence_base(std::true_type, std::initializer_list<T> list)
227 : m_Sequence{utilities::to_array<T, static_type::size()>(list)}
228 {
229 check();
230 }
231
232 constexpr void check()
233 {
234 if(size() > 1)
235 {
236 for(auto i{begin()+1}; i != end(); ++i)
237 {
238 if(Compare{}(*(i-1), *i))
239 throw std::logic_error("monotonic_sequence_base::monotonic_sequence_base - monotonicity violated");
240 }
241 }
242 }
243 };
244
245
246 template<class T, class Compare=std::ranges::less, class C=std::vector<T>>
247 class monotonic_sequence : public monotonic_sequence_base<T, C, Compare>
248 {
250 public:
251 static_assert(has_allocator_type_v<C>);
252
253 using allocator_type = typename C::allocator_type;
254
255 monotonic_sequence() = default;
256
257 explicit monotonic_sequence(const allocator_type& allocator)
259 {}
260
261 monotonic_sequence(std::initializer_list<T> list, const allocator_type& allocator=allocator_type{})
263 {}
264
265 monotonic_sequence(const monotonic_sequence&) = default;
266
267 monotonic_sequence(const monotonic_sequence& s, const allocator_type& allocator)
269 {}
270
271 monotonic_sequence(monotonic_sequence&&) noexcept = default;
272
273 monotonic_sequence(monotonic_sequence&& s, const allocator_type& allocator)
274 : monotonic_sequence_base<T, C, Compare>{std::move(s), allocator}
275 {}
276
277 ~monotonic_sequence() = default;
278
279 monotonic_sequence& operator=(const monotonic_sequence&) = default;
280 monotonic_sequence& operator=(monotonic_sequence&&) = default;
281
282 friend void swap(monotonic_sequence& lhs, monotonic_sequence& rhs) noexcept(noexcept(lhs.swap(rhs)))
283 {
284 lhs.swap(rhs);
285 }
286
287 allocator_type get_allocator() const
288 {
289 return base_t::get_allocator();
290 }
291
292 using base_t::push_back;
293 using base_t::insert;
294 using base_t::erase;
295 using base_t::reserve;
296 using base_t::capacity;
297 using base_t::shrink_to_fit;
298 using base_t::clear;
299 };
300
301 template<class T, std::size_t N, class Compare=std::ranges::less>
302 class static_monotonic_sequence : public monotonic_sequence_base<T, std::array<T, N>, Compare>
303 {
304 public:
305 using monotonic_sequence_base<T, std::array<T, N>, Compare>::monotonic_sequence_base;
306 };
307}
A collection of constexpr algorithms.
Utility to convert an initializer_list into an array, potentially transforming the initializer_list i...
Implementation details for monotonic sequences.
Definition: MonotonicSequence.hpp:25
Definition: MonotonicSequence.hpp:248
Definition: MonotonicSequence.hpp:303
Definition: MonotonicSequenceDetails.hpp:18
Definition: MonotonicSequence.hpp:22