Embedded Template Library 1.0
multi_range.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2020 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_MULTI_LOOP_INCLUDED
32#define ETL_MULTI_LOOP_INCLUDED
33
34#include "platform.h"
35#include "nullptr.h"
36#include "functional.h"
37#include "exception.h"
38#include "error_handler.h"
39
40namespace etl
41{
42 //***************************************************************************
44 //***************************************************************************
46 {
47 public:
48
49 multi_range_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
50 : exception(reason_, file_name_, line_number_)
51 {
52 }
53 };
54
55 //***************************************************************************
57 //***************************************************************************
59 {
60 public:
61
62 multi_range_circular_reference(string_type file_name_, numeric_type line_number_)
63 : etl::multi_range_exception(ETL_ERROR_TEXT("multi_range:circular reference", ETL_MULTI_LOOP_FILE_ID"A"), file_name_, line_number_)
64 {
65 }
66 };
67
68 //***************************************************************************
70 //***************************************************************************
72 {
73 public:
74
75 //***************************************************************************
77 //***************************************************************************
79 {
80 ETL_ASSERT(is_valid(inner_range), ETL_ERROR(multi_range_circular_reference));
81
82 // Remember what the next range was.
83 imulti_range* next = inner;
84
85 // Append the new range
86 inner = &inner_range;
87
88 // Link to the original next range.
89 inner_range.set_last(next);
90
91 return *this;
92 }
93
94 //***************************************************************************
96 //***************************************************************************
98 {
99 ETL_ASSERT(is_valid(inner_range), ETL_ERROR(multi_range_circular_reference));
100
101 if (inner != ETL_NULLPTR)
102 {
103 inner->append(inner_range);
104 }
105 else
106 {
107 inner = &inner_range;
108 }
109
110 return *this;
111 }
112
113 //***************************************************************************
115 //***************************************************************************
116 void detach()
117 {
118 inner = ETL_NULLPTR;
119 }
120
121 //***************************************************************************
123 //***************************************************************************
125 {
126 if (inner != ETL_NULLPTR)
127 {
128 inner->detach_all();
129 }
130
131 detach();
132 }
133
134 //***************************************************************************
136 //***************************************************************************
137 bool completed() const
138 {
139 return has_completed;
140 }
141
142 //***************************************************************************
144 //***************************************************************************
145 size_t number_of_ranges() const
146 {
147 size_t count = 1UL;
148
149 imulti_range* p_range = inner;
150
151 while (p_range != ETL_NULLPTR)
152 {
153 ++count;
154 p_range = p_range->inner;
155 }
156
157 return count;
158 }
159
160 //***************************************************************************
162 //***************************************************************************
164 {
165 size_t count = 0UL;
166
167 for (start(); !completed(); next())
168 {
169 ++count;
170 }
171
172 return count;
173 }
174
175 //***************************************************************************
177 //***************************************************************************
178 virtual void next() = 0;
179 virtual void start() = 0;
180
181 protected:
182
183 //***************************************************************************
185 //***************************************************************************
187 : has_completed(true)
188 , inner(ETL_NULLPTR)
189 {
190 }
191
192 //***************************************************************************
194 //***************************************************************************
195 bool is_valid(imulti_range& inner_range)
196 {
197 imulti_range* range = &inner_range;
198
199 while (range != ETL_NULLPTR)
200 {
201 if (range == this)
202 {
203 return false;
204 }
205
206 range = range->inner;
207 }
208
209 return true;
210 }
211
212 //***************************************************************************
214 //***************************************************************************
216 {
217 // Find the last range.
218 imulti_range* range = this;
219
220 while (range->inner != ETL_NULLPTR)
221 {
222 range = range->inner;
223 }
224
225 range->inner = next;
226 }
227
228 bool has_completed;
229 imulti_range* inner;
230 };
231
232 //***************************************************************************
235 //***************************************************************************
236 template <typename T>
238 {
239 public:
240
241 typedef T value_type;
242 typedef const T& const_reference;
243
244 //***************************************************************************
246 //***************************************************************************
248 {
249 typedef T value_type;
250
251 virtual void operator()(value_type& value) = 0;
252 };
253
254 //***************************************************************************
256 //***************************************************************************
257 struct forward_step : public step_type
258 {
259 typedef T value_type;
260
261 virtual void operator()(value_type& value)
262 {
263 ++value;
264 }
265 };
266
267 //***************************************************************************
269 //***************************************************************************
271 {
272 typedef T value_type;
273
274 explicit forward_step_by(const value_type& step_value_)
275 : step_value(step_value_)
276 {
277 }
278
279 virtual void operator()(value_type& value)
280 {
281 value += step_value;
282 }
283
284 const value_type step_value;
285 };
286
287 //***************************************************************************
289 //***************************************************************************
290 struct reverse_step : public step_type
291 {
292 typedef T value_type;
293
294 virtual void operator()(value_type& value)
295 {
296 --value;
297 }
298 };
299
300 //***************************************************************************
302 //***************************************************************************
304 {
305 typedef T value_type;
306
307 explicit reverse_step_by(const value_type& step_value_)
308 : step_value(step_value_)
309 {
310 }
311
312 virtual void operator()(value_type& value)
313 {
314 value -= step_value;
315 }
316
317 const value_type step_value;
318 };
319
320 //***************************************************************************
322 //***************************************************************************
324 {
325 typedef T value_type;
326
327 virtual bool operator()(const value_type& current, const value_type& last) const = 0;
328 };
329
330 //***************************************************************************
332 //***************************************************************************
334 {
335 typedef T value_type;
336
337 virtual bool operator()(const value_type& current, const value_type& last) const ETL_OVERRIDE
338 {
339 return etl::not_equal_to<value_type>()(current, last);
340 }
341 };
342
343 //***************************************************************************
345 //***************************************************************************
347 {
348 typedef T value_type;
349
350 virtual bool operator()(const value_type& current, const value_type& last) const ETL_OVERRIDE
351 {
352 return etl::less<value_type>()(current, last);
353 }
354 };
355
356 //***************************************************************************
358 //***************************************************************************
360 {
361 typedef T value_type;
362
363 virtual bool operator()(const value_type& current, const value_type& last) const ETL_OVERRIDE
364 {
365 return etl::greater<value_type>()(current, last);
366 }
367 };
368
369 //***************************************************************************
373 //***************************************************************************
374 multi_range(value_type first_,
375 value_type last_)
376 : first(first_)
377 , last(last_)
378 , current(first_)
379 , p_stepper(&default_stepper)
380 , p_compare(&default_compare)
381 {
382 }
383
384 //***************************************************************************
388 //***************************************************************************
389 multi_range(value_type first_,
390 value_type last_,
391 step_type& stepper_)
392 : first(first_)
393 , last(last_)
394 , current(first_)
395 , p_stepper(&stepper_)
396 , p_compare(&default_compare)
397 {
398 }
399
400 //***************************************************************************
404 //***************************************************************************
405 multi_range(value_type first_,
406 value_type last_,
407 compare_type& compare_)
408 : first(first_)
409 , last(last_)
410 , current(first_)
411 , p_stepper(&default_stepper)
412 , p_compare(&compare_)
413 {
414 }
415
416 //***************************************************************************
420 //***************************************************************************
421 multi_range(value_type first_,
422 value_type last_,
423 step_type& stepper_,
424 compare_type& compare_)
425 : first(first_)
426 , last(last_)
427 , current(first_)
428 , p_stepper(&stepper_)
429 , p_compare(&compare_)
430 {
431 }
432
433 //***************************************************************************
435 //***************************************************************************
436 const_reference begin()
437 {
438 return first;
439 }
440
441 //***************************************************************************
444 //***************************************************************************
445 const_reference end()
446 {
447 return last;
448 }
449
450 //***************************************************************************
452 //***************************************************************************
453 void start() ETL_OVERRIDE
454 {
455 if (inner != ETL_NULLPTR)
456 {
457 inner->start();
458 }
459
460 current = first;
461 has_completed = !(*p_compare)(current, last); // Check for null range.
462 }
463
464 //***************************************************************************
466 //***************************************************************************
467 void next() ETL_OVERRIDE
468 {
469 has_completed = false;
470
471 if (inner != ETL_NULLPTR)
472 {
473 inner->next();
474
475 if (inner->completed())
476 {
477 has_completed = step();
478 }
479 }
480 else
481 {
482 has_completed = step();
483 }
484 }
485
486 //***************************************************************************
488 //***************************************************************************
489 const_reference value() const
490 {
491 return current;
492 }
493
494 private:
495
496 //***************************************************************************
498 //***************************************************************************
499 bool step()
500 {
501 (*p_stepper)(current);
502
503 const bool has_rolled_over = !(*p_compare)(current, last);
504
505 if (has_rolled_over)
506 {
507 current = first;
508 }
509
510 return has_rolled_over;
511 }
512
513 multi_range() ETL_DELETE;
514 multi_range(const multi_range&) ETL_DELETE;
515 multi_range& operator =(const multi_range&) ETL_DELETE;
516
517 value_type first;
518 value_type last;
519 value_type current;
520
521 step_type* p_stepper;
522 forward_step default_stepper;
523
524 compare_type* p_compare;
525 not_equal_compare default_compare;
526 };
527}
528
529#endif
The base class for multi_range.
Definition: multi_range.h:72
virtual void next()=0
Pure virtual functions.
imulti_range()
Constructor.
Definition: multi_range.h:186
size_t number_of_iterations()
Gets the total number of iterations over all ranges, from this range inclusive.
Definition: multi_range.h:163
void set_last(imulti_range *next)
Set the inner range of the last linked range.
Definition: multi_range.h:215
void detach_all()
Unlinks this and all inner ranges.
Definition: multi_range.h:124
bool is_valid(imulti_range &inner_range)
Checks that there are no circular references.
Definition: multi_range.h:195
imulti_range & insert(imulti_range &inner_range)
Insert after this range.
Definition: multi_range.h:78
void detach()
Unlinks this range from its inner.
Definition: multi_range.h:116
size_t number_of_ranges() const
Gets the total number of ranges, from this range inclusive.
Definition: multi_range.h:145
imulti_range & append(imulti_range &inner_range)
Append to the most inner range.
Definition: multi_range.h:97
Circular reference exception.
Definition: multi_range.h:59
Exception for the multi_range.
Definition: multi_range.h:46
Definition: multi_range.h:238
const_reference end()
Definition: multi_range.h:445
void start() ETL_OVERRIDE
Initialises the ranges to the starting values.
Definition: multi_range.h:453
multi_range(value_type first_, value_type last_)
Definition: multi_range.h:374
multi_range(value_type first_, value_type last_, compare_type &compare_)
Definition: multi_range.h:405
const_reference begin()
Get a const reference to the starting value of the range.
Definition: multi_range.h:436
multi_range(value_type first_, value_type last_, step_type &stepper_, compare_type &compare_)
Definition: multi_range.h:421
const_reference value() const
Returns a const reference to the current range value.
Definition: multi_range.h:489
void next() ETL_OVERRIDE
Step to the next logical values in the ranges.
Definition: multi_range.h:467
multi_range(value_type first_, value_type last_, step_type &stepper_)
Definition: multi_range.h:389
#define ETL_ASSERT(b, e)
Definition: error_handler.h:316
ETL_CONSTEXPR exception(string_type reason_, string_type, numeric_type line_)
Constructor.
Definition: exception.h:69
Definition: exception.h:47
bitset_ext
Definition: absolute.h:38
Definition: functional.h:186
Definition: functional.h:134
Definition: multi_range.h:324
Definition: multi_range.h:271
Definition: multi_range.h:258
Definition: multi_range.h:360
Definition: multi_range.h:347
Definition: multi_range.h:334
Definition: multi_range.h:304
Definition: multi_range.h:291
Definition: multi_range.h:248
Definition: functional.h:265