Loading...
Searching...
No Matches
multi_range.h
Go to the documentation of this file.
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2020 John Wellbelove
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_MULTI_LOOP_INCLUDED
#define ETL_MULTI_LOOP_INCLUDED
#include "platform.h"
#include "error_handler.h"
#include "exception.h"
#include "functional.h"
#include "nullptr.h"
namespace etl
{
//***************************************************************************
//***************************************************************************
class multi_range_exception : public etl::exception
{
public:
multi_range_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
: exception(reason_, file_name_, line_number_)
{
}
};
//***************************************************************************
//***************************************************************************
class multi_range_circular_reference : public etl::multi_range_exception
{
public:
multi_range_circular_reference(string_type file_name_, numeric_type line_number_)
: etl::multi_range_exception(ETL_ERROR_TEXT("multi_range:circular reference", ETL_MULTI_LOOP_FILE_ID"A"), file_name_, line_number_)
{
}
};
//***************************************************************************
//***************************************************************************
class imulti_range
{
public:
//***************************************************************************
//***************************************************************************
imulti_range& insert(imulti_range& inner_range)
{
ETL_ASSERT(is_valid(inner_range), ETL_ERROR(multi_range_circular_reference));
// Remember what the next range was.
imulti_range* next = inner;
// Append the new range
inner = &inner_range;
// Link to the original next range.
inner_range.set_last(next);
return *this;
}
//***************************************************************************
//***************************************************************************
imulti_range& append(imulti_range& inner_range)
{
ETL_ASSERT(is_valid(inner_range), ETL_ERROR(multi_range_circular_reference));
if (inner != ETL_NULLPTR)
{
inner->append(inner_range);
}
else
{
inner = &inner_range;
}
return *this;
}
//***************************************************************************
//***************************************************************************
void detach()
{
inner = ETL_NULLPTR;
}
//***************************************************************************
//***************************************************************************
void detach_all()
{
if (inner != ETL_NULLPTR)
{
inner->detach_all();
}
detach();
}
//***************************************************************************
//***************************************************************************
bool completed() const
{
return has_completed;
}
//***************************************************************************
//***************************************************************************
size_t number_of_ranges() const
{
size_t count = 1UL;
imulti_range* p_range = inner;
while (p_range != ETL_NULLPTR)
{
++count;
p_range = p_range->inner;
}
return count;
}
//***************************************************************************
//***************************************************************************
size_t number_of_iterations()
{
size_t count = 0UL;
for (start(); !completed(); next())
{
++count;
}
return count;
}
//***************************************************************************
//***************************************************************************
virtual void next() = 0;
virtual void start() = 0;
protected:
//***************************************************************************
//***************************************************************************
imulti_range()
: has_completed(true)
, inner(ETL_NULLPTR)
{
}
//***************************************************************************
//***************************************************************************
bool is_valid(imulti_range& inner_range)
{
imulti_range* range = &inner_range;
while (range != ETL_NULLPTR)
{
if (range == this)
{
return false;
}
range = range->inner;
}
return true;
}
//***************************************************************************
//***************************************************************************
void set_last(imulti_range* next)
{
// Find the last range.
imulti_range* range = this;
while (range->inner != ETL_NULLPTR)
{
range = range->inner;
}
range->inner = next;
}
bool has_completed;
imulti_range* inner;
};
//***************************************************************************
//***************************************************************************
template <typename T>
class multi_range : public imulti_range
{
public:
typedef T value_type;
typedef const T& const_reference;
//***************************************************************************
//***************************************************************************
struct step_type
{
typedef T value_type;
virtual void operator()(value_type& value) = 0;
};
//***************************************************************************
//***************************************************************************
struct forward_step : public step_type
{
typedef T value_type;
virtual void operator()(value_type& value)
{
++value;
}
};
//***************************************************************************
//***************************************************************************
struct forward_step_by : public step_type
{
typedef T value_type;
explicit forward_step_by(const value_type& step_value_)
: step_value(step_value_)
{
}
virtual void operator()(value_type& value)
{
value += step_value;
}
const value_type step_value;
};
//***************************************************************************
//***************************************************************************
struct reverse_step : public step_type
{
typedef T value_type;
virtual void operator()(value_type& value)
{
--value;
}
};
//***************************************************************************
//***************************************************************************
struct reverse_step_by : public step_type
{
typedef T value_type;
explicit reverse_step_by(const value_type& step_value_)
: step_value(step_value_)
{
}
virtual void operator()(value_type& value)
{
value -= step_value;
}
const value_type step_value;
};
//***************************************************************************
//***************************************************************************
struct compare_type
{
typedef T value_type;
virtual bool operator()(const value_type& lhs, const value_type& rhs) const = 0;
};
//***************************************************************************
//***************************************************************************
struct not_equal_compare : public compare_type
{
typedef T value_type;
virtual bool operator()(const value_type& lhs, const value_type& rhs) const ETL_OVERRIDE
{
return etl::not_equal_to<value_type>()(lhs, rhs);
}
};
//***************************************************************************
//***************************************************************************
struct less_than_compare : public compare_type
{
typedef T value_type;
virtual bool operator()(const value_type& lhs, const value_type& rhs) const ETL_OVERRIDE
{
return etl::less<value_type>()(lhs, rhs);
}
};
//***************************************************************************
//***************************************************************************
struct greater_than_compare : public compare_type
{
typedef T value_type;
virtual bool operator()(const value_type& lhs, const value_type& rhs) const ETL_OVERRIDE
{
return etl::greater<value_type>()(lhs, rhs);
}
};
//***************************************************************************
//***************************************************************************
multi_range(value_type first_, value_type last_)
: first(first_)
, last(last_)
, current(first_)
, p_stepper(&default_stepper)
, p_compare(&default_compare)
{
}
//***************************************************************************
//***************************************************************************
multi_range(value_type first_, value_type last_, step_type& stepper_)
: first(first_)
, last(last_)
, current(first_)
, p_stepper(&stepper_)
, p_compare(&default_compare)
{
}
//***************************************************************************
//***************************************************************************
multi_range(value_type first_, value_type last_, compare_type& compare_)
: first(first_)
, last(last_)
, current(first_)
, p_stepper(&default_stepper)
, p_compare(&compare_)
{
}
//***************************************************************************
//***************************************************************************
multi_range(value_type first_, value_type last_, step_type& stepper_, compare_type& compare_)
: first(first_)
, last(last_)
, current(first_)
, p_stepper(&stepper_)
, p_compare(&compare_)
{
}
//***************************************************************************
//***************************************************************************
const_reference begin()
{
return first;
}
//***************************************************************************
//***************************************************************************
const_reference end()
{
return last;
}
//***************************************************************************
//***************************************************************************
void start() ETL_OVERRIDE
{
if (inner != ETL_NULLPTR)
{
inner->start();
}
current = first;
has_completed = !(*p_compare)(current, last); // Check for null range.
}
//***************************************************************************
//***************************************************************************
void next() ETL_OVERRIDE
{
has_completed = false;
if (inner != ETL_NULLPTR)
{
inner->next();
if (inner->completed())
{
has_completed = step();
}
}
else
{
has_completed = step();
}
}
//***************************************************************************
//***************************************************************************
const_reference value() const
{
return current;
}
private:
//***************************************************************************
//***************************************************************************
bool step()
{
(*p_stepper)(current);
const bool has_rolled_over = !(*p_compare)(current, last);
if (has_rolled_over)
{
current = first;
}
return has_rolled_over;
}
multi_range() ETL_DELETE;
multi_range(const multi_range&) ETL_DELETE;
multi_range& operator=(const multi_range&) ETL_DELETE;
value_type first;
value_type last;
value_type current;
step_type* p_stepper;
forward_step default_stepper;
compare_type* p_compare;
not_equal_compare default_compare;
};
} // namespace etl
#endif
etl::imulti_range
The base class for multi_range.
Definition multi_range.h:72
etl::imulti_range::next
virtual void next()=0
Pure virtual functions.
etl::imulti_range::imulti_range
imulti_range()
Constructor.
Definition multi_range.h:187
etl::imulti_range::number_of_iterations
size_t number_of_iterations()
Definition multi_range.h:164
etl::imulti_range::set_last
void set_last(imulti_range *next)
Set the inner range of the last linked range.
Definition multi_range.h:216
etl::imulti_range::detach_all
void detach_all()
Unlinks this and all inner ranges.
Definition multi_range.h:124
etl::imulti_range::is_valid
bool is_valid(imulti_range &inner_range)
Checks that there are no circular references.
Definition multi_range.h:196
etl::imulti_range::insert
imulti_range & insert(imulti_range &inner_range)
Insert after this range.
Definition multi_range.h:78
etl::imulti_range::detach
void detach()
Unlinks this range from its inner.
Definition multi_range.h:116
etl::imulti_range::number_of_ranges
size_t number_of_ranges() const
Gets the total number of ranges, from this range inclusive.
Definition multi_range.h:145
etl::imulti_range::append
imulti_range & append(imulti_range &inner_range)
Append to the most inner range.
Definition multi_range.h:97
etl::multi_range_circular_reference
Circular reference exception.
Definition multi_range.h:59
etl::multi_range_exception
Exception for the multi_range.
Definition multi_range.h:46
etl::multi_range::end
const_reference end()
Definition multi_range.h:441
etl::multi_range::start
void start() ETL_OVERRIDE
Initialises the ranges to the starting values.
Definition multi_range.h:449
etl::multi_range::multi_range
multi_range(value_type first_, value_type last_)
Definition multi_range.h:376
etl::multi_range::multi_range
multi_range(value_type first_, value_type last_, compare_type &compare_)
Definition multi_range.h:405
etl::multi_range::begin
const_reference begin()
Get a const reference to the starting value of the range.
Definition multi_range.h:432
etl::multi_range::multi_range
multi_range(value_type first_, value_type last_, step_type &stepper_, compare_type &compare_)
Definition multi_range.h:420
etl::multi_range::value
const_reference value() const
Returns a const reference to the current range value.
Definition multi_range.h:485
etl::multi_range::next
void next() ETL_OVERRIDE
Step to the next logical values in the ranges.
Definition multi_range.h:463
etl::multi_range::multi_range
multi_range(value_type first_, value_type last_, step_type &stepper_)
Definition multi_range.h:391
error_handler.h
exception.h
functional.h
ETL_ASSERT
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
etl::exception::exception
ETL_EXCEPTION_CONSTEXPR exception(string_type reason_, string_type, numeric_type)
Constructor.
Definition exception.h:81
etl::exception
Definition exception.h:59
etl
Definition absolute.h:40
nullptr.h
platform.h
etl::greater
Definition functional.h:253
etl::less
Definition functional.h:201
etl::multi_range::compare_type
Definition multi_range.h:325
etl::multi_range::forward_step
Definition multi_range.h:259
etl::multi_range::greater_than_compare
Definition multi_range.h:361
etl::multi_range::less_than_compare
Definition multi_range.h:348
etl::multi_range::not_equal_compare
Definition multi_range.h:335
etl::multi_range::reverse_step
Definition multi_range.h:292
etl::multi_range::step_type
Definition multi_range.h:249
etl::not_equal_to
Definition functional.h:332