Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com
Revision 0:b47c2a7920c2, committed 2018-03-16
- Comitter:
- bobbery
- Date:
- Fri Mar 16 16:34:18 2018 +0000
- Commit message:
- Works after using gcc_generic undef CAPACITY and replacing nullptr by std::nullptr
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/algorithm.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1120 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_ALGORITHM__ +#define __ETL_ALGORITHM__ + +///\defgroup algorithm algorithm +/// Reverse engineered algorithms from C++ 0x11 +/// Additional new variants of certain algorithms. +///\ingroup utilities + +#include <algorithm> +#include <iterator> +#include <utility> +#include <functional> +#include <iterator> +#include <stdint.h> + +#include "platform.h" +#include "iterator.h" +#include "type_traits.h" + +namespace etl +{ + //*************************************************************************** + /// Finds the greatest and the smallest element in the range (begin, end).<br> + ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax_element"></a> + ///\ingroup algorithm + //*************************************************************************** + template <typename TIterator, + typename TCompare> + std::pair<TIterator, TIterator> minmax_element(TIterator begin, + TIterator end, + TCompare compare) + { + TIterator minimum = begin; + TIterator maximum = begin; + + while (begin != end) + { + if (compare(*begin, *minimum)) + { + minimum = begin; + } + + if (compare(*maximum, *begin)) + { + maximum = begin; + } + + ++begin; + } + + return std::pair<TIterator, TIterator>(minimum, maximum); + } + + //*************************************************************************** + /// minmax_element + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax_element"></a> + //*************************************************************************** + template <typename TIterator> + std::pair<TIterator, TIterator> minmax_element(TIterator begin, + TIterator end) + { + typedef typename std::iterator_traits<TIterator>::value_type value_t; + + return etl::minmax_element(begin, end, std::less<value_t>()); + } + + //*************************************************************************** + /// minmax + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax"></a> + //*************************************************************************** + template <typename T> + std::pair<const T&, const T&> minmax(const T& a, + const T& b) + { + return (b < a) ? std::pair<const T&, const T&>(b, a) : std::pair<const T&, const T&>(a, b); + } + + //*************************************************************************** + /// minmax + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/minmax"></a> + //*************************************************************************** + template <typename T, + typename TCompare> + std::pair<const T&, const T&> minmax(const T& a, + const T& b, + TCompare compare) + { + return compare(b, a) ? std::pair<const T&, const T&>(b, a) : std::pair<const T&, const T&>(a, b); + } + + //*************************************************************************** + /// is_sorted_until + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted_until"></a> + //*************************************************************************** + template <typename TIterator> + TIterator is_sorted_until(TIterator begin, + TIterator end) + { + if (begin != end) + { + TIterator next = begin; + + while (++next != end) + { + if (*next < *begin) + { + return next; + } + + ++begin; + } + } + + return end; + } + + //*************************************************************************** + /// is_sorted_until + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted_until"></a> + //*************************************************************************** + template <typename TIterator, + typename TCompare> + TIterator is_sorted_until(TIterator begin, + TIterator end, + TCompare compare) + { + if (begin != end) + { + TIterator next = begin; + + while (++next != end) + { + if (compare(*next, *begin)) + { + return next; + } + + ++begin; + } + } + + return end; + } + + //*************************************************************************** + /// is_sorted + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted"></a> + //*************************************************************************** + template<typename TIterator> + bool is_sorted(TIterator begin, + TIterator end) + { + return etl::is_sorted_until(begin, end) == end; + } + + //*************************************************************************** + /// is_sorted + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_sorted"></a> + //*************************************************************************** + template<typename TIterator, + typename TCompare> + bool is_sorted(TIterator begin, + TIterator end, + TCompare compare) + { + return etl::is_sorted_until(begin, end, compare) == end; + } + + //*************************************************************************** + /// copy + /// A form of copy where the smallest of the two ranges is used. + /// There is currently no STL equivalent. + /// Specialisation for random access iterators. + ///\param i_begin Beginning of the input range. + ///\param i_end End of the input range. + ///\param o_begin Beginning of the output range. + ///\param o_end End of the output range. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TOutputIterator> + typename etl::enable_if<etl::is_random_iterator<TInputIterator>::value && + etl::is_random_iterator<TOutputIterator>::value, TOutputIterator>::type + copy(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end) + { + size_t s_size = std::distance(i_begin, i_end); + size_t d_size = std::distance(o_begin, o_end); + size_t size = (s_size < d_size) ? s_size : d_size; + + return std::copy(i_begin, i_begin + size, o_begin); + } + + //*************************************************************************** + /// copy + /// A form of copy where the smallest of the two ranges is used. + /// There is currently no STL equivalent. + /// Specialisation for non random access iterators. + ///\param i_begin Beginning of the input range. + ///\param i_end End of the input range. + ///\param o_begin Beginning of the output range. + ///\param o_end End of the output range. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TOutputIterator> + typename etl::enable_if<!etl::is_random_iterator<TInputIterator>::value || + !etl::is_random_iterator<TOutputIterator>::value, TOutputIterator>::type + copy(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end) + { + while ((i_begin != i_end) && (o_begin != o_end)) + { + *o_begin++ = *i_begin++; + } + + return o_begin; + } + + //*************************************************************************** + /// copy_n (Random input iterators) + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/copy_n"></a> + //*************************************************************************** + template <typename TInputIterator, + typename TSize, + typename TOutputIterator> + typename etl::enable_if<etl::is_random_iterator<TInputIterator>::value, TOutputIterator>::type + copy_n(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin) + { + return std::copy(i_begin, i_begin + n, o_begin); + } + + //*************************************************************************** + /// copy_n (Non-random input iterators) + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/copy_n"></a> + //*************************************************************************** + template <typename TInputIterator, + typename TSize, + typename TOutputIterator> + typename etl::enable_if<!etl::is_random_iterator<TInputIterator>::value, TOutputIterator>::type + copy_n(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin) + { + while (n-- > 0) + { + *o_begin++ = *i_begin++; + } + + return o_begin; + } + + //*************************************************************************** + /// copy_n + /// A form of copy_n where the smallest of the two ranges is used. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TSize, + typename TOutputIterator> + TOutputIterator copy_n(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin, + TOutputIterator o_end) + { + while ((n-- > 0) && (o_begin != o_end)) + { + *o_begin++ = *i_begin++; + } + + return o_begin; + } + + //*************************************************************************** + /// copy_n + /// A form of copy_n where the smallest of the two ranges is used. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TSize1, + typename TOutputIterator, + typename TSize2> + TOutputIterator copy_n(TInputIterator i_begin, + TSize1 n1, + TOutputIterator o_begin, + TSize2 n2) + { + while ((n1-- > 0) && (n2-- > 0)) + { + *o_begin++ = *i_begin++; + } + + return o_begin; + } + + //*************************************************************************** + /// copy_if + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/copy"></a> + //*************************************************************************** + template <typename TIterator, + typename TOutputIterator, + typename TUnaryPredicate> + TOutputIterator copy_if(TIterator begin, + TIterator end, + TOutputIterator out, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (predicate(*begin)) + { + *out++ = *begin; + } + + ++begin; + } + + return out; + } + + //*************************************************************************** + /// copy_if + /// A form of copy_if where it terminates when the first end iterator is reached. + /// There is currently no STL equivelent. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TOutputIterator, + typename TUnaryPredicate> + TOutputIterator copy_if(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end, + TUnaryPredicate predicate) + { + while ((i_begin != i_end) && (o_begin != o_end)) + { + if (predicate(*i_begin)) + { + *o_begin++ = *i_begin; + } + + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// copy_n_if + /// Combination of copy_n and copy_if. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TSize, + typename TOutputIterator, + typename TUnaryPredicate> + TOutputIterator copy_n_if(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin, + TUnaryPredicate predicate) + { + while (n-- > 0) + { + if (predicate(*i_begin)) + { + *o_begin++ = *i_begin; + } + + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// binary_find + ///\ingroup algorithm + /// Does a binary search and returns an iterator to the value or end if not found. + //*************************************************************************** + template <typename TIterator, + typename TValue> + TIterator binary_find(TIterator begin, + TIterator end, + const TValue& value) + { + TIterator it = std::lower_bound(begin, end, value); + + if ((it == end) || (*it != value)) + { + it = end; + } + + return it; + } + + //*************************************************************************** + /// binary_find + ///\ingroup algorithm + /// Does a binary search and returns an iterator to the value or end if not found. + //*************************************************************************** + template <typename TIterator, + typename TValue, + typename TBinaryPredicate, + typename TBinaryEquality> + TIterator binary_find(TIterator begin, + TIterator end, + const TValue& value, + TBinaryPredicate predicate, + TBinaryEquality equality) + { + TIterator it = std::lower_bound(begin, end, value, predicate); + + if ((it == end) || !equality(*it, value)) + { + it = end; + } + + return it; + } + + //*************************************************************************** + /// find_if_not + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/find"></a> + //*************************************************************************** + template <typename TIterator, + typename TUnaryPredicate> + TIterator find_if_not(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (!predicate(*begin)) + { + return begin; + } + + ++begin; + } + + return end; + } + + //*************************************************************************** + /// all_of + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/all_any_none_of"></a> + //*************************************************************************** + template <typename TIterator, + typename TUnaryPredicate> + bool all_of(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + return etl::find_if_not(begin, end, predicate) == end; + } + + //*************************************************************************** + /// any_of + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/all_any_none_of"></a> + //*************************************************************************** + template <typename TIterator, + typename TUnaryPredicate> + bool any_of(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + return std::find_if(begin, end, predicate) != end; + } + + //*************************************************************************** + /// none_of + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/all_any_none_of"></a> + //*************************************************************************** + template <typename TIterator, + typename TUnaryPredicate> + bool none_of(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + return std::find_if(begin, end, predicate) == end; + } + + //*************************************************************************** + /// is_permutation + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a> + //*************************************************************************** + template <typename TIterator1, + typename TIterator2> + bool is_permutation(TIterator1 begin1, + TIterator1 end1, + TIterator2 begin2) + { + if (begin1 != end1) + { + TIterator2 end2 = begin2; + + std::advance(end2, std::distance(begin1, end1)); + + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == std::find(begin1, i, *i)) + { + int32_t n = std::count(begin2, end2, *i); + + if (n == 0 || std::count(i, end1, *i) != n) + { + return false; + } + } + } + } + + return true; + } + + //*************************************************************************** + /// is_permutation + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a> + //*************************************************************************** + template <typename TIterator1, + typename TIterator2> + bool is_permutation(TIterator1 begin1, + TIterator1 end1, + TIterator2 begin2, + TIterator2 end2) + { + if (begin1 != end1) + { + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == std::find(begin1, i, *i)) + { + int32_t n = std::count(begin2, end2, *i); + + if (n == 0 || std::count(i, end1, *i) != n) + { + return false; + } + } + } + } + + return true; + } + + //*************************************************************************** + /// is_permutation + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a> + //*************************************************************************** + template <typename TIterator1, + typename TIterator2, + typename TBinaryPredicate> + bool is_permutation(TIterator1 begin1, + TIterator1 end1, + TIterator2 begin2, + TBinaryPredicate predicate) + { + if (begin1 != end1) + { + TIterator2 end2 = begin2; + + std::advance(end2, std::distance(begin1, end1)); + + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == std::find_if(begin1, i, std::bind1st(predicate, *i))) + { + int32_t n = std::count(begin2, end2, *i); + + if (n == 0 || std::count(i, end1, *i) != n) + { + return false; + } + } + } + } + + return true; + } + + //*************************************************************************** + /// is_permutation + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_permutation"></a> + //*************************************************************************** + template <typename TIterator1, + typename TIterator2, + typename TBinaryPredicate> + bool is_permutation(TIterator1 begin1, + TIterator1 end1, + TIterator2 begin2, + TIterator2 end2, + TBinaryPredicate predicate) + { + if (begin1 != end1) + { + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == std::find_if(begin1, i, std::bind1st(predicate, *i))) + { + int32_t n = std::count(begin2, end2, *i); + + if (n == 0 || std::count(i, end1, *i) != n) + { + return false; + } + } + } + } + + return true; + } + + //*************************************************************************** + /// is_partitioned + ///\ingroup algorithm + ///<a href="http://en.cppreference.com/w/cpp/algorithm/is_partitioned"></a> + //*************************************************************************** + template <typename TIterator, + typename TUnaryPredicate> + bool is_partitioned(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (!predicate(*begin++)) + { + break; + } + } + + while (begin != end) + { + if (predicate(*begin++)) + { + return false; + } + } + + return true; + } + + //*************************************************************************** + /// partition_point + ///<a href="http://en.cppreference.com/w/cpp/algorithm/partition_point"></a> + ///\ingroup algorithm + //*************************************************************************** + template <typename TIterator, + typename TUnaryPredicate> + TIterator partition_point(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (!predicate(*begin)) + { + return begin; + } + + ++begin; + } + + return begin; + } + + //*************************************************************************** + /// Copies the elements from the range (begin, end) to two different ranges + /// depending on the value returned by the predicate.<br> + ///<a href="http://en.cppreference.com/w/cpp/algorithm/partition_copy"></a> + ///\ingroup algorithm + //*************************************************************************** + template <typename TSource, + typename TDestinationTrue, + typename TDestinationFalse, + typename TUnaryPredicate> + std::pair<TDestinationTrue, TDestinationFalse> partition_copy(TSource begin, + TSource end, + TDestinationTrue destination_true, + TDestinationFalse destination_false, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (predicate(*begin)) + { + *destination_true++ = *begin++; + } + else + { + *destination_false++ = *begin++; + } + } + + return std::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false); + } + + //*************************************************************************** + /// Like std::for_each but applies a predicate before calling the function. + ///\ingroup algorithm + //*************************************************************************** + template <typename TIterator, + typename TUnaryFunction, + typename TUnaryPredicate> + TUnaryFunction for_each_if(TIterator begin, + const TIterator end, + TUnaryFunction function, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (predicate(*begin)) + { + function(*begin); + } + + ++begin; + } + + return function; + } + + //*************************************************************************** + /// Like std::for_each but for 'n' iterations. + ///\ingroup algorithm + //*************************************************************************** + template <typename TIterator, + typename TSize, + typename TUnaryFunction> + TIterator for_each_n(TIterator begin, + TSize n, + TUnaryFunction function) + { + while (n-- > 0) + { + function(*begin++); + } + + return begin; + } + + //*************************************************************************** + /// Like std::for_each but applies a predicate before calling the function, for 'n' iterations + ///\ingroup algorithm + //*************************************************************************** + template <typename TIterator, + typename TSize, + typename TUnaryFunction, + typename TUnaryPredicate> + TIterator for_each_n_if(TIterator begin, + TSize n, + TUnaryFunction function, + TUnaryPredicate predicate) + { + while (n-- > 0) + { + if (predicate(*begin)) + { + function(*begin); + } + + ++begin; + } + + return begin; + } + + //*************************************************************************** + /// A form of std::transform where the transform returns when the first range + /// end is reached. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TOutputIterator, + typename TUnaryFunction> + void transform(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end, + TUnaryFunction function) + { + while ((i_begin != i_end) && (o_begin != o_end)) + { + *o_begin++ = function(*i_begin++); + } + } + + //*************************************************************************** + /// Transform 'n' items. + /// Random iterators. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TSize, + typename TOutputIterator, + typename TUnaryFunction> + typename etl::enable_if<etl::is_random_iterator<TInputIterator>::value, void>::type + transform_n(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin, + TUnaryFunction function) + { + std::transform(i_begin, i_begin + n, o_begin, function); + } + + //*************************************************************************** + /// Transform 'n' items from two ranges. + /// Random iterators. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator1, + typename TInputIterator2, + typename TSize, + typename TOutputIterator, + typename TBinaryFunction> + typename etl::enable_if<etl::is_random_iterator<TInputIterator1>::value && + etl::is_random_iterator<TInputIterator2>::value, void>::type + transform_n(TInputIterator1 i_begin1, + TInputIterator2 i_begin2, + TSize n, + TOutputIterator o_begin, + TBinaryFunction function) + { + std::transform(i_begin1, i_begin1 + n, i_begin2, o_begin, function); + } + + //*************************************************************************** + /// Transform 'n' items. + /// Non-random iterators. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TSize, + typename TOutputIterator, + typename TUnaryFunction> + typename etl::enable_if<!etl::is_random_iterator<TInputIterator>::value, void>::type + transform_n(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin, + TUnaryFunction function) + { + while (n > 0) + { + *o_begin++ = function(*i_begin++); + --n; + } + } + + //*************************************************************************** + /// Transform 'n' items from two ranges. + /// Non-random iterators. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator1, + typename TInputIterator2, + typename TSize, + typename TOutputIterator, + typename TBinaryFunction> + typename etl::enable_if<!etl::is_random_iterator<TInputIterator1>::value || + !etl::is_random_iterator<TInputIterator2>::value, void>::type + transform_n(TInputIterator1 i_begin1, + TInputIterator2 i_begin2, + TSize n, + TOutputIterator o_begin, + TBinaryFunction function) + { + while (n > 0) + { + *o_begin++ = function(*i_begin1++, *i_begin2++); + --n; + } + } + + //*************************************************************************** + /// Like std::transform but applies a predicate before calling the function. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TOutputIterator, + typename TUnaryFunction, + typename TUnaryPredicate> + TOutputIterator transform_if(TInputIterator i_begin, + const TInputIterator i_end, + TOutputIterator o_begin, + TUnaryFunction function, + TUnaryPredicate predicate) + { + while (i_begin != i_end) + { + if (predicate(*i_begin)) + { + *o_begin++ = function(*i_begin); + } + + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// Like etl::transform_if but inputs from two ranges. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator1, + typename TInputIterator2, + typename TOutputIterator, + typename TBinaryFunction, + typename TBinaryPredicate> + TOutputIterator transform_if(TInputIterator1 i_begin1, + const TInputIterator1 i_end1, + TInputIterator2 i_begin2, + TOutputIterator o_begin, + TBinaryFunction function, + TBinaryPredicate predicate) + { + while (i_begin1 != i_end1) + { + if (predicate(*i_begin1, *i_begin2)) + { + *o_begin++ = function(*i_begin1, *i_begin2); + } + + ++i_begin1; + ++i_begin2; + } + + return o_begin; + } + + //*************************************************************************** + /// Like std::transform_if, for 'n' items. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator, + typename TSize, + typename TOutputIterator, + typename TUnaryFunction, + typename TUnaryPredicate> + TOutputIterator transform_n_if(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin, + TUnaryFunction function, + TUnaryPredicate predicate) + { + while (n-- > 0) + { + if (predicate(*i_begin)) + { + *o_begin++ = function(*i_begin); + } + + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// Like etl::transform_if but inputs from two ranges for 'n' items. + ///\ingroup algorithm + //*************************************************************************** + template <typename TInputIterator1, + typename TInputIterator2, + typename TSize, + typename TOutputIterator, + typename TBinaryFunction, + typename TBinaryPredicate> + TOutputIterator transform_n_if(TInputIterator1 i_begin1, + TInputIterator2 i_begin2, + TSize n, + TOutputIterator o_begin, + TBinaryFunction function, + TBinaryPredicate predicate) + { + while (n-- > 0) + { + if (predicate(*i_begin1, *i_begin2)) + { + *o_begin++ = function(*i_begin1, *i_begin2); + } + + ++i_begin1; + ++i_begin2; + } + + return o_begin; + } + + //*************************************************************************** + /// Transforms the elements from the range (begin, end) to two different ranges + /// depending on the value returned by the predicate.<br> + ///\ingroup algorithm + //*************************************************************************** + template <typename TSource, typename TDestinationTrue, typename TDestinationFalse, + typename TUnaryFunctionTrue, typename TUnaryFunctionFalse, + typename TUnaryPredicate> + std::pair<TDestinationTrue, TDestinationFalse> partition_transform(TSource begin, + TSource end, + TDestinationTrue destination_true, + TDestinationFalse destination_false, + TUnaryFunctionTrue function_true, + TUnaryFunctionFalse function_false, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (predicate(*begin)) + { + *destination_true++ = function_true(*begin++); + } + else + { + *destination_false++ = function_false(*begin++); + } + } + + return std::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false); + } + + //*************************************************************************** + /// Transforms the elements from the ranges (begin1, end1) & (begin2) + /// to two different ranges depending on the value returned by the predicate. + ///\ingroup algorithm + //*************************************************************************** + template <typename TSource1, + typename TSource2, + typename TDestinationTrue, + typename TDestinationFalse, + typename TBinaryFunctionTrue, + typename TBinaryFunctionFalse, + typename TBinaryPredicate> + std::pair<TDestinationTrue, TDestinationFalse> partition_transform(TSource1 begin1, + TSource1 end1, + TSource2 begin2, + TDestinationTrue destination_true, + TDestinationFalse destination_false, + TBinaryFunctionTrue function_true, + TBinaryFunctionFalse function_false, + TBinaryPredicate predicate) + { + while (begin1 != end1) + { + if (predicate(*begin1, *begin2)) + { + *destination_true++ = function_true(*begin1++, *begin2++); + } + else + { + *destination_false++ = function_false(*begin1++, *begin2++); + } + } + + return std::pair<TDestinationTrue, TDestinationFalse>(destination_true, destination_false); + } +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/alignment.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,198 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_ALIGNEMENT__ +#define __ETL_ALIGNEMENT__ + +#include <stdint.h> + +#include "platform.h" +#include "type_traits.h" +#include "static_assert.h" + +///\defgroup alignment alignment +/// Creates a variable of the specified type at the specified alignment. +/// \ingroup utilities + +namespace etl +{ + namespace __private_alignment__ + { + //*************************************************************************** + // Matcher. + //*************************************************************************** + template <const bool IS_MATCH, const size_t ALIGNMENT, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void> + class type_with_alignment_matcher; + + // Matching alignment. + template <const size_t ALIGNMENT, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> + class type_with_alignment_matcher <true, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8> + { + public: + + typedef T1 type; + }; + + // Non-matching alignment. + template <const size_t ALIGNMENT, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8> + class type_with_alignment_matcher <false, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8> + { + public: + + typedef typename type_with_alignment_matcher<ALIGNMENT <= etl::alignment_of<T2>::value, ALIGNMENT, T2, T3, T4, T5, T6, T7, T8, void>::type type; + }; + + // Non-matching alignment, none left. + template <const size_t ALIGNMENT> + class type_with_alignment_matcher <false, ALIGNMENT, void, void, void, void, void, void, void, void> + { + public: + + typedef char type; + }; + + //*************************************************************************** + // Helper. + //*************************************************************************** + template <const size_t ALIGNMENT, typename T1, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void> + class type_with_alignment_helper + { + public: + + typedef typename type_with_alignment_matcher<ALIGNMENT <= etl::alignment_of<T1>::value, ALIGNMENT, T1, T2, T3, T4, T5, T6, T7, T8>::type type; + }; + } + + //*************************************************************************** + /// Gets a type that has the same as the specified alignment. + ///\ingroup alignment + //*************************************************************************** + template <const size_t ALIGNMENT> + class type_with_alignment + { + public: + + typedef typename __private_alignment__::type_with_alignment_helper<ALIGNMENT, int_least8_t, int_least16_t, int32_t, int64_t, float, double, void*>::type type; + }; + + //*************************************************************************** + /// Aligned storage + /// LENGTH should be determined in terms of sizeof() + ///\ingroup alignment + //*************************************************************************** + template <const size_t LENGTH, const size_t ALIGNMENT> + struct aligned_storage + { + struct type + { + /// Convert to T reference. + template <typename T> + operator T& () + { + STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment"); + return reinterpret_cast<T&>(*data); + } + + /// Convert to const T reference. + template <typename T> + operator const T& () const + { + STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment"); + return reinterpret_cast<const T&>(*data); + } + + /// Convert to T pointer. + template <typename T> + operator T* () + { + STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment"); + return reinterpret_cast<T*>(data); + } + + /// Convert to const T pointer. + template <typename T> + operator const T* () const + { + STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment"); + return reinterpret_cast<const T*>(data); + } + + /// Get address as T reference. + template <typename T> + T& get_reference() + { + STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment"); + return reinterpret_cast<T&>(*data); + } + + /// Get address as const T reference. + template <typename T> + const T& get_reference() const + { + STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment"); + return reinterpret_cast<const T&>(*data); + } + + /// Get address as T pointer. + template <typename T> + T* get_address() + { + STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment"); + return reinterpret_cast<T*>(data); + } + + /// Get address as const T pointer. + template <typename T> + const T* get_address() const + { + STATIC_ASSERT((etl::is_same<T*, void*>:: value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment"); + return reinterpret_cast<const T*>(data); + } + + union + { + char data[LENGTH]; + typename etl::type_with_alignment<ALIGNMENT>::type __etl_alignment_type__; // A POD type that has the same alignment as ALIGNMENT. + }; + }; + }; + + //*************************************************************************** + /// Aligned storage as + ///\ingroup alignment + //*************************************************************************** + template <const size_t LENGTH, typename T> + struct aligned_storage_as : public etl::aligned_storage<LENGTH, etl::alignment_of<T>::value> + { + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/array.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,674 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_ARRAY__ +#define __ETL_ARRAY__ + +#include <iterator> +#include <functional> +#include <algorithm> +#include <stddef.h> + +#include "platform.h" +#include "exception.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "static_assert.h" +#include "error_handler.h" +#include "algorithm.h" + +///\defgroup array array +/// A replacement for std::array if you haven't got C++0x11. +///\ingroup containers + +namespace etl +{ + //*************************************************************************** + ///\ingroup array + /// The base class for array exceptions. + //*************************************************************************** + class array_exception : public exception + { + public: + + array_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup array + /// The out of range exceptions. + //*************************************************************************** + class array_out_of_range : public array_exception + { + public: + + array_out_of_range(string_type file_name_, numeric_type line_number_) + : array_exception("array:range", file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup array + /// A replacement for std::array if you haven't got C++0x11. + //*************************************************************************** + template <typename T, const size_t SIZE_> + class array + { + private: + + typedef typename etl::parameter_type<T>::type parameter_t; + + public: + + enum + { + SIZE = SIZE_ + }; + + typedef T value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef T* iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + //************************************************************************* + // Element access + //************************************************************************* + + //************************************************************************* + /// Returns a reference to the value at index 'i'. + ///\param i The index of the element to access. + //************************************************************************* + reference at(size_t i) + { + ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); + + return _buffer[i]; + } + + //************************************************************************* + /// Returns a const reference to the value at index 'i'. + ///\param i The index of the element to access. + //************************************************************************* + const_reference at(size_t i) const + { + ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); + + return _buffer[i]; + } + + //************************************************************************* + /// [] operator. + /// Returns a reference to the value at index 'i'. + ///\param i The index of the element to access. + //************************************************************************* + reference operator[](size_t i) + { + return _buffer[i]; + } + + //************************************************************************* + /// [] operator. + /// Returns a const reference to the value at index 'i'. + ///\param i The index of the element to access. + //************************************************************************* + const_reference operator[](size_t i) const + { + return _buffer[i]; + } + + //************************************************************************* + /// Returns a reference to the first element. + //************************************************************************* + reference front() + { + return _buffer[0]; + } + + //************************************************************************* + /// Returns a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return _buffer[0]; + } + + //************************************************************************* + /// Returns a reference to the last element. + //************************************************************************* + reference back() + { + return _buffer[SIZE - 1]; + } + + //************************************************************************* + /// Returns a const reference to the last element. + //************************************************************************* + const_reference back() const + { + return _buffer[SIZE - 1]; + } + + //************************************************************************* + /// Returns a pointer to the first element of the internal buffer. + //************************************************************************* + pointer data() + { + return &_buffer[0]; + } + + //************************************************************************* + /// Returns a const pointer to the first element of the internal buffer. + //************************************************************************* + const_pointer data() const + { + return &_buffer[0]; + } + + //************************************************************************* + // Iterators + //************************************************************************* + + //************************************************************************* + /// Returns an iterator to the beginning of the array. + //************************************************************************* + iterator begin() + { + return &_buffer[0]; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator begin() const + { + return &_buffer[0]; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator cbegin() const + { + return begin(); + } + + //************************************************************************* + /// Returns an iterator to the end of the array. + //************************************************************************* + iterator end() + { + return &_buffer[SIZE]; + } + + //************************************************************************* + /// Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator end() const + { + return &_buffer[SIZE]; + } + + //************************************************************************* + // Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator cend() const + { + return &_buffer[SIZE]; + } + + //************************************************************************* + // Returns an reverse iterator to the reverse beginning of the array. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(end()); + } + + //************************************************************************* + /// Returns a reverse iterator to the end of the array. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(begin()); + } + + //************************************************************************* + // Capacity + //************************************************************************* + + //************************************************************************* + /// Returns <b>true</b> if the array size is zero. + //************************************************************************* + bool empty() const + { + return (SIZE == 0); + } + + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + size_t size() const + { + return SIZE; + } + + //************************************************************************* + /// Returns the maximum possible size of the array. + //************************************************************************* + size_t max_size() const + { + return SIZE; + } + + //************************************************************************* + // Operations + //************************************************************************* + + //************************************************************************* + /// Fills the array with the specified value. + ///\param value The value to fill the array with. + //************************************************************************* + void fill(parameter_t value) + { + std::fill(begin(), end(), value); + } + + //************************************************************************* + /// Swaps the contents of this array and another. + ///\param other A reference to the other array. + //************************************************************************* + void swap(array& other) + { + for (size_t i = 0; i < SIZE; ++i) + { + std::swap(_buffer[i], other._buffer[i]); + } + } + + //************************************************************************* + /// Fills the array from the range. + /// If the range is larger than the array then the extra data is ignored. + /// If the range is smaller than the array then the unused array elements are left unmodified. + ///\param first The iterator to the first item in the ramge. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template <typename TIterator> + void assign(TIterator first, const TIterator last) + { + etl::copy(first, last, begin(), end()); + } + + //************************************************************************* + /// Fills the array from the range. + /// If the range is larger than the array then the extra data is ignored. + /// If the range is smaller than the array then the unused array elements are initialised with the supplied value. + ///\param first The iterator to the first item in the ramge. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template <typename TIterator> + void assign(TIterator first, const TIterator last, parameter_t value) + { + // Copy from the range. + iterator p = etl::copy(first, last, begin(), end()); + + // Default initialise any that are left. + std::fill(p, end(), value); + } + + //************************************************************************* + /// Inserts a value into the array. + ///\param position The index of the position to insert at. + ///\param value The value to insert. + //************************************************************************* + inline iterator insert_at(size_t position, parameter_t value) + { + return insert(begin() + position, value); + } + + //************************************************************************* + /// Inserts a value into the array. + ///\param position The iterator to the position to insert at. + ///\param value The value to insert. + //************************************************************************* + iterator insert(const_iterator position, parameter_t value) + { + iterator p = const_cast<iterator>(position); + + std::copy_backward(p, end() - 1, end()); + *p = value; + + return p; + } + + //************************************************************************* + /// Insert into the array from the range. + ///\param position The position to insert at. + ///\param first The iterator to the first item in the range. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template <typename TIterator> + inline iterator insert_at(size_t position, TIterator first, const TIterator last) + { + return insert(begin() + position, first, last); + } + + //************************************************************************* + /// Insert into the array from the range. + ///\param position The position to insert at. + ///\param first The iterator to the first item in the range. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template <typename TIterator> + iterator insert(const_iterator position, TIterator first, const TIterator last) + { + iterator p = const_cast<iterator>(position); + iterator result(p); + + size_t source_size = std::distance(first, last); + size_t destination_space = std::distance(position, cend()); + + // Do we need to move anything? + if (source_size < destination_space) + { + size_t length = SIZE - (std::distance(begin(), p) + source_size); + std::copy_backward(p, p + length, end()); + } + + // Copy from the range. + etl::copy(first, last, p, end()); + + return result; + } + + //************************************************************************* + /// Erases a value from the array. + /// After erase, the last value in the array will be unmodified. + ///\param position The index of the position to erase at. + //************************************************************************* + inline iterator erase_at(size_t position) + { + return erase(begin() + position); + } + + //************************************************************************* + /// Erases a value from the array. + /// After erase, the last value in the array will be unmodified. + ///\param position The iterator to the position to erase at. + //************************************************************************* + iterator erase(const_iterator position) + { + iterator p = const_cast<iterator>(position); + std::copy(p + 1, end(), p); + + return p; + } + + //************************************************************************* + /// Erases a range of values from the array. + /// After erase, the last values in the array will be unmodified. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + //************************************************************************* + iterator erase_range(size_t first, size_t last) + { + return erase(begin() + first, begin() + last); + } + + //************************************************************************* + /// Erases a range of values from the array. + /// After erase, the last values in the array will be unmodified. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + iterator p = const_cast<iterator>(first); + std::copy(last, cend(), p); + return p; + } + + //************************************************************************* + /// Erases a value from the array. + ///\param position The index of the position to erase at. + ///\param value The value to use to overwrite the last element in the array. + //************************************************************************* + inline iterator erase_at(size_t position, parameter_t value) + { + return erase(begin() + position, value); + } + + //************************************************************************* + /// Erases a value from the array. + ///\param position The iterator to the position to erase at. + ///\param value The value to use to overwrite the last element in the array. + //************************************************************************* + iterator erase(const_iterator position, parameter_t value) + { + iterator p = const_cast<iterator>(position); + + std::copy(p + 1, end(), p); + back() = value; + + return p; + } + + //************************************************************************* + /// Erases a range of values from the array. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + ///\param value The value to use to overwrite the last elements in the array. + //************************************************************************* + iterator erase_range(size_t first, size_t last, parameter_t value) + { + return erase(begin() + first, begin() + last, value); + } + + //************************************************************************* + /// Erases a range of values from the array. + ///\param position The iterator to the position to erase at. + ///\param value The value to use to overwrite the last elements in the array. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last, parameter_t value) + { + iterator p = const_cast<iterator>(first); + + p = std::copy(last, cend(), p); + std::fill(p, end(), value); + + return const_cast<iterator>(first); + } + + /// The array data. + T _buffer[SIZE]; + }; + + //************************************************************************* + /// Overloaded swap for etl::array<T, SIZE> + ///\param lhs The first array. + ///\param rhs The second array. + //************************************************************************* + template <typename T, const size_t SIZE> + void swap(etl::array<T, SIZE> &lhs, etl::array<T, SIZE> &rhs) + { + lhs.swap(rhs); + } + + //************************************************************************* + /// Equal operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + //************************************************************************* + template <typename T, std::size_t SIZE> + bool operator ==(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs) + { + return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + } + + //************************************************************************* + /// Not equal operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + //************************************************************************* + template <typename T, std::size_t SIZE> + bool operator !=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// Less than operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return <b>true</b> if the first array is lexicographically less than the second, otherwise <b>false</b> + //************************************************************************* + template <typename T, std::size_t SIZE> + bool operator <(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs) + { + return std::lexicographical_compare(lhs.cbegin(), + lhs.cend(), + rhs.cbegin(), + rhs.cend()); + } + + //************************************************************************* + /// Less than or equal operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return <b>true</b> if the first array is lexicographically less than or equal to the second, otherwise <b>false</b> + //************************************************************************* + template <typename T, std::size_t SIZE> + bool operator <=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs) + { + return !(lhs > rhs); + } + + //************************************************************************* + /// Greater than operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return <b>true</b> if the first array is lexicographically greater than the second, otherwise <b>false</b> + template <typename T, std::size_t SIZE> + //************************************************************************* + bool operator >(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs) + { + return (rhs < lhs); + } + + //************************************************************************* + /// Greater than or equal operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return <b>true</b> if the first array is lexicographically greater than or equal to the second, otherwise <b>false</b> + //************************************************************************* + template <typename T, std::size_t SIZE> + bool operator >=(const etl::array<T, SIZE>& lhs, const etl::array<T, SIZE>& rhs) + { + return !(lhs < rhs); + } + + //************************************************************************* + /// Gets a reference to an element in the array. + ///\tparam I The index. + ///\tparam T The type. + ///\tparam MAXN The array size. + ///\param a The array. + ///\return A reference to the element + //************************************************************************* + template <std::size_t I, typename T, std::size_t MAXN> + inline T& get(array<T, MAXN>& a) + { + STATIC_ASSERT(I < MAXN, "Index out of bounds"); + return a[I]; + } + + //************************************************************************* + /// Gets a const reference to an element in the array. + ///\tparam I The index. + ///\tparam T The type. + ///\tparam MAXN The array size. + ///\param a The array. + ///\return A const reference to the element + //************************************************************************* + template <std::size_t I, typename T, std::size_t MAXN> + inline const T& get(const array<T, MAXN>& a) + { + STATIC_ASSERT(I < MAXN, "Index out of bounds"); + return a[I]; + } +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/array_view.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,874 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ARRAY_VIEW__ +#define __ETL_ARRAY_VIEW__ + +#include "platform.h" +#include "memory.h" +#include "iterator.h" +#include "error_handler.h" +#include "exception.h" +#include "nullptr.h" +#include "hash.h" + +#include <algorithm> + +///\defgroup array array +/// A wrapper for arrays +///\ingroup containers + +#undef ETL_FILE +#define ETL_FILE "41" + +namespace etl +{ + //*************************************************************************** + /// The base class for array_view exceptions. + //*************************************************************************** + class array_view_exception : public exception + { + public: + + array_view_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the index is out of bounds. + //*************************************************************************** + class array_view_bounds : public array_view_exception + { + public: + + array_view_bounds(string_type file_name_, numeric_type line_number_) + : array_view_exception(ETL_ERROR_TEXT("array_view:bounds", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the view is uninitialised. + //*************************************************************************** + class array_view_uninitialised : public array_view_exception + { + public: + + array_view_uninitialised(string_type file_name_, numeric_type line_number_) + : array_view_exception(ETL_ERROR_TEXT("array_view:uninitialised", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Array view. + //*************************************************************************** + template <typename T> + class array_view + { + public: + + typedef T value_type; + typedef std::size_t size_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef T* iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + array_view() + : mbegin(std::nullptr), + mend(std::nullptr) + { + } + + //************************************************************************* + /// Construct from std::array or etl::array or other type that supports + /// data() and size() member functions. + //************************************************************************* + template <typename TArray, + typename TDummy = typename etl::enable_if<!etl::is_same<T, TArray>::value, void>::type> + explicit array_view(TArray& a) + : mbegin(a.data()), + mend(a.data() + a.size()) + { + } + + //************************************************************************* + /// Construct from iterators + //************************************************************************* + template <typename TIterator, + typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + array_view(TIterator begin_, TIterator end_) + : mbegin(etl::addressof(*begin_)), + mend(etl::addressof(*begin_) + std::distance(begin_, end_)) + { + } + + //************************************************************************* + /// Construct from C array + //************************************************************************* + template <typename TIterator, + typename TSize, + typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + array_view(TIterator begin_, TSize size_) + : mbegin(etl::addressof(*begin_)), + mend(etl::addressof(*begin_) + size_) + { + } + + //************************************************************************* + /// Construct from C array + //************************************************************************* + template<const size_t ARRAY_SIZE> + explicit array_view(T(&begin_)[ARRAY_SIZE]) + : mbegin(begin_), + mend(begin_ + ARRAY_SIZE) + { + } + + //************************************************************************* + /// Copy constructor + //************************************************************************* + array_view(const array_view& other) + : mbegin(other.mbegin), + mend(other.mend) + { + } + + //************************************************************************* + /// Returns a reference to the first element. + //************************************************************************* + reference front() + { + return *mbegin; + } + + //************************************************************************* + /// Returns a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return *mbegin; + } + + //************************************************************************* + /// Returns a reference to the last element. + //************************************************************************* + reference back() + { + return *(mend - 1); + } + + //************************************************************************* + /// Returns a const reference to the last element. + //************************************************************************* + const_reference back() const + { + return *(mend - 1); + } + + //************************************************************************* + /// Returns a pointer to the first element of the internal storage. + //************************************************************************* + pointer data() + { + return mbegin; + } + + //************************************************************************* + /// Returns a const pointer to the first element of the internal storage. + //************************************************************************* + const_pointer data() const + { + return mbegin; + } + + //************************************************************************* + /// Returns an iterator to the beginning of the array. + //************************************************************************* + iterator begin() + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator begin() const + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator cbegin() const + { + return mbegin; + } + + //************************************************************************* + /// Returns an iterator to the end of the array. + //************************************************************************* + iterator end() + { + return mend; + } + + //************************************************************************* + /// Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator end() const + { + return mend; + } + + //************************************************************************* + // Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator cend() const + { + return mend; + } + + //************************************************************************* + // Returns an reverse iterator to the reverse beginning of the array. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a reverse iterator to the end of the array. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(mbegin); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(mbegin); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(mbegin); + } + + //************************************************************************* + /// Returns <b>true</b> if the array size is zero. + //************************************************************************* + bool empty() const + { + return (mbegin == mend); + } + + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + size_t size() const + { + return (mend - mbegin); + } + + //************************************************************************* + /// Returns the maximum possible size of the array. + //************************************************************************* + size_t max_size() const + { + return size(); + } + + //************************************************************************* + /// Assign from a view. + //************************************************************************* + array_view& operator=(const array_view& other) + { + mbegin = other.mbegin; + mend = other.mend; + return *this; + } + + //************************************************************************* + /// Assign from iterators + //************************************************************************* + template <typename TIterator, + typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + void assign(TIterator begin_, TIterator end_) + { + mbegin = etl::addressof(*begin_); + mend = etl::addressof(*begin_) + std::distance(begin_, end_); + } + + //************************************************************************* + /// Assign from iterator and size. + //************************************************************************* + template <typename TIterator, + typename TSize, + typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + void assign(TIterator begin_, TSize size_) + { + mbegin = etl::addressof(*begin_); + mend = etl::addressof(*begin_) + size_; + } + + //************************************************************************* + /// Returns a reference to the indexed value. + //************************************************************************* + reference operator[](size_t i) + { + return mbegin[i]; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference operator[](size_t i) const + { + return mbegin[i]; + } + + //************************************************************************* + /// Returns a reference to the indexed value. + //************************************************************************* + reference at(size_t i) + { + ETL_ASSERT((mbegin != std::nullptr && mend != std::nullptr), ETL_ERROR(array_view_uninitialised)); + ETL_ASSERT(i < size(), ETL_ERROR(array_view_bounds)); + return mbegin[i]; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference at(size_t i) const + { + ETL_ASSERT((mbegin != std::nullptr && mend != std::nullptr), ETL_ERROR(array_view_uninitialised)); + ETL_ASSERT(i < size(), ETL_ERROR(array_view_bounds)); + return mbegin[i]; + } + + //************************************************************************* + /// Swaps with another array_view. + //************************************************************************* + void swap(array_view& other) + { + std::swap(mbegin, other.mbegin); + std::swap(mend, other.mend); + } + + //************************************************************************* + /// Shrinks the view by moving its start forward. + //************************************************************************* + void remove_prefix(size_type n) + { + mbegin += n; + } + + //************************************************************************* + /// Shrinks the view by moving its end backward. + //************************************************************************* + void remove_suffix(size_type n) + { + mend -= n; + } + + //************************************************************************* + /// Equality for array views. + //************************************************************************* + friend bool operator == (const array_view<T>& lhs, const array_view<T>& rhs) + { + return (lhs.size() == rhs.size()) && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //************************************************************************* + /// Inequality for array views. + //************************************************************************* + friend bool operator != (const array_view<T>& lhs, const array_view<T>& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// Less-than for array views. + //************************************************************************* + friend bool operator < (const array_view<T>& lhs, const array_view<T>& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //************************************************************************* + /// Greater-than for array views. + //************************************************************************* + friend bool operator > (const array_view<T>& lhs, const array_view<T>& rhs) + { + return rhs < lhs; + } + + //************************************************************************* + /// Less-than-equal for array views. + //************************************************************************* + friend bool operator <= (const array_view<T>& lhs, const array_view<T>& rhs) + { + return !(lhs > rhs); + } + + //************************************************************************* + /// Greater-than-equal for array views. + //************************************************************************* + friend bool operator >= (const array_view<T>& lhs, const array_view<T>& rhs) + { + return !(lhs < rhs); + } + + private: + + T* mbegin; + T* mend; + }; + + //*************************************************************************** + /// Constant array view. + //*************************************************************************** + template <typename T> + class const_array_view + { + public: + + typedef T value_type; + typedef std::size_t size_type; + typedef const T& const_reference; + typedef const T* const_pointer; + typedef const T* const_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + const_array_view() + : mbegin(std::nullptr), + mend(std::nullptr) + { + } + + //************************************************************************* + /// Construct from std::array or etl::array or other type that supports + /// data() and size() member functions. + //************************************************************************* + template <typename TArray, + typename TDummy = typename etl::enable_if<!etl::is_same<T, TArray>::value, void>::type> + explicit const_array_view(TArray& a) + : mbegin(a.data()), + mend(a.data() + a.size()) + { + } + + //************************************************************************* + /// Construct from iterators + //************************************************************************* + template <typename TIterator, + typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + const_array_view(TIterator begin_, TIterator end_) + : mbegin(etl::addressof(*begin_)), + mend(etl::addressof(*begin_) + std::distance(begin_, end_)) + { + } + + //************************************************************************* + /// Construct from C array + //************************************************************************* + template <typename TIterator, + typename TSize, typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + const_array_view(TIterator begin_, TSize size_) + : mbegin(etl::addressof(*begin_)), + mend(etl::addressof(*begin_) + size_) + { + } + + //************************************************************************* + /// Construct from C array + //************************************************************************* + template<const size_t ARRAY_SIZE> + explicit const_array_view(const T(&begin_)[ARRAY_SIZE]) + : mbegin(begin_), + mend(begin_ + ARRAY_SIZE) + { + } + + //************************************************************************* + /// Copy constructor + //************************************************************************* + const_array_view(const array_view<T>& other) + : mbegin(other.begin()), + mend(other.end()) + { + } + + //************************************************************************* + /// Copy constructor + //************************************************************************* + const_array_view(const const_array_view& other) + : mbegin(other.mbegin), + mend(other.mend) + { + } + + //************************************************************************* + /// Returns a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return *mbegin; + } + + //************************************************************************* + /// Returns a const reference to the last element. + //************************************************************************* + const_reference back() const + { + return *(mend - 1); + } + + //************************************************************************* + /// Returns a const pointer to the first element of the internal storage. + //************************************************************************* + const_pointer data() const + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator begin() const + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator cbegin() const + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator end() const + { + return mend; + } + + //************************************************************************* + // Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator cend() const + { + return mend; + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(mbegin); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(mbegin); + } + + //************************************************************************* + // Capacity + //************************************************************************* + + //************************************************************************* + /// Returns <b>true</b> if the array size is zero. + //************************************************************************* + bool empty() const + { + return (mbegin == mend); + } + + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + size_t size() const + { + return (mend - mbegin); + } + + //************************************************************************* + /// Returns the maximum possible size of the array. + //************************************************************************* + size_t max_size() const + { + return size(); + } + + //************************************************************************* + /// Assign from a view. + //************************************************************************* + const_array_view<T>& operator=(const const_array_view<T>& other) + { + mbegin = other.mbegin; + mend = other.mend; + return *this; + } + + //************************************************************************* + /// Assign from iterators + //************************************************************************* + template <typename TIterator, + typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + void assign(TIterator begin_, TIterator end_) + { + mbegin = etl::addressof(*begin_); + mend = etl::addressof(*begin_) + std::distance(begin_, end_); + } + + //************************************************************************* + /// Assign from iterator and size. + //************************************************************************* + template <typename TIterator, + typename TSize, + typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + void assign(TIterator begin_, TSize size_) + { + mbegin = etl::addressof(*begin_); + mend = etl::addressof(*begin_) + size_; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference operator[](size_t i) const + { + return mbegin[i]; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference at(size_t i) const + { + ETL_ASSERT((mbegin != std::nullptr && mend != std::nullptr), ETL_ERROR(array_view_uninitialised)); + ETL_ASSERT(i < size(), ETL_ERROR(array_view_bounds)); + return mbegin[i]; + } + + //************************************************************************* + /// Swaps with another array_view. + //************************************************************************* + void swap(const_array_view& other) + { + std::swap(mbegin, other.mbegin); + std::swap(mend, other.mend); + } + + //************************************************************************* + /// Shrinks the view by moving its start forward. + //************************************************************************* + void remove_prefix(size_type n) + { + mbegin += n; + } + + //************************************************************************* + /// Shrinks the view by moving its end backward. + //************************************************************************* + void remove_suffix(size_type n) + { + mend -= n; + } + + //************************************************************************* + /// Equality for array views. + //************************************************************************* + friend bool operator == (const const_array_view<T>& lhs, const const_array_view<T>& rhs) + { + return (lhs.size() == rhs.size()) && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //************************************************************************* + /// Inequality for array views. + //************************************************************************* + friend bool operator != (const const_array_view<T>& lhs, const const_array_view<T>& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// Less-than for array views. + //************************************************************************* + friend bool operator < (const const_array_view<T>& lhs, const const_array_view<T>& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //************************************************************************* + /// Greater-than for array views. + //************************************************************************* + friend bool operator > (const const_array_view<T>& lhs, const const_array_view<T>& rhs) + { + return rhs < lhs; + } + + //************************************************************************* + /// Less-than-equal for array views. + //************************************************************************* + friend bool operator <= (const const_array_view<T>& lhs, const const_array_view<T>& rhs) + { + return !(lhs > rhs); + } + + //************************************************************************* + /// Greater-than-equal for array views. + //************************************************************************* + friend bool operator >= (const const_array_view<T>& lhs, const const_array_view<T>& rhs) + { + return !(lhs < rhs); + } + + private: + + const T* mbegin; + const T* mend; + }; + + //************************************************************************* + /// Hash function. + //************************************************************************* +#if ETL_8BIT_SUPPORT + template <typename T> + struct hash<etl::array_view<T> > + { + size_t operator()(const etl::array_view<T>& view) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&view[0]), + reinterpret_cast<const uint8_t*>(&view[view.size()])); + } + }; + + template <typename T> + struct hash<etl::const_array_view<T> > + { + size_t operator()(const etl::const_array_view<T>& view) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&view[0]), + reinterpret_cast<const uint8_t*>(&view[view.size()])); + } + }; +#endif +} + +//************************************************************************* +/// Swaps the values. +//************************************************************************* +template <typename T> +void swap(etl::array_view<T>& lhs, etl::array_view<T>& rhs) +{ + lhs.swap(rhs); +} + +//************************************************************************* +/// Swaps the values. +//************************************************************************* +template <typename T> +void swap(etl::const_array_view<T>& lhs, etl::const_array_view<T>& rhs) +{ + lhs.swap(rhs); +} + +#undef ETL_FILE + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/array_wrapper.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,422 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ARRAY_WRAPPER__ +#define __ETL_ARRAY_WRAPPER__ + +#include "platform.h" +#include "iterator.h" +#include "error_handler.h" +#include "exception.h" +#include "hash.h" +#include "container.h" +#include "parameter_type.h" + +#include <algorithm> + +///\defgroup array array +/// A wrapper for arrays +///\ingroup containers + +#undef ETL_FILE +#define ETL_FILE "42" + +namespace etl +{ + //*************************************************************************** + /// The base class for array_wrapper exceptions. + //*************************************************************************** + class array_wrapper_exception : public exception + { + public: + + array_wrapper_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the index is out of bounds. + //*************************************************************************** + class array_wrapper_bounds : public array_wrapper_exception + { + public: + + array_wrapper_bounds(string_type file_name_, numeric_type line_number_) + : array_wrapper_exception(ETL_ERROR_TEXT("array_wrapper:bounds", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Array wrapper. + //*************************************************************************** + template <typename T, std::size_t SIZE_, T(&ARRAY_)[SIZE_]> + class array_wrapper + { + public: + + typedef T value_type; + typedef std::size_t size_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef T* iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + typedef typename etl::parameter_type<T>::type parameter_t; + + // Indexes for positions in the array. + enum + { + SIZE = SIZE_, + MAX_SIZE = SIZE_, + FRONT = 0, + BACK = SIZE - 1, + BEGIN = 0, + END = SIZE, + RBEGIN = SIZE - 1, + REND = -1 + }; + + //************************************************************************* + /// Returns a reference to the first element. + //************************************************************************* + reference front() + { + return *&ARRAY_[FRONT]; + } + + //************************************************************************* + /// Returns a const reference to the first element. + //************************************************************************* + ETL_CONSTEXPR const_reference front() const + { + return *&ARRAY_[FRONT]; + } + + //************************************************************************* + /// Returns a reference to the last element. + //************************************************************************* + reference back() + { + return *&ARRAY_[BACK]; + } + + //************************************************************************* + /// Returns a const reference to the last element. + //************************************************************************* + ETL_CONSTEXPR const_reference back() const + { + return *&ARRAY_[BACK]; + } + + //************************************************************************* + /// Returns a pointer to the first element of the internal storage. + //************************************************************************* + pointer data() + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns a const pointer to the first element of the internal storage. + //************************************************************************* + ETL_CONSTEXPR const_pointer data() const + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns an iterator to the beginning of the array. + //************************************************************************* + iterator begin() + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + ETL_CONSTEXPR const_iterator begin() const + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + ETL_CONSTEXPR const_iterator cbegin() const + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns an iterator to the end of the array. + //************************************************************************* + iterator end() + { + return &ARRAY_[END]; + } + + //************************************************************************* + /// Returns a const iterator to the end of the array. + //************************************************************************* + ETL_CONSTEXPR const_iterator end() const + { + return &ARRAY_[END]; + } + + //************************************************************************* + // Returns a const iterator to the end of the array. + //************************************************************************* + ETL_CONSTEXPR const_iterator cend() const + { + return &ARRAY_[END]; + } + + //************************************************************************* + // Returns an reverse iterator to the reverse beginning of the array. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(&ARRAY_[END]); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + ETL_CONSTEXPR const_reverse_iterator rbegin() const + { + return const_reverse_iterator(&ARRAY_[END]); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + ETL_CONSTEXPR const_reverse_iterator crbegin() const + { + return const_reverse_iterator(&ARRAY_[END]); + } + + //************************************************************************* + /// Returns a reverse iterator to the end of the array. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(&ARRAY_[BEGIN]); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + ETL_CONSTEXPR const_reverse_iterator rend() const + { + return const_reverse_iterator(&ARRAY_[BEGIN]); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + ETL_CONSTEXPR const_reverse_iterator crend() const + { + return const_reverse_iterator(&ARRAY_[BEGIN]); + } + + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + ETL_CONSTEXPR size_t size() const + { + return SIZE; + } + + //************************************************************************* + /// Returns the maximum possible size of the array. + //************************************************************************* + ETL_CONSTEXPR size_t max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns a reference to the indexed value. + //************************************************************************* + reference operator[](size_t i) + { + return ARRAY_[i]; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + ETL_CONSTEXPR const_reference operator[](size_t i) const + { + return ARRAY_[i]; + } + + //************************************************************************* + /// Returns a reference to the indexed value. + //************************************************************************* + reference at(size_t i) + { + ETL_ASSERT(i < SIZE, ETL_ERROR(etl::array_wrapper_bounds)); + return ARRAY_[i]; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference at(size_t i) const + { + ETL_ASSERT(i < SIZE, ETL_ERROR(etl::array_wrapper_bounds)); + return ARRAY_[i]; + } + + //************************************************************************* + /// Fills the array. + //************************************************************************* + void fill(parameter_t value) + { + std::fill(begin(), end(), value); + } + + //************************************************************************* + /// Swaps the contents of arrays. + //************************************************************************* + template <typename U, U(&ARRAYOTHER)[SIZE_]> + typename etl::enable_if<etl::is_same<T, U>::value, void>::type + swap(etl::array_wrapper<U, SIZE_, ARRAYOTHER>& other) + { + for (size_t i = 0; i < SIZE; ++i) + { + std::swap(ARRAY_[i], other.begin()[i]); + } + } + }; + + //************************************************************************* + /// Equality for array wrappers. + //************************************************************************* + template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]> + bool operator == (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs, + const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs) + { + return (SIZEL == SIZER) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //************************************************************************* + /// Inequality for array wrapper. + //************************************************************************* + template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]> + bool operator != (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs, + const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// Less-than for array wrapper. + //************************************************************************* + template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]> + bool operator < (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs, + const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //************************************************************************* + /// Greater-than for array wrapper. + //************************************************************************* + template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]> + bool operator > (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs, + const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs) + { + return rhs < lhs; + } + + //************************************************************************* + /// Less-than-equal for array wrapper. + //************************************************************************* + template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]> + bool operator <= (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs, + const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs) + { + return !(lhs > rhs); + } + + //************************************************************************* + /// Greater-than-equal for array wrapper. + //************************************************************************* + template <typename TL, typename TR, std::size_t SIZEL, std::size_t SIZER, TL(&ARRAYL)[SIZEL], TR(&ARRAYR)[SIZER]> + bool operator >= (const etl::array_wrapper<TL, SIZEL, ARRAYL>& lhs, + const etl::array_wrapper<TR, SIZER, ARRAYR>& rhs) + { + return !(lhs < rhs); + } + + //************************************************************************* + /// Hash function. + //************************************************************************* +#if ETL_8BIT_SUPPORT + template <typename T, std::size_t SIZE, T(&ARRAY)[SIZE]> + struct hash<etl::array_wrapper<T, SIZE, ARRAY> > + { + size_t operator()(const etl::array_wrapper<T, SIZE, ARRAY>& aw) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&aw[0]), + reinterpret_cast<const uint8_t*>(&aw[aw.size()])); + } + }; +#endif +} + +//************************************************************************* +/// Swap. +//************************************************************************* +template <typename T, std::size_t SIZE, T(&ARRAYL)[SIZE], T(&ARRAYR)[SIZE]> +void swap(etl::array_wrapper<T, SIZE, ARRAYL>& lhs, + etl::array_wrapper<T, SIZE, ARRAYR>& rhs) +{ + lhs.swap(rhs); +} + +#define ETL_ARRAY_WRAPPER(arraytype, arrayobject) etl::array_wrapper<arraytype, ETL_ARRAY_SIZE(arrayobject), arrayobject> + +#undef ETL_FILE + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/atomic.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,52 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ATOMIC__ +#define __ETL_ATOMIC__ + +#include "platform.h" + +#if ETL_ATOMIC_SUPPORTED == 1 + #include <atomic> + + namespace etl + { + typedef std::atomic<uint32_t> atomic_uint32_t; + } +#elif defined(ETL_COMPILER_ARM) + #include "atomic/atomic_arm.h" +#elif defined(ETL_COMPILER_GCC) + #include "atomic/atomic_gcc.h" +#elif defined(ETL_COMPILER_MSVC) + #include "atomic/atomic_windows.h" +#else + #warning NO ATOMIC SUPPORT DEFINED! +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/atomic/atomic_arm.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,35 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ATOMIC_ARM__ +#define __ETL_ATOMIC_ARM__ + +#include "atomic_gcc.h" + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/atomic/atomic_gcc.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,634 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ATOMIC_GCC__ +#define __ETL_ATOMIC_GCC__ + +#include "../platform.h" +#include "../type_traits.h" +#include "../char_traits.h" +#include "../static_assert.h" +#include "../nullptr.h" + +#include <stdint.h> + +namespace etl +{ + //*************************************************************************** + // Atomic type for pre C++11 GCC compilers that support the builtin 'fetch' functions. + // Only integral and pointer types are supported. + //*************************************************************************** + template <typename T> + class atomic + { + public: + + STATIC_ASSERT(etl::is_integral<T>::value, "Only integral types are supported"); + + atomic() + : value(0) + { + } + + atomic(T v) + : value(v) + { + } + + // Assignment + T operator =(T v) + { + __sync_lock_test_and_set(&value, v); + + return v; + } + + T operator =(T v) volatile + { + __sync_lock_test_and_set(&value, v); + + return v; + } + + // Pre-increment + T operator ++() + { + return fetch_add(1) + 1; + } + + T operator ++() volatile + { + return fetch_add(1) + 1; + } + + // Post-increment + T operator ++(int) + { + return fetch_add(1); + } + + T operator ++(int) volatile + { + return fetch_add(1); + } + + // Pre-decrement + T operator --() + { + return fetch_sub(1) + 1; + } + + T operator --() volatile + { + return fetch_sub(1) + 1; + } + + // Post-decrement + T operator --(int) + { + return fetch_sub(1); + } + + T operator --(int) volatile + { + return fetch_sub(1); + } + + // Add + T operator +=(T v) + { + return fetch_add(v) + v; + } + + T operator +=(T v) volatile + { + return fetch_add(v) + v; + } + + // Subtract + T operator -=(T v) + { + return fetch_sub(v) - v; + } + + T operator -=(T v) volatile + { + return fetch_sub(v) - v; + } + + // And + T operator &=(T v) + { + return fetch_and(v) & v; + } + + T operator &=(T v) volatile + { + return fetch_and(v) & v; + } + + // Or + T operator |=(T v) + { + return fetch_or(v) | v; + } + + T operator |=(T v) volatile + { + return fetch_or(v) | v; + } + + // Exclusive or + T operator ^=(T v) + { + return fetch_xor(v) ^ v; + } + + T operator ^=(T v) volatile + { + return fetch_xor(v) ^ v; + } + + // Conversion operator + operator T () const + { + return __sync_fetch_and_add(const_cast<T*>(&value), 0); + } + + operator T() volatile const + { + return __sync_fetch_and_add(const_cast<T*>(&value), 0); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(T v) + { + __sync_lock_test_and_set(&value, v); + } + + void store(T v) volatile + { + __sync_lock_test_and_set(&value, v); + } + + // Load + T load() + { + return __sync_fetch_and_add(&value, 0); + } + + T load() volatile + { + return __sync_fetch_and_add(&value, 0); + } + + // Fetch add + T fetch_add(T v) + { + return __sync_fetch_and_add(&value, v); + } + + T fetch_add(T v) volatile + { + return __sync_fetch_and_add(&value, v); + } + + // Fetch subtract + T fetch_sub(T v) + { + return __sync_fetch_and_sub(&value, v); + } + + T fetch_sub(T v) volatile + { + return __sync_fetch_and_sub(&value, v); + } + + // Fetch or + T fetch_or(T v) + { + return __sync_fetch_and_or(&value, v); + } + + T fetch_or(T v) volatile + { + return __sync_fetch_and_or(&value, v); + } + + // Fetch and + T fetch_and(T v) + { + return __sync_fetch_and_and(&value, v); + } + + T fetch_and(T v) volatile + { + return __sync_fetch_and_and(&value, v); + } + + // Fetch exclusive or + T fetch_xor(T v) + { + return __sync_fetch_and_xor(&value, v); + } + + T fetch_xor(T v) volatile + { + return __sync_fetch_and_xor(&value, v); + } + + // Exchange + T exchange(T v) + { + return __sync_lock_test_and_set(&value, v); + } + + T exchange(T v) volatile + { + return __sync_lock_test_and_set(&value, v); + } + + // Compare exchange weak + bool compare_exchange_weak(T& expected, T desired) + { + T old = __sync_val_compare_and_swap(&value, expected, desired); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(T& expected, T desired) volatile + { + T old = __sync_val_compare_and_swap(&value, expected, desired); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + // Compare exchange strong + bool compare_exchange_strong(T& expected, T desired) + { + T old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(T& expected, T desired) volatile + { + T old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T))) + { + expected = old; + return false; + } + } + + return true; + } + + private: + + atomic& operator =(const atomic&); + atomic& operator =(const atomic&) volatile; + + T value; + }; + + //*************************************************************************** + // Specialisation for pointers. + //*************************************************************************** + template <typename T> + class atomic<T*> + { + public: + + atomic() + : value(std::nullptr) + { + } + + atomic(T v) + : value(v) + { + } + + // Assignment + T operator =(T* v) + { + __sync_lock_test_and_set(&value, v); + + return v; + } + + T operator =(T* v) volatile + { + __sync_lock_test_and_set(&value, v); + + return v; + } + + // Pre-increment + T operator ++() + { + return fetch_add(1) + 1; + } + + T operator ++() volatile + { + return fetch_add(1) + 1; + } + + // Post-increment + T operator ++(int) + { + return fetch_add(1); + } + + T operator ++(int) volatile + { + return fetch_add(1); + } + + // Pre-decrement + T operator --() + { + return fetch_sub(1) + 1; + } + + T operator --() volatile + { + return fetch_sub(1) + 1; + } + + // Post-decrement + T operator --(int) + { + return fetch_sub(1); + } + + T operator --(int) volatile + { + return fetch_sub(1); + } + + // Add + T* operator +=(std::ptrdiff_t v) + { + return fetch_add(v) + v; + } + + T* operator +=(std::ptrdiff_t v) volatile + { + return fetch_add(v) + v; + } + + // Subtract + T* operator -=(std::ptrdiff_t v) + { + return fetch_sub(v) - v; + } + + T* operator -=(std::ptrdiff_t v) volatile + { + return fetch_sub(v) - v; + } + + // Conversion operator + operator T () const + { + return __sync_fetch_and_add(const_cast<T**>(&value), 0); + } + + operator T() volatile const + { + return __sync_fetch_and_add(const_cast<T**>(&value), 0); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(T v) + { + __sync_lock_test_and_set(&value, v); + } + + void store(T v) volatile + { + __sync_lock_test_and_set(&value, v); + } + + // Load + T load() + { + return __sync_fetch_and_add(&value, 0); + } + + T load() volatile + { + return __sync_fetch_and_add(&value, 0); + } + + // Fetch add + T* fetch_add(std::ptrdiff_t v) + { + return __sync_fetch_and_add(&value, v); + } + + T* fetch_add(std::ptrdiff_t v) volatile + { + return __sync_fetch_and_add(&value, v); + } + + // Fetch subtract + T* fetch_sub(std::ptrdiff_t v) + { + return __sync_fetch_and_sub(&value, v); + } + + T* fetch_sub(std::ptrdiff_t v) volatile + { + return __sync_fetch_and_sub(&value, v); + } + + // Exchange + T exchange(T v) + { + return __sync_lock_test_and_set(&value, v); + } + + T exchange(T v) volatile + { + return __sync_lock_test_and_set(&value, v); + } + + // Compare exchange weak + bool compare_exchange_weak(T& expected, T desired) + { + return __sync_bool_compare_and_swap(&value, expected, desired); + } + + bool compare_exchange_weak(T& expected, T desired) volatile + { + return __sync_bool_compare_and_swap(&value, expected, desired); + } + + // Compare exchange strong + bool compare_exchange_strong(T& expected, T desired) + { + T old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(T& expected, T desired) volatile + { + T old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T))) + { + expected = old; + return false; + } + } + + return true; + } + + private: + + atomic& operator =(const atomic&); + atomic& operator =(const atomic&) volatile; + + T* value; + }; + + typedef etl::atomic<char> atomic_char; + typedef etl::atomic<signed char> atomic_schar; + typedef etl::atomic<unsigned char> atomic_uchar; + typedef etl::atomic<short> atomic_short; + typedef etl::atomic<unsigned short> atomic_ushort; + typedef etl::atomic<int> atomic_int; + typedef etl::atomic<unsigned int> atomic_uint; + typedef etl::atomic<long> atomic_long; + typedef etl::atomic<unsigned long> atomic_ulong; + typedef etl::atomic<long long> atomic_llong; + typedef etl::atomic<unsigned long long> atomic_ullong; + typedef etl::atomic<wchar_t> atomic_wchar_t; + typedef etl::atomic<char16_t> atomic_char16_t; + typedef etl::atomic<char32_t> atomic_char32_t; + typedef etl::atomic<uint8_t> atomic_uint8_t; + typedef etl::atomic<int8_t> atomic_int8_t; + typedef etl::atomic<uint16_t> atomic_uint16_t; + typedef etl::atomic<int16_t> atomic_int16_t; + typedef etl::atomic<uint32_t> atomic_uint32_t; + typedef etl::atomic<int32_t> atomic_int32_t; + typedef etl::atomic<uint64_t> atomic_uint64_t; + typedef etl::atomic<int64_t> atomic_int64_t; + typedef etl::atomic<int_least8_t> atomic_int_least8_t; + typedef etl::atomic<uint_least8_t> atomic_uint_least8_t; + typedef etl::atomic<int_least16_t> atomic_int_least16_t; + typedef etl::atomic<uint_least16_t> atomic_uint_least16_t; + typedef etl::atomic<int_least32_t> atomic_int_least32_t; + typedef etl::atomic<uint_least32_t> atomic_uint_least32_t; + typedef etl::atomic<int_least64_t> atomic_int_least64_t; + typedef etl::atomic<uint_least64_t> atomic_uint_least64_t; + typedef etl::atomic<int_fast8_t> atomic_int_fast8_t; + typedef etl::atomic<uint_fast8_t> atomic_uint_fast8_t; + typedef etl::atomic<int_fast16_t> atomic_int_fast16_t; + typedef etl::atomic<uint_fast16_t> atomic_uint_fast16_t; + typedef etl::atomic<int_fast32_t> atomic_int_fast32_t; + typedef etl::atomic<uint_fast32_t> atomic_uint_fast32_t; + typedef etl::atomic<int_fast64_t> atomic_int_fast64_t; + typedef etl::atomic<uint_fast64_t> atomic_uint_fast64_t; + typedef etl::atomic<intptr_t> atomic_intptr_t; + typedef etl::atomic<uintptr_t> atomic_uintptr_t; + typedef etl::atomic<size_t> atomic_size_t; + typedef etl::atomic<ptrdiff_t> atomic_ptrdiff_t; + typedef etl::atomic<intmax_t> atomic_intmax_t; + typedef etl::atomic<uintmax_t> atomic_uintmax_t; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/atomic/atomic_windows.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,105 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ATOMIC_WINDOWS__ +#define __ETL_ATOMIC_WINDOWS__ + +#include "../platform.h" + +#include <stdint.h> +#include <Windows.h> + +namespace etl +{ + class atomic_uint32_t + { + public: + + atomic_uint32_t() + { + InterlockedExchange(&value, 0); + } + + atomic_uint32_t(uint32_t v) + { + InterlockedExchange(&value, v); + } + + atomic_uint32_t& operator =(uint32_t v) + { + InterlockedExchange(&value, v); + + return *this; + } + + atomic_uint32_t& operator ++() + { + InterlockedIncrement(&value); + + return *this; + } + + volatile atomic_uint32_t& operator ++() volatile + { + InterlockedIncrement(&value); + + return *this; + } + + atomic_uint32_t& operator --() + { + InterlockedDecrement(&value); + + return *this; + } + + volatile atomic_uint32_t& operator --() volatile + { + InterlockedDecrement(&value); + + return *this; + } + + operator uint32_t () const + { + return InterlockedAdd((volatile long*)&value, 0); + } + + operator uint32_t() volatile const + { + return InterlockedAdd((volatile long*)&value, 0); + } + + private: + + uint32_t value; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/basic_string.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,2226 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_BASIC_STRING__ +#define __ETL_BASIC_STRING__ + +#include <stddef.h> +#include <stdint.h> +#include <iterator> +#include <algorithm> +#include <functional> +#include <string.h> + +#include "platform.h" +#include "char_traits.h" +#include "container.h" +#include "alignment.h" +#include "array.h" +#include "algorithm.h" +#include "type_traits.h" +#include "error_handler.h" +#include "integral_limits.h" +#include "exception.h" + +#define ETL_FILE "27" + +#ifdef ETL_COMPILER_GCC +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#ifdef ETL_COMPILER_MICROSOFT +#undef max +#endif + +//***************************************************************************** +///\defgroup basic_string basic_string +/// A basic_string with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Alternative strlen for all character types. + //*************************************************************************** + template <typename T> + size_t strlen(const T* t) + { + return etl::char_traits<T>::length(t); + } + + //*************************************************************************** + ///\ingroup string + /// Exception base for strings + //*************************************************************************** + class string_exception : public etl::exception + { + public: + + string_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup string + /// String empty exception. + //*************************************************************************** + class string_empty : public etl::string_exception + { + public: + + string_empty(string_type file_name_, numeric_type line_number_) + : string_exception(ETL_ERROR_TEXT("string:empty", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup string + /// String out of bounds exception. + //*************************************************************************** + class string_out_of_bounds : public etl::string_exception + { + public: + + string_out_of_bounds(string_type file_name_, numeric_type line_number_) + : string_exception(ETL_ERROR_TEXT("string:bounds", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup string + /// String iterator exception. + //*************************************************************************** + class string_iterator : public etl::string_exception + { + public: + + string_iterator(string_type file_name_, numeric_type line_number_) + : string_exception(ETL_ERROR_TEXT("string:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup string + /// The base class for all templated string types. + //*************************************************************************** + class string_base + { + public: + + typedef size_t size_type; + + enum + { + npos = etl::integral_limits<size_t>::max + }; + + //************************************************************************* + /// Gets the current size of the string. + ///\return The current size of the string. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Gets the current size of the string. + ///\return The current size of the string. + //************************************************************************* + size_type length() const + { + return current_size; + } + + //************************************************************************* + /// Checks the 'empty' state of the string. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return (current_size == 0); + } + + //************************************************************************* + /// Checks the 'full' state of the string. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return current_size == CAPACITY; + } + + //************************************************************************* + /// Returns the capacity of the string. + ///\return The capacity of the string. + //************************************************************************* + size_type capacity() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the maximum possible size of the string. + ///\return The maximum size of the string. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + //************************************************************************* + /// Returns whether the string was truncated by the last operation. + ///\return Whether the string was truncated by the last operation. + //************************************************************************* + size_t truncated() const + { + return is_truncated; + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + string_base(size_type max_size_) + : is_truncated(false), + current_size(0), + CAPACITY(max_size_) + { + } + + bool is_truncated; ///< Set to true if the operation truncated the string. + size_type current_size; ///< The current number of elements in the string. + const size_type CAPACITY; ///< The maximum number of elements in the string. + }; + + //*************************************************************************** + /// The base class for specifically sized strings. + /// Can be used as a reference type for all strings containing a specific type. + ///\ingroup string + //*************************************************************************** + template <typename T> + class ibasic_string : public etl::string_base + { + public: + + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef T* iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef size_t size_type; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the string. + ///\return An iterator to the beginning of the string. + //********************************************************************* + iterator begin() + { + return &p_buffer[0]; + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the string. + ///\return A const iterator to the beginning of the string. + //********************************************************************* + const_iterator begin() const + { + return &p_buffer[0]; + } + + //********************************************************************* + /// Returns an iterator to the end of the string. + ///\return An iterator to the end of the string. + //********************************************************************* + iterator end() + { + return &p_buffer[current_size]; + } + + //********************************************************************* + /// Returns a const_iterator to the end of the string. + ///\return A const iterator to the end of the string. + //********************************************************************* + const_iterator end() const + { + return &p_buffer[current_size]; + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the string. + ///\return A const iterator to the beginning of the string. + //********************************************************************* + const_iterator cbegin() const + { + return &p_buffer[0]; + } + + //********************************************************************* + /// Returns a const_iterator to the end of the string. + ///\return A const iterator to the end of the string. + //********************************************************************* + const_iterator cend() const + { + return &p_buffer[current_size]; + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the string. + ///\return Iterator to the reverse beginning of the string. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the string. + ///\return Const iterator to the reverse beginning of the string. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the string. + ///\return Reverse iterator to the end + 1 of the string. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the string. + ///\return Const reverse iterator to the end + 1 of the string. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the string. + ///\return Const reverse iterator to the reverse beginning of the string. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the string. + ///\return Const reverse iterator to the end + 1 of the string. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + //********************************************************************* + /// Resizes the string. + /// If asserts or exceptions are enabled and the new size is larger than the + ///\param new_size The new size. + //********************************************************************* + void resize(size_t new_size) + { + resize(new_size, 0); + } + + //********************************************************************* + /// Resizes the string. + ///\param new_size The new size. + ///\param value The value to fill new elements with. Default = default constructed value. + //********************************************************************* + void resize(size_t new_size, T value) + { + new_size = std::min(new_size, CAPACITY); + + // Size up? + if (new_size > current_size) + { + std::fill(p_buffer + current_size, p_buffer + new_size, value); + } + + current_size = new_size; + p_buffer[new_size] = 0; + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference operator [](size_t i) + { + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference operator [](size_t i) const + { + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::string_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference at(size_t i) + { + ETL_ASSERT(i < size(), ETL_ERROR(string_out_of_bounds)); + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::string_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference at(size_t i) const + { + ETL_ASSERT(i < size(), ETL_ERROR(string_out_of_bounds)); + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a reference to the first element. + ///\return A reference to the first element. + //********************************************************************* + reference front() + { + return p_buffer[0]; + } + + //********************************************************************* + /// Returns a const reference to the first element. + ///\return A const reference to the first element. + //********************************************************************* + const_reference front() const + { + return p_buffer[0]; + } + + //********************************************************************* + /// Returns a reference to the last element. + ///\return A reference to the last element. + //********************************************************************* + reference back() + { + return p_buffer[current_size - 1]; + } + + //********************************************************************* + /// Returns a const reference to the last element. + ///\return A const reference to the last element. + //********************************************************************* + const_reference back() const + { + return p_buffer[current_size - 1]; + } + + //********************************************************************* + /// Returns a pointer to the beginning of the string data. + ///\return A pointer to the beginning of the string data. + //********************************************************************* + pointer data() + { + return p_buffer; + } + + //********************************************************************* + /// Returns a const pointer to the beginning of the string data. + ///\return A const pointer to the beginning of the string data. + //********************************************************************* + const_pointer data() const + { + return p_buffer; + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param other The other string. + //********************************************************************* + void assign(const etl::ibasic_string<T>& other) + { + size_t len = std::min(CAPACITY, other.size()); + assign(other.begin(), other.begin() + len); + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param other The other string. + ///\param subposition The position to start from. + ///\param sublength The length to copy. + //********************************************************************* + void assign(const etl::ibasic_string<T>& other, size_t subposition, size_t sublength) + { + if (sublength == npos) + { + sublength = other.size() - subposition; + } + + ETL_ASSERT(subposition <= other.size(), ETL_ERROR(string_out_of_bounds)); + + assign(other.begin() + subposition, sublength); + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param other The other string. + //********************************************************************* + void assign(const_pointer other) + { + initialise(); + + while ((*other != 0) && (current_size < CAPACITY)) + { + p_buffer[current_size++] = *other++; + } + + is_truncated = (*other != 0); + + p_buffer[current_size] = 0; + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param other The other string. + ///\param length The length to copy. + //********************************************************************* + void assign(const_pointer other, size_t length_) + { + length_ = std::min(length_, CAPACITY); + + initialise(); + + etl::copy_n(other, length_, begin()); + + current_size = length_; + p_buffer[current_size] = 0; + } + + //********************************************************************* + /// Assigns values to the string. + /// If asserts or exceptions are enabled, emits string_iterator if the iterators are reversed. + /// Truncates if the string does not have enough free space. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d >= 0, ETL_ERROR(string_iterator)); +#endif + + initialise(); + + while ((first != last) && (current_size != CAPACITY)) + { + p_buffer[current_size++] = *first++; + } + + p_buffer[current_size] = 0; + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param n The number of elements to add. + ///\param value The value to insert for each element. + //********************************************************************* + void assign(size_t n, T value) + { + initialise(); + + n = std::min(n, CAPACITY); + + std::fill_n(begin(), n, value); + current_size = n; + p_buffer[current_size] = 0; + } + + //************************************************************************* + /// Clears the string. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Inserts a value at the end of the string. + /// Sets 'truncated' if the string is already full. + ///\param value The value to add. + //********************************************************************* + void push_back(T value) + { + if (current_size != CAPACITY) + { + p_buffer[current_size++] = value; + is_truncated = false; + } + else + { + is_truncated = true; + } + } + + //************************************************************************* + /// Removes an element from the end of the string. + /// Does nothing if the string is empty. + //************************************************************************* + void pop_back() + { + if (current_size != 0) + { + p_buffer[--current_size] = 0; + } + } + + //********************************************************************* + /// Appends to the string. + ///\param str The string to append. + //********************************************************************* + ibasic_string& append(const ibasic_string& str) + { + insert(end(), str.begin(), str.end()); + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param str The string to append. + ///\param subposition The position in str. + ///\param sublength The number of characters. + //********************************************************************* + ibasic_string& append(const ibasic_string& str, size_t subposition, size_t sublength = npos) + { + ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds)); + + insert(size(), str, subposition, sublength); + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param str The string to append. + //********************************************************************* + ibasic_string& append(const T* str) + { + insert(size(), str); + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param str The string to append. + ///\param n The number of characters. + //********************************************************************* + ibasic_string& append(const T* str, size_t n) + { + insert(size(), str, n); + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param n The number of characters. + ///\param c The character. + //********************************************************************* + ibasic_string& append(size_t n, T c) + { + insert(size(), n, c); + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param first The first of the characters to append. + ///\param last The last + 1 character to add. + //********************************************************************* + template <class TIterator> + ibasic_string& append(TIterator first, TIterator last) + { + insert(end(), first, last); + return *this; + } + + //********************************************************************* + /// Inserts a value to the string. + ///\param position The position to insert before. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator position, T value) + { + is_truncated = false; + + // Quick hack, as iterators are pointers. + iterator insert_position = const_cast<iterator>(position); + + if (current_size < CAPACITY) + { + // Not full yet. + if (position != end()) + { + // Insert in the middle. + ++current_size; + std::copy_backward(insert_position, end() - 1, end()); + *insert_position = value; + } + else + { + // Insert at the end. + *insert_position = value; + ++current_size; + } + } + else + { + // Already full. + if (position != end()) + { + // Insert in the middle. + std::copy_backward(insert_position, end() - 1, end()); + *insert_position = value; + } + + is_truncated = true; + } + + p_buffer[current_size] = 0; + + return insert_position; + } + + //********************************************************************* + /// Inserts 'n' values to the string. + ///\param position The position to insert before. + ///\param n The number of elements to add. + ///\param value The value to insert. + //********************************************************************* + void insert(const_iterator position, size_t n, T value) + { + is_truncated = false; + + if (n == 0) + { + return; + } + + // Quick hack, as iterators are pointers. + iterator insert_position = const_cast<iterator>(position); + const size_t start = std::distance(cbegin(), position); + + // No effect. + if (start == CAPACITY) + { + return; + } + + // Fills the string to the end? + if ((start + n) >= CAPACITY) + { + is_truncated = ((current_size + n) > CAPACITY); + current_size = CAPACITY; + std::fill(insert_position, end(), value); + } + else + { + // Lets do some shifting. + const size_t shift_amount = n; + const size_t to_position = start + shift_amount; + const size_t remaining_characters = current_size - start; + const size_t max_shift_characters = CAPACITY - start - shift_amount; + const size_t characters_to_shift = std::min(max_shift_characters, remaining_characters); + + // Will the string truncate? + if ((start + shift_amount + remaining_characters) > CAPACITY) + { + current_size = CAPACITY; + is_truncated = true; + } + else + { + current_size += shift_amount; + } + + std::copy_backward(insert_position, insert_position + characters_to_shift, begin() + to_position + characters_to_shift); + std::fill(insert_position, insert_position + shift_amount, value); + } + + p_buffer[current_size] = 0; + } + + //********************************************************************* + /// Inserts a range of values to the string. + /// If asserts or exceptions are enabled, emits string_full if the string does not have enough free space. + ///\param position The position to insert before. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(iterator position, TIterator first, TIterator last) + { + is_truncated = false; + + if (first == last) + { + return; + } + + const size_t start = std::distance(begin(), position); + const size_t n = std::distance(first, last); + + // No effect. + if (start == CAPACITY) + { + return; + } + + // Fills the string to the end? + if ((start + n) >= CAPACITY) + { + is_truncated = ((current_size + n) > CAPACITY); + current_size = CAPACITY; + + while (position != end()) + { + *position++ = *first++; + } + } + else + { + // Lets do some shifting. + const size_t shift_amount = n; + const size_t to_position = start + shift_amount; + const size_t remaining_characters = current_size - start; + const size_t max_shift_characters = CAPACITY - start - shift_amount; + const size_t characters_to_shift = std::min(max_shift_characters, remaining_characters); + + // Will the string truncate? + if ((start + shift_amount + remaining_characters) > CAPACITY) + { + current_size = CAPACITY; + is_truncated = true; + } + else + { + current_size += shift_amount; + } + + std::copy_backward(position, position + characters_to_shift, begin() + to_position + characters_to_shift); + + while (first != last) + { + *position++ = *first++; + } + } + + p_buffer[current_size] = 0; + } + + //********************************************************************* + /// Inserts a string at the specified position. + ///\param position The position to insert before. + ///\param str The string to insert. + //********************************************************************* + etl::ibasic_string<T>& insert(size_t position, const etl::ibasic_string<T>& str) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + insert(begin() + position, str.cbegin(), str.cend()); + return *this; + } + + //********************************************************************* + /// Inserts a string at the specified position from subposition for sublength. + ///\param position The position to insert before. + ///\param str The string to insert. + ///\param subposition The subposition to start from. + ///\param sublength The number of characters to insert. + //********************************************************************* + etl::ibasic_string<T>& insert(size_t position, const etl::ibasic_string<T>& str, size_t subposition, size_t sublength) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds)); + + if ((sublength == npos) || (subposition + sublength > str.size())) + { + sublength = str.size() - subposition; + } + + insert(begin() + position, str.cbegin() + subposition, str.cbegin() + subposition + sublength); + return *this; + } + + //********************************************************************* + /// Inserts a string at the specified position from pointer. + ///\param position The position to insert before. + ///\param s The string to insert. + //********************************************************************* + etl::ibasic_string<T>& insert(size_t position, const_pointer s) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + insert(begin() + position, s, s + strlen(s)); + return *this; + } + + //********************************************************************* + /// Inserts a string at the specified position from pointer for n characters. + ///\param position The position to insert before. + ///\param s The string to insert. + ///\param n The number of characters to insert. + //********************************************************************* + etl::ibasic_string<T>& insert(size_t position, const_pointer s, size_t n) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + insert(begin() + position, s, s + n); + return *this; + } + + //********************************************************************* + /// Insert n characters of c at position. + ///\param position The position to insert before. + ///\param n The number of characters to insert. + ///\param c The character to insert. + //********************************************************************* + etl::ibasic_string<T>& insert(size_t position, size_t n, value_type c) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + insert(begin() + position, n, c); + return *this; + } + + //********************************************************************* + /// Erases a sequence. + ///\param position Position to start from. + ///\param length Number of characters. + ///\return A refernce to this string. + //********************************************************************* + etl::ibasic_string<T>& erase(size_t position, size_t length_ = npos) + { + // Limit the length. + length_ = std::min(length_, size() - position); + + erase(begin() + position, begin() + position + length_); + + return *this; + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(iterator i_element) + { + std::copy(i_element + 1, end(), i_element); + p_buffer[--current_size] = 0; + + return i_element; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(iterator first, iterator last) + { + std::copy(last, end(), first); + size_t n_delete = std::distance(first, last); + + current_size -= n_delete; + p_buffer[current_size] = 0; + + return first; + } + + //********************************************************************* + /// Return a pointer to a C string. + //********************************************************************* + const_pointer c_str() const + { + return p_buffer; + } + + //********************************************************************* + /// Copies a portion of a string. + ///\param s Pointer to the string to copy. + ///\param len The number of characters to copy. + ///\param pos The position to start copying from. + //********************************************************************* + size_t copy(pointer s, size_t len, size_t pos = 0) + { + size_t endpos = std::min(pos + len, size()); + + for (size_t i = pos; i < endpos; ++i) + { + *s++ = p_buffer[i]; + } + + return endpos - pos; + } + + //********************************************************************* + /// Find content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find(const ibasic_string<T>& str, size_t pos = 0) const + { + if ((pos + str.size()) > size()) + { + return npos; + } + + const_iterator iposition = std::search(begin() + pos, end(), str.begin(), str.end()); + + if (iposition == end()) + { + return npos; + } + else + { + return std::distance(begin(), iposition); + } + } + + //********************************************************************* + /// Find content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find(const_pointer s, size_t pos = 0) const + { +#if defined(ETL_DEBUG) + if ((pos + etl::strlen(s)) > size()) + { + return npos; + } +#endif + + const_iterator iposition = std::search(begin() + pos, end(), s, s + etl::strlen(s)); + + if (iposition == end()) + { + return npos; + } + else + { + return std::distance(begin(), iposition); + } + } + + //********************************************************************* + /// Find content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + ///\param n The number of characters to search for. + //********************************************************************* + size_t find(const_pointer s, size_t pos, size_t n) const + { +#if defined(ETL_DEBUG) + if ((pos + etl::strlen(s) - n) > size()) + { + return npos; + } +#endif + + const_iterator iposition = std::search(begin() + pos, end(), s, s + n); + + if (iposition == end()) + { + return npos; + } + else + { + return std::distance(begin(), iposition); + } + } + + //********************************************************************* + /// Find character within the string + ///\param c The character to find. + ///\param position The position to start searching from. + //********************************************************************* + size_t find(T c, size_t position = 0) const + { + const_iterator i = std::find(begin() + position, end(), c); + + if (i != end()) + { + return std::distance(begin(), i); + } + else + { + return npos; + } + } + + //********************************************************************* + /// Find content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t rfind(const ibasic_string<T>& str, size_t position = npos) const + { + if ((str.size()) > size()) + { + return npos; + } + + if (position >= size()) + { + position = size(); + } + + position = size() - position; + + const_reverse_iterator iposition = std::search(rbegin() + position, rend(), str.rbegin(), str.rend()); + + if (iposition == rend()) + { + return npos; + } + else + { + return size() - str.size() - std::distance(rbegin(), iposition); + } + } + + //********************************************************************* + /// Find content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t rfind(const_pointer s, size_t position = npos) const + { + size_t len = etl::strlen(s); + + if (len > size()) + { + return npos; + } + + if (position >= size()) + { + position = size(); + } + + position = size() - position; + + const_reverse_iterator srbegin(s + len); + const_reverse_iterator srend(s); + + const_reverse_iterator iposition = std::search(rbegin() + position, rend(), srbegin, srend); + + if (iposition == rend()) + { + return npos; + } + else + { + return size() - len - std::distance(rbegin(), iposition); + } + } + + //********************************************************************* + /// Find content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t rfind(const_pointer s, size_t position, size_t length_) const + { + if (length_ > size()) + { + return npos; + } + + if (position >= size()) + { + position = size(); + } + + position = size() - position; + + const_reverse_iterator srbegin(s + length_); + const_reverse_iterator srend(s); + + const_reverse_iterator iposition = std::search(rbegin() + position, rend(), srbegin, srend); + + if (iposition == rend()) + { + return npos; + } + else + { + return size() - length_ - std::distance(rbegin(), iposition); + } + } + + //********************************************************************* + /// Find character within the string + ///\param c The character to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t rfind(T c, size_t position = npos) const + { + if (position >= size()) + { + position = size(); + } + + position = size() - position; + + const_reverse_iterator i = std::find(rbegin() + position, rend(), c); + + if (i != rend()) + { + return size() - std::distance(rbegin(), i) - 1; + } + else + { + return npos; + } + } + + //********************************************************************* + /// Replace 'length' characters from 'position' with 'str'. + ///\param position The position to start from. + ///\param length The number of characters to replace. + ///\param str The string to replace it with. + //********************************************************************* + ibasic_string& replace(size_t position, size_t length_, const ibasic_string& str) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = std::min(length_, size() - position); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, str); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' to one before 'last' with 'str'. + ///\param first The position to start from. + ///\param last The one after the position to end at. + ///\param str The string to replace it with. + //********************************************************************* + ibasic_string& replace(const_iterator first, const_iterator last, const ibasic_string& str) + { + // Quick hack, as iterators are pointers. + iterator first_ = const_cast<iterator>(first); + iterator last_ = const_cast<iterator>(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, str.begin(), str.end()); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'position' of 'length' with 'str' from 'subpsotion' of 'sublength'. + //********************************************************************* + ibasic_string& replace(size_t position, size_t length_, const ibasic_string& str, size_t subposition, size_t sublength) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the lengths. + length_ = std::min(length_, size() - position); + sublength = std::min(sublength, str.size() - subposition); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, str, subposition, sublength); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'position' of 'length' with pointed to string. + //********************************************************************* + ibasic_string& replace(size_t position, size_t length_, const_pointer s) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = std::min(length_, size() - position); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, s, etl::strlen(s)); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' 'last' with pointed to string. + //********************************************************************* + ibasic_string& replace(const_iterator first, const_iterator last, const_pointer s) + { + // Quick hack, as iterators are pointers. + iterator first_ = const_cast<iterator>(first); + iterator last_ = const_cast<iterator>(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, s, s + etl::strlen(s)); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'position' of 'length' with 'n' characters from pointed to string. + //********************************************************************* + ibasic_string& replace(size_t position, size_t length_, const_pointer s, size_t n) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = std::min(length_, size() - position); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, s, n); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' to 'last' with 'n' characters from pointed to string. + //********************************************************************* + ibasic_string& replace(const_iterator first, const_iterator last, const_pointer s, size_t n) + { + // Quick hack, as iterators are pointers. + iterator first_ = const_cast<iterator>(first); + iterator last_ = const_cast<iterator>(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, s, s + n); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'position' of 'length' with 'n' copies of 'c'. + //********************************************************************* + ibasic_string& replace(size_t position, size_t length_, size_t n, value_type c) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = std::min(length_, size() - position); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, n, c); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' of 'last' with 'n' copies of 'c'. + //********************************************************************* + ibasic_string& replace(const_iterator first, const_iterator last, size_t n, value_type c) + { + // Quick hack, as iterators are pointers. + iterator first_ = const_cast<iterator>(first); + iterator last_ = const_cast<iterator>(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, n, c); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' of 'last' with characters from 'first_replace' to 'last_replace'. + //********************************************************************* + template <typename TIterator> + ibasic_string& replace(const_iterator first, const_iterator last, TIterator first_replace, TIterator last_replace) + { + // Quick hack, as iterators are pointers. + iterator first_ = const_cast<iterator>(first); + iterator last_ = const_cast<iterator>(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, first_replace, last_replace); + + return *this; + } + + //************************************************************************* + /// Compare with string. + //************************************************************************* + int compare(const ibasic_string& str) const + { + return compare(p_buffer, + p_buffer + size(), + str.p_buffer, + str.p_buffer + str.size()); + } + + //************************************************************************* + /// Compare position / length with string. + //************************************************************************* + int compare(size_t position, size_t length_, const ibasic_string& str) const + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = std::min(length_, size() - position); + + return compare(p_buffer + position, + p_buffer + position + length_, + str.p_buffer, + str.p_buffer + str.size()); + } + + //************************************************************************* + /// Compare position / length with string / subposition / sublength. + //************************************************************************* + int compare(size_t position, size_t length_, const ibasic_string& str, size_t subposition, size_t sublength) const + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the lengths. + length_ = std::min(length_, size() - position); + sublength = std::min(sublength, str.size() - subposition); + + return compare(p_buffer + position, + p_buffer + position + length_, + str.p_buffer + subposition, + str.p_buffer + subposition + sublength); + } + + //************************************************************************* + /// Compare with C string + //************************************************************************* + int compare(const value_type* s) const + { + return compare(p_buffer, + p_buffer + size(), + s, + s + etl::strlen(s)); + } + + //************************************************************************* + /// Compare position / length with C string. + //************************************************************************* + int compare(size_t position, size_t length_, const_pointer s) const + { + return compare(p_buffer + position, + p_buffer + position + length_, + s, + s + etl::strlen(s)); + } + + //************************************************************************* + /// Compare position / length with C string / n. + //************************************************************************* + int compare(size_t position, size_t length_, const_pointer s, size_t n) const + { + return compare(p_buffer + position, + p_buffer + position + length_, + s, + s + n);; + } + + //********************************************************************* + /// Find first of any of content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_first_of(const ibasic_string<T>& str, size_t position = 0) const + { + return find_first_of(str.c_str(), position, str.size()); + } + + //********************************************************************* + /// Find first of any of content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_first_of(const_pointer s, size_t position = 0) const + { + return find_first_of(s, position, etl::strlen(s)); + } + + //********************************************************************* + /// Find first of any of content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + ///\param n The number of characters to search for. + //********************************************************************* + size_t find_first_of(const_pointer s, size_t position, size_t n) const + { + if (position < size()) + { + for (size_t i = position; i < size(); ++i) + { + for (size_t j = 0; j < n; ++j) + { + if (p_buffer[i] == s[j]) + { + return i; + } + } + } + } + + return npos; + } + + //********************************************************************* + /// Find first of character within the string + ///\param c The character to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_first_of(value_type c, size_t position = 0) const + { + if (position < size()) + { + for (size_t i = position; i < size(); ++i) + { + if (p_buffer[i] == c) + { + return i; + } + } + } + + return npos; + } + + //********************************************************************* + /// Find last of any of content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_last_of(const ibasic_string<T>& str, size_t position = npos) const + { + return find_last_of(str.c_str(), position, str.size()); + } + + //********************************************************************* + /// Find last of any of content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_last_of(const_pointer s, size_t position = npos) const + { + return find_last_of(s, position, etl::strlen(s)); + } + + //********************************************************************* + /// Find last of any of content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + ///\param n The number of characters to search for. + //********************************************************************* + size_t find_last_of(const_pointer s, size_t position, size_t n) const + { + if (empty()) + { + return npos; + } + + position = std::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + for (size_t j = 0; j < n; ++j) + { + if (p_buffer[position] == s[j]) + { + return position; + } + } + + ++it; + --position; + } + + return npos; + } + + //********************************************************************* + /// Find last of character within the string + ///\param c The character to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_last_of(value_type c, size_t position = npos) const + { + if (empty()) + { + return npos; + } + + position = std::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + if (p_buffer[position] == c) + { + return position; + } + + ++it; + --position; + } + + return npos; + } + + //********************************************************************* + /// Find first not of any of content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_first_not_of(const ibasic_string<T>& str, size_t position = 0) const + { + return find_first_not_of(str.c_str(), position, str.size()); + } + + //********************************************************************* + /// Find first not of any of content within the string + ///\param s Pointer to the content to not find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_first_not_of(const_pointer s, size_t position = 0) const + { + return find_first_not_of(s, position, etl::strlen(s)); + } + + //********************************************************************* + /// Find first not of any of content within the string + ///\param s Pointer to the content to not find + ///\param pos The position to start searching from. + ///\param n The number of characters to search for. + //********************************************************************* + size_t find_first_not_of(const_pointer s, size_t position, size_t n) const + { + if (position < size()) + { + for (size_t i = position; i < size(); ++i) + { + bool found = false; + + for (size_t j = 0; j < n; ++j) + { + if (p_buffer[i] == s[j]) + { + found = true; + } + } + + if (!found) + { + return i; + } + } + } + + return npos; + } + + //********************************************************************* + /// Find first not of character within the string + ///\param c The character to not find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_first_not_of(value_type c, size_t position = 0) const + { + if (position < size()) + { + for (size_t i = position; i < size(); ++i) + { + if (p_buffer[i] != c) + { + return i; + } + } + } + + return npos; + } + + //********************************************************************* + /// Find last not of any of content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_last_not_of(const ibasic_string<T>& str, size_t position = npos) const + { + return find_last_not_of(str.c_str(), position, str.size()); + } + + //********************************************************************* + /// Find last not of any of content within the string + ///\param s The pointer to the content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_t find_last_not_of(const_pointer s, size_t position = npos) const + { + return find_last_not_of(s, position, etl::strlen(s)); + } + + //********************************************************************* + /// Find last not of any of content within the string + ///\param s The pointer to the content to find + ///\param pos The position to start searching from. + ///\param n The number of characters to use. + //********************************************************************* + size_t find_last_not_of(const_pointer s, size_t position, size_t n) const + { + if (empty()) + { + return npos; + } + + position = std::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + bool found = false; + + for (size_t j = 0; j < n; ++j) + { + if (p_buffer[position] == s[j]) + { + found = true; + } + } + + if (!found) + { + return position; + } + + ++it; + --position; + } + + return npos; + } + + //********************************************************************* + // + //********************************************************************* + size_t find_last_not_of(value_type c, size_t position = npos) const + { + if (empty()) + { + return npos; + } + + position = std::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + if (p_buffer[position] != c) + { + return position; + } + + ++it; + --position; + } + + return npos; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + ibasic_string& operator = (const ibasic_string& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// += operator. + //************************************************************************* + ibasic_string& operator += (const ibasic_string& rhs) + { + if (&rhs != this) + { + append(rhs); + } + + return *this; + } + + //************************************************************************* + /// += operator. + //************************************************************************* + ibasic_string& operator += (const T* rhs) + { + append(rhs); + + return *this; + } + + //************************************************************************* + /// += operator. + //************************************************************************* + ibasic_string& operator += (T rhs) + { + append(size_t(1), rhs); + + return *this; + } + +#ifdef ETL_ISTRING_REPAIR_ENABLE + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + virtual void repair() = 0; +#endif + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + ibasic_string(T* p_buffer_, size_t MAX_SIZE_) + : string_base(MAX_SIZE_), + p_buffer(p_buffer_) + { + } + + //********************************************************************* + /// Initialise the string. + //********************************************************************* + void initialise() + { + current_size = 0; + p_buffer[0] = 0; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair(T* p_buffer_) + { + p_buffer = p_buffer_; + } + + private: + + //************************************************************************* + /// Compare helper function + //************************************************************************* + int compare(const_pointer first1, const_pointer last1, const_pointer first2, const_pointer last2) const + { + while ((first1 != last1) && (first2 != last2)) + { + if (*first1 < *first2) + { + // Compared character is lower. + return -1; + } + else if (*first1 > *first2) + { + // Compared character is higher. + return 1; + } + + ++first1; + ++first2; + } + + // We reached the end of one or both of the strings. + if ((first1 == last1) && (first2 == last2)) + { + // Same length. + return 0; + } + else if (first1 == last1) + { + // Compared string is shorter. + return -1; + } + else + { + // Compared string is longer. + return 1; + } + } + + // Disable copy construction. + ibasic_string(const ibasic_string&); + + T* p_buffer; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator ==(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator ==(const etl::ibasic_string<T>& lhs, const T* rhs) + { + return (lhs.size() == etl::strlen(rhs)) && std::equal(lhs.begin(), lhs.end(), rhs); + } + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator ==(const T* lhs, const etl::ibasic_string<T>& rhs) + { + return (rhs.size() == etl::strlen(lhs)) && std::equal(rhs.begin(), rhs.end(), lhs); + } + + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator !=(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator !=(const etl::ibasic_string<T>& lhs, const T* rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator !=(const T* lhs, const etl::ibasic_string<T>& rhs) + { + return !(lhs == rhs); + } + + + //*************************************************************************** + /// Less than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically less than the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator <(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //*************************************************************************** + /// Less than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically less than the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator <(const etl::ibasic_string<T>& lhs, const T* rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs, rhs + etl::strlen(rhs)); + } + + //*************************************************************************** + /// Less than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically less than the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator <(const T* lhs, const etl::ibasic_string<T>& rhs) + { + return std::lexicographical_compare(lhs, lhs + etl::strlen(lhs), rhs.begin(), rhs.end()); + } + + + //*************************************************************************** + /// Greater than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically greater than the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator >(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs) + { + return (rhs < lhs); + } + + //*************************************************************************** + /// Greater than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically greater than the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator >(const etl::ibasic_string<T>& lhs, const T* rhs) + { + return (rhs < lhs); + } + + //*************************************************************************** + /// Greater than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically greater than the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator >(const T* lhs, const etl::ibasic_string<T>& rhs) + { + return (rhs < lhs); + } + + + //*************************************************************************** + /// Less than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically less than or equal to the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator <=(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs) + { + return !(lhs > rhs); + } + + //*************************************************************************** + /// Less than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically less than or equal to the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator <=(const etl::ibasic_string<T>& lhs, const T* rhs) + { + return !(lhs > rhs); + } + + //*************************************************************************** + /// Less than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically less than or equal to the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator <=(const T* lhs, const etl::ibasic_string<T>& rhs) + { + return !(lhs > rhs); + } + + + //*************************************************************************** + /// Greater than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically greater than or equal to the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator >=(const etl::ibasic_string<T>& lhs, const etl::ibasic_string<T>& rhs) + { + return !(lhs < rhs); + } + + //*************************************************************************** + /// Greater than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically greater than or equal to the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator >=(const etl::ibasic_string<T>& lhs, const T* rhs) + { + return !(lhs < rhs); + } + + //*************************************************************************** + /// Greater than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return <b>true</b> if the first string is lexicographically greater than or equal to the second, otherwise <b>false</b> + ///\ingroup string + //*************************************************************************** + template <typename T> + bool operator >=(const T* lhs, const etl::ibasic_string<T>& rhs) + { + return !(lhs < rhs); + } +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifdef ETL_COMPILER_MICROSOFT +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/binary.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,471 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#include "platform.h" +#include "binary.h" + +namespace etl +{ +#if ETL_8BIT_SUPPORT + //*************************************************************************** + /// Reverse 8 bits. + //*************************************************************************** + uint8_t reverse_bits(uint8_t value) + { + value = ((value & 0xAA) >> 1) | ((value & 0x55) << 1); + value = ((value & 0xCC) >> 2) | ((value & 0x33) << 2); + value = (value >> 4) | (value << 4); + + return value; + } +#endif + + //*************************************************************************** + /// Reverse 16 bits. + //*************************************************************************** + uint16_t reverse_bits(uint16_t value) + { + value = ((value & 0xAAAA) >> 1) | ((value & 0x5555) << 1); + value = ((value & 0xCCCC) >> 2) | ((value & 0x3333) << 2); + value = ((value & 0xF0F0) >> 4) | ((value & 0x0F0F) << 4); + value = (value >> 8) | (value << 8); + + return value; + } + + //*************************************************************************** + /// Reverse 32 bits. + //*************************************************************************** + uint32_t reverse_bits(uint32_t value) + { + value = ((value & 0xAAAAAAAA) >> 1) | ((value & 0x55555555) << 1); + value = ((value & 0xCCCCCCCC) >> 2) | ((value & 0x33333333) << 2); + value = ((value & 0xF0F0F0F0) >> 4) | ((value & 0x0F0F0F0F) << 4); + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + value = (value >> 16) | (value << 16); + + return value; + } + + //*************************************************************************** + /// Reverse 64 bits. + //*************************************************************************** + uint64_t reverse_bits(uint64_t value) + { + value = ((value & 0xAAAAAAAAAAAAAAAA) >> 1) | ((value & 0x5555555555555555) << 1); + value = ((value & 0xCCCCCCCCCCCCCCCC) >> 2) | ((value & 0x3333333333333333) << 2); + value = ((value & 0xF0F0F0F0F0F0F0F0) >> 4) | ((value & 0x0F0F0F0F0F0F0F0F) << 4); + value = ((value & 0xFF00FF00FF00FF00) >> 8) | ((value & 0x00FF00FF00FF00FF) << 8); + value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16); + value = (value >> 32) | (value << 32); + + return value; + } + + //*************************************************************************** + /// Reverse bytes 16 bit. + //*************************************************************************** + uint16_t reverse_bytes(uint16_t value) + { + value = (value >> 8) | (value << 8); + + return value; + } + + //*************************************************************************** + /// Reverse bytes 32 bit. + //*************************************************************************** + uint32_t reverse_bytes(uint32_t value) + { + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + value = (value >> 16) | (value << 16); + + return value; + } + + //*************************************************************************** + /// Reverse bytes 64 bit. + //*************************************************************************** + uint64_t reverse_bytes(uint64_t value) + { + value = ((value & 0xFF00FF00FF00FF00) >> 8) | ((value & 0x00FF00FF00FF00FF) << 8); + value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16); + value = (value >> 32) | (value << 32); + + return value; + } + +#if ETL_8BIT_SUPPORT + //*************************************************************************** + /// Converts Gray code to binary. + //*************************************************************************** + uint8_t gray_to_binary(uint8_t value) + { + value ^= (value >> 4); + value ^= (value >> 2); + value ^= (value >> 1); + + return value; + } +#endif + + //*************************************************************************** + /// Converts Gray code to binary. + //*************************************************************************** + uint16_t gray_to_binary(uint16_t value) + { + value ^= (value >> 8); + value ^= (value >> 4); + value ^= (value >> 2); + value ^= (value >> 1); + + return value; + } + + //*************************************************************************** + /// Converts Gray code to binary. + //*************************************************************************** + uint32_t gray_to_binary(uint32_t value) + { + value ^= (value >> 16); + value ^= (value >> 8); + value ^= (value >> 4); + value ^= (value >> 2); + value ^= (value >> 1); + + return value; + } + + //*************************************************************************** + /// Converts Gray code to binary. + //*************************************************************************** + uint64_t gray_to_binary(uint64_t value) + { + value ^= (value >> 32); + value ^= (value >> 16); + value ^= (value >> 8); + value ^= (value >> 4); + value ^= (value >> 2); + value ^= (value >> 1); + + return value; + } + +#if ETL_8BIT_SUPPORT + //*************************************************************************** + /// Count set bits. 8 bits. + //*************************************************************************** + uint_least8_t count_bits(uint8_t value) + { + uint32_t count; + static const int S[] = { 1, 2, 4 }; + static const uint8_t B[] = { 0x55, 0x33, 0x0F }; + + count = value - ((value >> 1) & B[0]); + count = ((count >> S[1]) & B[1]) + (count & B[1]); + count = ((count >> S[2]) + count) & B[2]; + + return uint_least8_t(count); + } +#endif + + //*************************************************************************** + /// Count set bits. 16 bits. + //*************************************************************************** + uint_least8_t count_bits(uint16_t value) + { + uint32_t count; + static const int S[] = { 1, 2, 4, 8 }; + static const uint16_t B[] = { 0x5555, 0x3333, 0x0F0F, 0x00FF }; + + count = value - ((value >> 1) & B[0]); + count = ((count >> S[1]) & B[1]) + (count & B[1]); + count = ((count >> S[2]) + count) & B[2]; + count = ((count >> S[3]) + count) & B[3]; + + return count; + } + + //*************************************************************************** + /// Count set bits. 32 bits. + //*************************************************************************** + uint_least8_t count_bits(uint32_t value) + { + uint32_t count; + + value = value - ((value >> 1) & 0x55555555); + value = (value & 0x33333333) + ((value >> 2) & 0x33333333); + count = (((value + (value >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; + + return uint_least8_t(count); + } + + //*************************************************************************** + /// Count set bits. 64 bits. + //*************************************************************************** + uint_least8_t count_bits(uint64_t value) + { + uint64_t count; + static const int S[] = { 1, 2, 4, 8, 16, 32 }; + static const uint64_t B[] = { 0x5555555555555555, 0x3333333333333333, 0x0F0F0F0F0F0F0F0F, 0x00FF00FF00FF00FF, 0x0000FFFF0000FFFF, 0x00000000FFFFFFFF }; + + count = value - ((value >> 1) & B[0]); + count = ((count >> S[1]) & B[1]) + (count & B[1]); + count = ((count >> S[2]) + count) & B[2]; + count = ((count >> S[3]) + count) & B[3]; + count = ((count >> S[4]) + count) & B[4]; + count = ((count >> S[5]) + count) & B[5]; + + return uint_least8_t(count); + } + +#if ETL_8BIT_SUPPORT + //*************************************************************************** + /// Parity. 8bits. 0 = even, 1 = odd + //*************************************************************************** + uint_least8_t parity(uint8_t value) + { + value ^= value >> 4; + value &= 0x0F; + return (0x6996 >> value) & 1; + } +#endif + + //*************************************************************************** + /// Parity. 16bits. 0 = even, 1 = odd + //*************************************************************************** + uint_least8_t parity(uint16_t value) + { + value ^= value >> 8; + value ^= value >> 4; + value &= 0x0F; + return (0x6996 >> value) & 1; + } + + //*************************************************************************** + /// Parity. 32bits. 0 = even, 1 = odd + //*************************************************************************** + uint_least8_t parity(uint32_t value) + { + value ^= value >> 16; + value ^= value >> 8; + value ^= value >> 4; + value &= 0x0F; + return (0x6996 >> value) & 1; + } + + //*************************************************************************** + /// Parity. 64bits. 0 = even, 1 = odd + //*************************************************************************** + uint_least8_t parity(uint64_t value) + { + value ^= value >> 32; + value ^= value >> 16; + value ^= value >> 8; + value ^= value >> 4; + value &= 0x0F; + return (0x69966996 >> value) & 1; + } + +#if ETL_8BIT_SUPPORT + //*************************************************************************** + /// Count trailing zeros. bit. + /// Uses a binary search. + //*************************************************************************** + uint_least8_t count_trailing_zeros(uint8_t value) + { + uint_least8_t count; + + if (value & 0x1) + { + count = 0; + } + else + { + count = 1; + + if ((value & 0xF) == 0) + { + value >>= 4; + count += 4; + } + + if ((value & 0x3) == 0) + { + value >>= 2; + count += 2; + } + + count -= value & 0x1; + } + + return count; + } +#endif + + //*************************************************************************** + /// Count trailing zeros. 16bit. + /// Uses a binary search. + //*************************************************************************** + uint_least8_t count_trailing_zeros(uint16_t value) + { + uint_least8_t count; + + if (value & 0x1) + { + count = 0; + } + else + { + count = 1; + + if ((value & 0xFF) == 0) + { + value >>= 8; + count += 8; + } + + if ((value & 0xF) == 0) + { + value >>= 4; + count += 4; + } + + if ((value & 0x3) == 0) + { + value >>= 2; + count += 2; + } + + count -= value & 0x1; + } + + return count; + } + + //*************************************************************************** + /// Count trailing zeros. 32bit. + /// Uses a binary search. + //*************************************************************************** + uint_least8_t count_trailing_zeros(uint32_t value) + { + uint_least8_t count; + + if (value & 0x1) + { + count = 0; + } + else + { + count = 1; + + if ((value & 0xFFFF) == 0) + { + value >>= 16; + count += 16; + } + + if ((value & 0xFF) == 0) + { + value >>= 8; + count += 8; + } + + if ((value & 0xF) == 0) + { + value >>= 4; + count += 4; + } + + if ((value & 0x3) == 0) + { + value >>= 2; + count += 2; + } + + count -= value & 0x1; + } + + return count; + } + + //*************************************************************************** + /// Count trailing zeros. 64bit. + /// Uses a binary search. + //*************************************************************************** + uint_least8_t count_trailing_zeros(uint64_t value) + { + uint_least8_t count; + + if (value & 0x1) + { + count = 0; + } + else + { + count = 1; + + if ((value & 0xFFFFFFFF) == 0) + { + value >>= 32; + count += 32; + } + + if ((value & 0xFFFF) == 0) + { + value >>= 16; + count += 16; + } + + if ((value & 0xFF) == 0) + { + value >>= 8; + count += 8; + } + + if ((value & 0xF) == 0) + { + value >>= 4; + count += 4; + } + + if ((value & 0x3) == 0) + { + value >>= 2; + count += 2; + } + + count -= value & 0x1; + } + + return count; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/binary.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,726 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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_BINARY__ +#define __ETL_BINARY__ + +///\defgroup binary binary +/// Binary utilities +///\ingroup utilities + +#include <limits> +#include <assert.h> + +#include "platform.h" +#include "type_traits.h" +#include "integral_limits.h" +#include "static_assert.h" +#include "log.h" +#include "power.h" +#include "smallest.h" +#include "platform.h" + +namespace etl +{ + //*************************************************************************** + /// Maximum value that can be contained in N bits. + //*************************************************************************** + /// Definition for non-zero NBITS. + template <const size_t NBITS> + struct max_value_for_nbits + { + typedef typename etl::smallest_uint_for_bits<NBITS>::type value_type; + static const value_type value = (value_type(1) << (NBITS - 1)) | max_value_for_nbits<NBITS - 1>::value; + }; + + /// Specialisation for when NBITS == 0. + template <> + struct max_value_for_nbits<0> + { + typedef etl::smallest_uint_for_bits<0>::type value_type; + static const value_type value = 0; + }; + + template <const size_t NBITS> + const typename max_value_for_nbits<NBITS>::value_type max_value_for_nbits<NBITS>::value; + + //*************************************************************************** + /// Rotate left. + //*************************************************************************** + template <typename T> + T rotate_left(T value) + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + + const size_t SHIFT = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits - 1; + + return (value << 1) | (value >> SHIFT); + } + + //*************************************************************************** + /// Rotate left. + //*************************************************************************** + template <typename T> + T rotate_left(T value, size_t distance) + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + + const size_t BITS = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits; + distance %= BITS; + const size_t SHIFT = BITS - distance; + + return (value << distance) | (value >> SHIFT); + } + + //*************************************************************************** + /// Rotate right. + //*************************************************************************** + template <typename T> + T rotate_right(T value) + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + + const size_t SHIFT = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits - 1; + + return (value >> 1) | (value << SHIFT); + } + + //*************************************************************************** + /// Rotate right. + //*************************************************************************** + template <typename T> + T rotate_right(T value, size_t distance) + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + + const size_t BITS = etl::integral_limits<typename etl::make_unsigned<T>::type>::bits; + distance %= BITS; + const size_t SHIFT = BITS - distance; + + return (value >> distance) | (value << SHIFT); + } + + //*************************************************************************** + /// Rotate. + /// Positive is left, negative is right. + //*************************************************************************** + template <typename T> + T rotate(T value, typename etl::make_signed<size_t>::type distance) + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + + T result; + + if (distance > 0) + { + result = rotate_left(value, size_t(distance)); + } + else + { + result = rotate_right(value, size_t(-distance)); + } + + return result; + } + + //*************************************************************************** + /// Reverse bits. + //*************************************************************************** +#if ETL_8BIT_SUPPORT + uint8_t reverse_bits(uint8_t value); + inline int8_t reverse_bits(int8_t value) { return int8_t(reverse_bits(uint8_t(value))); } +#endif + uint16_t reverse_bits(uint16_t value); + inline int16_t reverse_bits(int16_t value) { return int16_t(reverse_bits(uint16_t(value))); } + uint32_t reverse_bits(uint32_t value); + inline int32_t reverse_bits(int32_t value) { return int32_t(reverse_bits(uint32_t(value))); } + uint64_t reverse_bits(uint64_t value); + inline int64_t reverse_bits(int64_t value) { return int64_t(reverse_bits(uint64_t(value))); } + + //*************************************************************************** + /// Reverse bytes. + //*************************************************************************** +#if ETL_8BIT_SUPPORT + inline uint8_t reverse_bytes(uint8_t value) { return value; } + inline int8_t reverse_bytes(int8_t value) { return value; } +#endif + uint16_t reverse_bytes(uint16_t value); + inline int16_t reverse_bytes(int16_t value) { return int16_t(reverse_bytes(uint16_t(value))); } + uint32_t reverse_bytes(uint32_t value); + inline int32_t reverse_bytes(int32_t value) { return int32_t(reverse_bytes(uint32_t(value))); } + uint64_t reverse_bytes(uint64_t value); + inline int64_t reverse_bytes(int64_t value) { return int64_t(reverse_bytes(uint64_t(value))); } + + //*************************************************************************** + /// Converts binary to Gray code. + //*************************************************************************** + template <typename T> + T binary_to_gray(T value) + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + + return (value >> 1) ^ value; + } + + //*************************************************************************** + /// Converts Gray code to binary. + //*************************************************************************** +#if ETL_8BIT_SUPPORT + uint8_t gray_to_binary(uint8_t value); + inline int8_t gray_to_binary(int8_t value) { return int8_t(gray_to_binary(uint8_t(value))); } +#endif + uint16_t gray_to_binary(uint16_t value); + inline int16_t gray_to_binary(int16_t value) { return int16_t(gray_to_binary(uint16_t(value))); } + uint32_t gray_to_binary(uint32_t value); + inline int32_t gray_to_binary(int32_t value) { return int32_t(gray_to_binary(uint32_t(value))); } + uint64_t gray_to_binary(uint64_t value); + inline int64_t gray_to_binary(int64_t value) { return int64_t(gray_to_binary(uint64_t(value))); } + + //*************************************************************************** + /// Count set bits. + //*************************************************************************** +#if ETL_8BIT_SUPPORT + uint_least8_t count_bits(uint8_t value); + inline uint_least8_t count_bits(int8_t value) { return count_bits(uint8_t(value)); } +#endif + uint_least8_t count_bits(uint16_t value); + inline uint_least8_t count_bits(int16_t value) { return count_bits(uint16_t(value)); } + uint_least8_t count_bits(uint32_t value); + inline uint_least8_t count_bits(int32_t value) { return count_bits(uint32_t(value)); } + uint_least8_t count_bits(uint64_t value); + inline uint_least8_t count_bits(int64_t value) { return count_bits(uint64_t(value)); } + + //*************************************************************************** + /// Parity. 0 = even, 1 = odd + //*************************************************************************** +#if ETL_8BIT_SUPPORT + uint_least8_t parity(uint8_t value); + inline uint_least8_t parity(int8_t value) { return parity(uint8_t(value)); } +#endif + uint_least8_t parity(uint16_t value); + inline uint_least8_t parity(int16_t value) { return parity(uint16_t(value)); } + uint_least8_t parity(uint32_t value); + inline uint_least8_t parity(int32_t value) { return parity(uint32_t(value)); } + uint_least8_t parity(uint64_t value); + inline uint_least8_t parity(int64_t value) { return parity(uint64_t(value)); } + + //*************************************************************************** + /// Fold a binary number down to a set number of bits using XOR. + //*************************************************************************** + template <typename TReturn, const size_t NBITS, typename TValue> + TReturn fold_bits(TValue value) + { + STATIC_ASSERT(integral_limits<TReturn>::bits >= NBITS, "Return type too small to hold result"); + + const TValue mask = etl::power<2, NBITS>::value - 1; + const size_t shift = NBITS; + + // Fold the value down to fit the width. + TReturn folded_value = 0; + + // Keep shifting down and XORing the lower bits. + while (value >= etl::max_value_for_nbits<NBITS>::value) + { + folded_value ^= value & mask; + value >>= shift; + } + + // Fold the remaining bits. + folded_value ^= value & mask; + + return folded_value; + } + + //*************************************************************************** + /// Sign extend. + /// Converts an N bit binary number, where bit N-1 is the sign bit, to a signed integral type. + //*************************************************************************** + template <typename TReturn, const size_t NBITS, typename TValue> + TReturn sign_extend(TValue value) + { + STATIC_ASSERT(etl::is_integral<TValue>::value, "TValue not an integral type"); + STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type"); + STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type"); + STATIC_ASSERT(NBITS <= std::numeric_limits<TReturn>::digits, "NBITS too large for return type"); + + const TReturn negative = (TReturn(1) << (NBITS - 1)); + TReturn signed_value = value & ((1 << NBITS) - 1); + + if ((signed_value & negative) != 0) + { + const TReturn sign_bits = ~((TReturn(1) << NBITS) - 1); + signed_value |= sign_bits; + } + + return signed_value; + } + + //*************************************************************************** + /// Sign extend. + /// Converts an N bit binary number, where bit N-1 is the sign bit, and SHIFT + /// is the right shift amount, to a signed integral type. + //*************************************************************************** + template <typename TReturn, const size_t NBITS, const size_t SHIFT, typename TValue> + TReturn sign_extend(TValue value) + { + STATIC_ASSERT(etl::is_integral<TValue>::value, "TValue not an integral type"); + STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type"); + STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type"); + STATIC_ASSERT(NBITS <= std::numeric_limits<TReturn>::digits, "NBITS too large for return type"); + STATIC_ASSERT(SHIFT <= std::numeric_limits<TReturn>::digits, "SHIFT too large"); + + const TReturn negative = (TReturn(1) << (NBITS - 1)); + TReturn signed_value = (value >> SHIFT) & ((1 << NBITS) - 1); + + if ((signed_value & negative) != 0) + { + const TReturn sign_bits = ~((TReturn(1) << NBITS) - 1); + signed_value |= sign_bits; + } + + return signed_value; + } + + //*************************************************************************** + /// Sign extend. + /// Converts an N bit binary number, where bit N-1 is the sign bit, to a signed integral type. + //*************************************************************************** + template <typename TReturn, typename TValue> + TReturn sign_extend(TValue value, const size_t NBITS) + { + STATIC_ASSERT(etl::is_integral<TValue>::value, "TValue not an integral type"); + STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type"); + STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type"); + assert(NBITS <= std::numeric_limits<TReturn>::digits); + + const TReturn negative = (TReturn(1) << (NBITS - 1)); + TReturn signed_value = value & ((1 << NBITS) - 1); + + if ((signed_value & negative) != 0) + { + const TReturn sign_bits = ~((TReturn(1) << NBITS) - 1); + signed_value |= sign_bits; + } + + return signed_value; + } + + //*************************************************************************** + /// Sign extend. + /// Converts an N bit binary number, where bit N-1 is the sign bit, and SHIFT + /// is the right shift amount, to a signed integral type. + //*************************************************************************** + template <typename TReturn, typename TValue> + TReturn sign_extend(TValue value, const size_t NBITS, const size_t SHIFT) + { + STATIC_ASSERT(etl::is_integral<TValue>::value, "TValue not an integral type"); + STATIC_ASSERT(etl::is_integral<TReturn>::value, "TReturn not an integral type"); + STATIC_ASSERT(etl::is_signed<TReturn>::value, "TReturn not a signed type"); + assert(NBITS <= std::numeric_limits<TReturn>::digits); + + const TReturn negative = (TReturn(1) << (NBITS - 1)); + TReturn signed_value = (value >> SHIFT) & ((1 << NBITS) - 1); + + if ((signed_value & negative) != 0) + { + const TReturn sign_bits = ~((TReturn(1) << NBITS) - 1); + signed_value |= sign_bits; + } + + return signed_value; + } + + //*************************************************************************** + /// Count trailing zeros. bit. + /// Uses a binary search. + //*************************************************************************** +#if ETL_8BIT_SUPPORT + uint_least8_t count_trailing_zeros(uint8_t value); + inline uint_least8_t count_trailing_zeros(int8_t value) { return count_trailing_zeros(uint8_t(value)); } +#endif + uint_least8_t count_trailing_zeros(uint16_t value); + inline uint_least8_t count_trailing_zeros(int16_t value) { return count_trailing_zeros(uint16_t(value)); } + uint_least8_t count_trailing_zeros(uint32_t value); + inline uint_least8_t count_trailing_zeros(int32_t value) { return count_trailing_zeros(uint32_t(value)); } + uint_least8_t count_trailing_zeros(uint64_t value); + inline uint_least8_t count_trailing_zeros(int64_t value) { return count_trailing_zeros(uint64_t(value)); } + + //*************************************************************************** + /// Find the position of the first set bit. + /// Starts from LSB. + //*************************************************************************** + template <typename T> + uint_least8_t first_set_bit_position(T value) + { + return count_trailing_zeros(value); + } + + //*************************************************************************** + /// Find the position of the first clear bit. + /// Starts from LSB. + //*************************************************************************** + template <typename T> + uint_least8_t first_clear_bit_position(T value) + { + value = ~value; + return count_trailing_zeros(value); + } + + //*************************************************************************** + /// Find the position of the first bit that is clear or set. + /// Starts from LSB. + //*************************************************************************** + template <typename T> + uint_least8_t first_bit_position(bool state, T value) + { + if (!state) + { + value = ~value; + } + + return count_trailing_zeros(value); + } + + //*************************************************************************** + /// Gets the value of the bit at POSITION + /// Starts from LSB. + //*************************************************************************** + template <const size_t POSITION> + struct bit + { + typedef typename etl::smallest_uint_for_bits<POSITION + 1>::type value_type; + static const value_type value = value_type(1) << POSITION; + }; + + template <const size_t POSITION> + const typename bit<POSITION>::value_type bit<POSITION>::value; + + //*************************************************************************** + /// 8 bit binary constants. + //*************************************************************************** + enum binary_constant + { + b00000000 = 0, + b00000001 = 1, + b00000010 = 2, + b00000011 = 3, + b00000100 = 4, + b00000101 = 5, + b00000110 = 6, + b00000111 = 7, + b00001000 = 8, + b00001001 = 9, + b00001010 = 10, + b00001011 = 11, + b00001100 = 12, + b00001101 = 13, + b00001110 = 14, + b00001111 = 15, + b00010000 = 16, + b00010001 = 17, + b00010010 = 18, + b00010011 = 19, + b00010100 = 20, + b00010101 = 21, + b00010110 = 22, + b00010111 = 23, + b00011000 = 24, + b00011001 = 25, + b00011010 = 26, + b00011011 = 27, + b00011100 = 28, + b00011101 = 29, + b00011110 = 30, + b00011111 = 31, + b00100000 = 32, + b00100001 = 33, + b00100010 = 34, + b00100011 = 35, + b00100100 = 36, + b00100101 = 37, + b00100110 = 38, + b00100111 = 39, + b00101000 = 40, + b00101001 = 41, + b00101010 = 42, + b00101011 = 43, + b00101100 = 44, + b00101101 = 45, + b00101110 = 46, + b00101111 = 47, + b00110000 = 48, + b00110001 = 49, + b00110010 = 50, + b00110011 = 51, + b00110100 = 52, + b00110101 = 53, + b00110110 = 54, + b00110111 = 55, + b00111000 = 56, + b00111001 = 57, + b00111010 = 58, + b00111011 = 59, + b00111100 = 60, + b00111101 = 61, + b00111110 = 62, + b00111111 = 63, + b01000000 = 64, + b01000001 = 65, + b01000010 = 66, + b01000011 = 67, + b01000100 = 68, + b01000101 = 69, + b01000110 = 70, + b01000111 = 71, + b01001000 = 72, + b01001001 = 73, + b01001010 = 74, + b01001011 = 75, + b01001100 = 76, + b01001101 = 77, + b01001110 = 78, + b01001111 = 79, + b01010000 = 80, + b01010001 = 81, + b01010010 = 82, + b01010011 = 83, + b01010100 = 84, + b01010101 = 85, + b01010110 = 86, + b01010111 = 87, + b01011000 = 88, + b01011001 = 89, + b01011010 = 90, + b01011011 = 91, + b01011100 = 92, + b01011101 = 93, + b01011110 = 94, + b01011111 = 95, + b01100000 = 96, + b01100001 = 97, + b01100010 = 98, + b01100011 = 99, + b01100100 = 100, + b01100101 = 101, + b01100110 = 102, + b01100111 = 103, + b01101000 = 104, + b01101001 = 105, + b01101010 = 106, + b01101011 = 107, + b01101100 = 108, + b01101101 = 109, + b01101110 = 110, + b01101111 = 111, + b01110000 = 112, + b01110001 = 113, + b01110010 = 114, + b01110011 = 115, + b01110100 = 116, + b01110101 = 117, + b01110110 = 118, + b01110111 = 119, + b01111000 = 120, + b01111001 = 121, + b01111010 = 122, + b01111011 = 123, + b01111100 = 124, + b01111101 = 125, + b01111110 = 126, + b01111111 = 127, + b10000000 = 128, + b10000001 = 129, + b10000010 = 130, + b10000011 = 131, + b10000100 = 132, + b10000101 = 133, + b10000110 = 134, + b10000111 = 135, + b10001000 = 136, + b10001001 = 137, + b10001010 = 138, + b10001011 = 139, + b10001100 = 140, + b10001101 = 141, + b10001110 = 142, + b10001111 = 143, + b10010000 = 144, + b10010001 = 145, + b10010010 = 146, + b10010011 = 147, + b10010100 = 148, + b10010101 = 149, + b10010110 = 150, + b10010111 = 151, + b10011000 = 152, + b10011001 = 153, + b10011010 = 154, + b10011011 = 155, + b10011100 = 156, + b10011101 = 157, + b10011110 = 158, + b10011111 = 159, + b10100000 = 160, + b10100001 = 161, + b10100010 = 162, + b10100011 = 163, + b10100100 = 164, + b10100101 = 165, + b10100110 = 166, + b10100111 = 167, + b10101000 = 168, + b10101001 = 169, + b10101010 = 170, + b10101011 = 171, + b10101100 = 172, + b10101101 = 173, + b10101110 = 174, + b10101111 = 175, + b10110000 = 176, + b10110001 = 177, + b10110010 = 178, + b10110011 = 179, + b10110100 = 180, + b10110101 = 181, + b10110110 = 182, + b10110111 = 183, + b10111000 = 184, + b10111001 = 185, + b10111010 = 186, + b10111011 = 187, + b10111100 = 188, + b10111101 = 189, + b10111110 = 190, + b10111111 = 191, + b11000000 = 192, + b11000001 = 193, + b11000010 = 194, + b11000011 = 195, + b11000100 = 196, + b11000101 = 197, + b11000110 = 198, + b11000111 = 199, + b11001000 = 200, + b11001001 = 201, + b11001010 = 202, + b11001011 = 203, + b11001100 = 204, + b11001101 = 205, + b11001110 = 206, + b11001111 = 207, + b11010000 = 208, + b11010001 = 209, + b11010010 = 210, + b11010011 = 211, + b11010100 = 212, + b11010101 = 213, + b11010110 = 214, + b11010111 = 215, + b11011000 = 216, + b11011001 = 217, + b11011010 = 218, + b11011011 = 219, + b11011100 = 220, + b11011101 = 221, + b11011110 = 222, + b11011111 = 223, + b11100000 = 224, + b11100001 = 225, + b11100010 = 226, + b11100011 = 227, + b11100100 = 228, + b11100101 = 229, + b11100110 = 230, + b11100111 = 231, + b11101000 = 232, + b11101001 = 233, + b11101010 = 234, + b11101011 = 235, + b11101100 = 236, + b11101101 = 237, + b11101110 = 238, + b11101111 = 239, + b11110000 = 240, + b11110001 = 241, + b11110010 = 242, + b11110011 = 243, + b11110100 = 244, + b11110101 = 245, + b11110110 = 246, + b11110111 = 247, + b11111000 = 248, + b11111001 = 249, + b11111010 = 250, + b11111011 = 251, + b11111100 = 252, + b11111101 = 253, + b11111110 = 254, + b11111111 = 255 + }; + + enum bit_constant + { + b0 = 0x1, + b1 = 0x2, + b2 = 0x4, + b3 = 0x8, + b4 = 0x10, + b5 = 0x20, + b6 = 0x40, + b7 = 0x80, + b8 = 0x100, + b9 = 0x200, + b10 = 0x400, + b11 = 0x800, + b12 = 0x1000, + b13 = 0x2000, + b14 = 0x4000, + b15 = 0x8000, + b16 = 0x10000, + b17 = 0x20000, + b18 = 0x40000, + b19 = 0x80000, + b20 = 0x100000, + b21 = 0x200000, + b22 = 0x400000, + b23 = 0x800000, + b24 = 0x1000000, + b25 = 0x2000000, + b26 = 0x4000000, + b27 = 0x8000000, + b28 = 0x10000000, + b29 = 0x20000000, + b30 = 0x40000000, + b31 = 0x80000000 + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bitset.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1011 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_BITSET__ +#define __ETL_BITSET__ + +#include <algorithm> +#include <iterator> +#include <string.h> +#include <stddef.h> +#include <stdint.h> + +#include "platform.h" +#include "integral_limits.h" +#include "algorithm.h" +#include "nullptr.h" +#include "log.h" +#include "exception.h" +#include "integral_limits.h" +#include "binary.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#include "error_handler.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +//***************************************************************************** +///\defgroup bitset bitset +/// Similar to std::bitset but without requiring std::string. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception base for bitset + ///\ingroup bitset + //*************************************************************************** + class bitset_exception : public etl::exception + { + public: + + bitset_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Bitset nullptr exception. + ///\ingroup bitset + //*************************************************************************** + class bitset_nullptr : public bitset_exception + { + public: + + bitset_nullptr(string_type file_name_, numeric_type line_number_) + : bitset_exception("bitset: nullptr", file_name_, line_number_) + { + } + }; + + //************************************************************************* + /// The base class for etl::bitset + ///\ingroup bitset + //************************************************************************* + class ibitset + { + protected: + + // The type used for each element in the array. +#if !defined(ETL_BITSET_ELEMENT_TYPE) + typedef uint_least8_t element_t; +#else + typedef ETL_BITSET_ELEMENT_TYPE element_t; +#endif + + public: + + static const element_t ALL_SET = etl::integral_limits<element_t>::max; + static const element_t ALL_CLEAR = 0; + + static const size_t BITS_PER_ELEMENT = etl::integral_limits<element_t>::bits; + + enum + { + npos = etl::integral_limits<size_t>::max + }; + + //************************************************************************* + /// The reference type returned. + //************************************************************************* + class bit_reference + { + public: + + friend class ibitset; + + //******************************* + /// Conversion operator. + //******************************* + operator bool() const + { + return p_bitset->test(position); + } + + //******************************* + /// Assignment operator. + //******************************* + bit_reference& operator = (bool b) + { + p_bitset->set(position, b); + return *this; + } + + //******************************* + /// Assignment operator. + //******************************* + bit_reference& operator = (const bit_reference& r) + { + p_bitset->set(position, bool(r)); + return *this; + } + + //******************************* + /// Flip the bit. + //******************************* + bit_reference& flip() + { + p_bitset->flip(position); + return *this; + } + + //******************************* + /// Return the logical inverse of the bit. + //******************************* + bool operator~() const + { + return !p_bitset->test(position); + } + + private: + + //******************************* + /// Default constructor. + //******************************* + bit_reference() + : p_bitset(std::nullptr), + position(0) + { + } + + //******************************* + /// Constructor. + //******************************* + bit_reference(ibitset& r_bitset, size_t position_) + : p_bitset(&r_bitset), + position(position_) + { + } + + ibitset* p_bitset; ///< The bitset. + size_t position; ///< The position in the bitset. + }; + + //************************************************************************* + /// The size of the bitset. + //************************************************************************* + size_t size() const + { + return NBITS; + } + + //************************************************************************* + /// Count the number of bits set. + //************************************************************************* + size_t count() const + { + size_t n = 0; + + for (size_t i = 0; i < SIZE; ++i) + { + n += etl::count_bits(pdata[i]); + } + + return n; + } + + //************************************************************************* + /// Tests a bit at a position. + /// Positions greater than the number of configured bits will return <b>false</b>. + //************************************************************************* + bool test(size_t position) const + { + size_t index; + element_t mask; + + if (SIZE == 1) + { + index = 0; + mask = element_t(1) << position; + } + else + { + index = position >> etl::log2<BITS_PER_ELEMENT>::value; + mask = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + return (pdata[index] & mask) != 0; + } + + //************************************************************************* + /// Set the bit at the position. + //************************************************************************* + ibitset& set() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ALL_SET; + } + + pdata[SIZE - 1] &= TOP_MASK; + + return *this; + } + + //************************************************************************* + /// Set the bit at the position. + //************************************************************************* + ibitset& set(size_t position, bool value = true) + { + size_t index; + element_t bit; + + if (SIZE == 1) + { + index = 0; + bit = element_t(1) << position; + } + else + { + index = position >> etl::log2<BITS_PER_ELEMENT>::value; + bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + if (value) + { + pdata[index] |= bit; + } + else + { + pdata[index] &= ~bit; + } + + return *this; + } + + //************************************************************************* + /// Set from a string. + //************************************************************************* + ibitset& set(const char* text) + { + reset(); + + size_t i = std::min(NBITS, strlen(text)); + + while (i > 0) + { + set(--i, *text++ == '1'); + } + + return *this; + } + + //************************************************************************* + /// Resets the bitset. + //************************************************************************* + ibitset& reset() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ALL_CLEAR; + } + + return *this; + } + + //************************************************************************* + /// Reset the bit at the position. + //************************************************************************* + ibitset& reset(size_t position) + { + size_t index; + element_t bit; + + if (SIZE == 1) + { + index = 0; + bit = element_t(1) << position; + } + else + { + index = position >> etl::log2<BITS_PER_ELEMENT>::value; + bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + pdata[index] &= ~bit; + + return *this; + } + + //************************************************************************* + /// Flip all of the bits. + //************************************************************************* + ibitset& flip() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ~pdata[i]; + } + + pdata[SIZE - 1] &= TOP_MASK; + + return *this; + } + + //************************************************************************* + /// Flip the bit at the position. + //************************************************************************* + ibitset& flip(size_t position) + { + if (position < NBITS) + { + size_t index; + element_t bit; + + if (SIZE == 1) + { + index = 0; + bit = element_t(1) << position; + } + else + { + index = position >> log2<BITS_PER_ELEMENT>::value; + bit = element_t(1) << (position & (BITS_PER_ELEMENT - 1)); + } + + pdata[index] ^= bit; + } + + return *this; + } + + //************************************************************************* + // Are all the bits sets? + //************************************************************************* + bool all() const + { + // All but the last. + for (size_t i = 0; i < (SIZE - 1); ++i) + { + if (pdata[i] != ALL_SET) + { + return false; + } + } + + // The last. + if (pdata[SIZE - 1] != (ALL_SET & TOP_MASK)) + { + return false; + } + + return true; + } + + //************************************************************************* + /// Are any of the bits set? + //************************************************************************* + bool any() const + { + return !none(); + } + + //************************************************************************* + /// Are none of the bits set? + //************************************************************************* + bool none() const + { + for (size_t i = 0; i < SIZE; ++i) + { + if (pdata[i] != 0) + { + return false; + } + } + + return true; + } + + //************************************************************************* + /// Finds the first bit in the specified state. + ///\param state The state to search for. + ///\returns The position of the bit or SIZE if none were found. + //************************************************************************* + size_t find_first(bool state) const + { + return find_next(state, 0); + } + + //************************************************************************* + /// Finds the next bit in the specified state. + ///\param state The state to search for. + ///\param position The position to start from. + ///\returns The position of the bit or SIZE if none were found. + //************************************************************************* + size_t find_next(bool state, size_t position) const + { + // Where to start. + size_t index; + size_t bit; + + if (SIZE == 1) + { + index = 0; + bit = position; + } + else + { + index = position >> log2<BITS_PER_ELEMENT>::value; + bit = position & (BITS_PER_ELEMENT - 1); + } + + element_t mask = 1 << bit; + + // For each element in the bitset... + while (index < SIZE) + { + element_t value = pdata[index]; + + // Needs checking? + if ((state && (value != ALL_CLEAR)) || + (!state && (value != ALL_SET))) + { + // For each bit in the element... + while ((bit < BITS_PER_ELEMENT) && (position < NBITS)) + { + // Equal to the required state? + if (((value & mask) != 0) == state) + { + return position; + } + + // Move on to the next bit. + mask <<= 1; + ++position; + ++bit; + } + } + else + { + position += BITS_PER_ELEMENT; + } + + // Start at the beginning for all other elements. + bit = 0; + mask = 1; + + ++index; + } + + return ibitset::npos; + } + + //************************************************************************* + /// Read [] operator. + //************************************************************************* + bool operator[] (size_t position) const + { + return test(position); + } + + //************************************************************************* + /// Write [] operator. + //************************************************************************* + bit_reference operator [] (size_t position) + { + return bit_reference(*this, position); + } + + //************************************************************************* + /// operator &= + //************************************************************************* + ibitset& operator &=(const ibitset& other) + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] &= other.pdata[i]; + } + + return *this; + } + + //************************************************************************* + /// operator |= + //************************************************************************* + ibitset& operator |=(const ibitset& other) + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] |= other.pdata[i]; + } + + return *this; + } + + //************************************************************************* + /// operator ^= + //************************************************************************* + ibitset& operator ^=(const ibitset& other) + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] ^= other.pdata[i]; + } + + return *this; + } + + //************************************************************************* + /// operator <<= + //************************************************************************* + ibitset& operator<<=(size_t shift) + { + if (SIZE == 1) + { + pdata[0] <<= shift; + } + else + { + size_t source = NBITS - shift - 1; + size_t destination = NBITS - 1; + + for (size_t i = 0; i < (NBITS - shift); ++i) + { + set(destination--, test(source--)); + } + + for (size_t i = 0; i < shift; ++i) + { + reset(destination--); + } + } + + return *this; + } + + //************************************************************************* + /// operator >>= + //************************************************************************* + ibitset& operator>>=(size_t shift) + { + if (SIZE == 1) + { + pdata[0] >>= shift; + } + else + { + size_t source = shift; + size_t destination = 0; + + for (size_t i = 0; i < (NBITS - shift); ++i) + { + set(destination++, test(source++)); + } + + for (size_t i = 0; i < shift; ++i) + { + reset(destination++); + } + } + + return *this; + } + + //************************************************************************* + /// operator = + //************************************************************************* + ibitset& operator =(const ibitset& other) + { + if (this != &other) + { + etl::copy_n(other.pdata, SIZE, pdata); + } + + return *this; + } + + //************************************************************************* + /// swap + //************************************************************************* + void swap(ibitset& other) + { + std::swap_ranges(pdata, pdata + SIZE, other.pdata); + } + + protected: + + //************************************************************************* + /// Initialise from an unsigned long long. + //************************************************************************* + ibitset& initialise(unsigned long long value) + { + reset(); + + const size_t SHIFT = (integral_limits<unsigned long long>::bits <= (int)BITS_PER_ELEMENT) ? 0 : BITS_PER_ELEMENT; + + // Can we do it in one hit? + if (SHIFT == 0) + { + pdata[0] = element_t(value); + } + else + { + size_t i = 0; + + while ((value != 0) && (i < SIZE)) + { + pdata[i++] = value & ALL_SET; + value = value >> SHIFT; + } + } + + pdata[SIZE - 1] &= TOP_MASK; + + return *this; + } + + //************************************************************************* + /// Invert + //************************************************************************* + void invert() + { + for (size_t i = 0; i < SIZE; ++i) + { + pdata[i] = ~pdata[i]; + } + } + + //************************************************************************* + /// Gets a reference to the specified bit. + //************************************************************************* + bit_reference get_bit_reference(size_t position) + { + return bit_reference(*this, position); + } + + //************************************************************************* + /// Constructor. + //************************************************************************* + ibitset(size_t nbits_, size_t size_, element_t* pdata_) + : NBITS(nbits_), + SIZE(size_), + pdata(pdata_) + { + size_t allocated_bits = SIZE * BITS_PER_ELEMENT; + size_t top_mask_shift = ((BITS_PER_ELEMENT - (allocated_bits - NBITS)) % BITS_PER_ELEMENT); + TOP_MASK = element_t(top_mask_shift == 0 ? ALL_SET : ~(ALL_SET << top_mask_shift)); + } + + //************************************************************************* + /// Compare bitsets. + //************************************************************************* + static bool is_equal(const ibitset& lhs, const ibitset&rhs) + { + return std::equal(lhs.pdata, lhs.pdata + lhs.SIZE, rhs.pdata); + } + + element_t TOP_MASK; + + private: + + // Disable copy construction. + ibitset(const ibitset&); + + const size_t NBITS; + const size_t SIZE; + element_t* pdata; + }; + + //************************************************************************* + /// The class emulates an array of bool elements, but optimized for space allocation. + /// Will accommodate any number of bits. + /// Does not use std::string. + ///\tparam N The number of bits. + ///\ingroup bitset + //************************************************************************* + template <const size_t MAXN> + class bitset : public etl::ibitset + { + + static const size_t ARRAY_SIZE = (MAXN % BITS_PER_ELEMENT == 0) ? MAXN / BITS_PER_ELEMENT : MAXN / BITS_PER_ELEMENT + 1; + + public: + + static const size_t ALLOCATED_BITS = ARRAY_SIZE * BITS_PER_ELEMENT; + + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + bitset() + : etl::ibitset(MAXN, ARRAY_SIZE, data) + { + reset(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + bitset(const bitset<MAXN>& other) + : etl::ibitset(MAXN, ARRAY_SIZE, data) + { + etl::copy_n(other.data, ARRAY_SIZE, data); + } + + //************************************************************************* + /// Construct from a value. + //************************************************************************* + bitset(unsigned long long value) + : etl::ibitset(MAXN, ARRAY_SIZE, data) + { + initialise(value); + } + + //************************************************************************* + /// Construct from a string. + //************************************************************************* + bitset(const char* text) + : etl::ibitset(MAXN, ARRAY_SIZE, data) + { + set(text); + } + + //************************************************************************* + /// Set all of the bits. + //************************************************************************* + bitset<MAXN>& set() + { + etl::ibitset::set(); + return *this; + } + + //************************************************************************* + /// Set the bit at the position. + //************************************************************************* + bitset<MAXN>& set(size_t position, bool value = true) + { + etl::ibitset::set(position, value); + return *this; + } + + //************************************************************************* + /// Set from a string. + //************************************************************************* + bitset<MAXN>& set(const char* text) + { + ETL_ASSERT(text != 0, ETL_ERROR(bitset_nullptr)); + etl::ibitset::set(text); + + return *this; + } + + //************************************************************************* + /// Reset all of the bits. + //************************************************************************* + bitset<MAXN>& reset() + { + ibitset::reset(); + return *this; + } + + //************************************************************************* + /// Reset the bit at the position. + //************************************************************************* + bitset<MAXN>& reset(size_t position) + { + etl::ibitset::reset(position); + return *this; + } + + //************************************************************************* + /// Flip all of the bits. + //************************************************************************* + bitset<MAXN>& flip() + { + ibitset::flip(); + return *this; + } + + //************************************************************************* + /// Flip the bit at the position. + //************************************************************************* + bitset<MAXN>& flip(size_t position) + { + etl::ibitset::flip(position); + return *this; + } + + //************************************************************************* + /// operator = + //************************************************************************* + bitset<MAXN>& operator =(const bitset<MAXN>& other) + { + if (this != &other) + { + etl::copy_n(other.data, ARRAY_SIZE, data); + } + + return *this; + } + + //************************************************************************* + /// operator &= + //************************************************************************* + bitset<MAXN>& operator &=(const bitset<MAXN>& other) + { + etl::ibitset::operator &=(other); + return *this; + } + + //************************************************************************* + /// operator |= + //************************************************************************* + bitset<MAXN>& operator |=(const bitset<MAXN>& other) + { + etl::ibitset::operator |=(other); + return *this; + } + + //************************************************************************* + /// operator ^= + //************************************************************************* + bitset<MAXN>& operator ^=(const bitset<MAXN>& other) + { + ibitset::operator ^=(other); + return *this; + } + + //************************************************************************* + /// operator ~ + //************************************************************************* + bitset<MAXN> operator ~() const + { + etl::bitset<MAXN> temp(*this); + + temp.invert(); + + return temp; + } + + //************************************************************************* + /// operator << + //************************************************************************* + bitset<MAXN> operator<<(size_t shift) const + { + etl::bitset<MAXN> temp(*this); + + temp <<= shift; + + return temp; + } + + //************************************************************************* + /// operator <<= + //************************************************************************* + bitset<MAXN>& operator<<=(size_t shift) + { + etl::ibitset::operator <<=(shift); + return *this; + } + + //************************************************************************* + /// operator >> + //************************************************************************* + bitset<MAXN> operator>>(size_t shift) const + { + bitset<MAXN> temp(*this); + + temp >>= shift; + + return temp; + } + + //************************************************************************* + /// operator >>= + //************************************************************************* + bitset<MAXN>& operator>>=(size_t shift) + { + etl::ibitset::operator >>=(shift); + return *this; + } + + //************************************************************************* + /// operator == + //************************************************************************* + friend bool operator == (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + return etl::ibitset::is_equal(lhs, rhs); + } + + private: + + element_t data[ARRAY_SIZE]; + }; + + //*************************************************************************** + /// operator & + ///\ingroup bitset + //*************************************************************************** + template <const size_t MAXN> + bitset<MAXN> operator & (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + bitset<MAXN> temp(lhs); + temp &= rhs; + return temp; + } + + //*************************************************************************** + /// operator | + ///\ingroup bitset + //*************************************************************************** + template<const size_t MAXN> + bitset<MAXN> operator | (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + bitset<MAXN> temp(lhs); + temp |= rhs; + return temp; + } + + //*************************************************************************** + /// operator ^ + ///\ingroup bitset + //*************************************************************************** + template<const size_t MAXN> + bitset<MAXN> operator ^ (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + bitset<MAXN> temp(lhs); + temp ^= rhs; + return temp; + } + + //*************************************************************************** + /// operator != + ///\ingroup bitset + //*************************************************************************** + template<const size_t MAXN> + bool operator != (const bitset<MAXN>& lhs, const bitset<MAXN>& rhs) + { + return !(lhs == rhs); + } +} + +//************************************************************************* +/// swap +//************************************************************************* +template <const size_t MAXN> +void swap(etl::bitset<MAXN>& lhs, etl::bitset<MAXN>& rhs) +{ + lhs.swap(rhs); +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bloom_filter.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,191 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_BLOOM_FILTER__ +#define __ETL_BLOOM_FILTER__ + +#include "platform.h" +#include "parameter_type.h" +#include "bitset.h" +#include "type_traits.h" +#include "binary.h" +#include "log.h" +#include "power.h" + +///\defgroup bloom_filter bloom_filter +/// A Bloom filter +///\ingroup containers + +namespace etl +{ + namespace __private_bloom_filter__ + { + // Placeholder null hash for defaulted template parameters. + struct null_hash + { + template <typename T> + size_t operator ()(T) + { + return 0; + } + }; + } + + //*************************************************************************** + /// An implementation of a bloom filter. + /// Allows up to three hashes to be defined. + /// Hashes must support the () operator and define 'argument_type'. + ///\tparam DESIRED_WIDTH The desired number of hash results that can be stored. Rounded up to best fit the underlying bitset. + ///\tparam THash1 The first hash generator class. + ///\tparam THash2 The second hash generator class. If omitted, uses the null hash. + ///\tparam THash3 The third hash generator class. If omitted, uses the null hash. + /// The hash classes must define <b>argument_type</b>. + ///\ingroup bloom_filter + //*************************************************************************** + template <const size_t DESIRED_WIDTH, + typename THash1, + typename THash2 = __private_bloom_filter__::null_hash, + typename THash3 = __private_bloom_filter__::null_hash> + class bloom_filter + { + private: + + typedef typename etl::parameter_type<typename THash1::argument_type>::type parameter_t; + typedef __private_bloom_filter__::null_hash null_hash; + + public: + + enum + { + // Make the most efficient use of the bitset. + WIDTH = etl::bitset<DESIRED_WIDTH>::ALLOCATED_BITS + }; + + //*************************************************************************** + /// Clears the bloom filter of all entries. + //*************************************************************************** + void clear() + { + flags.reset(); + } + + //*************************************************************************** + /// Adds a key to the filter. + ///\param key The key to add. + //*************************************************************************** + void add(parameter_t key) + { + flags.set(get_hash<THash1>(key)); + + if (!etl::is_same<THash2, null_hash>::value) + { + flags.set(get_hash<THash2>(key)); + } + + if (!etl::is_same<THash3, null_hash>::value) + { + flags.set(get_hash<THash3>(key)); + } + } + + //*************************************************************************** + /// Tests a key to see if it exists in the filter. + ///\param key The key to test. + ///\return <b>true</b> if the key exists in the filter. + //*************************************************************************** + bool exists(parameter_t key) const + { + bool exists1 = flags[get_hash<THash1>(key)]; + bool exists2 = true; + bool exists3 = true; + + // Do we have a second hash? + if (!etl::is_same<THash2, null_hash>::value) + { + exists2 = flags[get_hash<THash2>(key)]; + } + + // Do we have a third hash? + if (!etl::is_same<THash3, null_hash>::value) + { + exists3 = flags[get_hash<THash3>(key)]; + } + + return exists1 && exists2 && exists3; + } + + //*************************************************************************** + /// Returns the width of the Bloom filter. + //*************************************************************************** + size_t width() const + { + return WIDTH; + } + + //*************************************************************************** + /// Returns the percentage of usage. Range 0 to 100. + //*************************************************************************** + size_t usage() const + { + return (100 * count()) / WIDTH; + } + + //*************************************************************************** + /// Returns the number of filter flags set. + //*************************************************************************** + size_t count() const + { + return flags.count(); + } + + private: + + //*************************************************************************** + /// Gets the hash for the key. + ///\param key The key. + ///\return The hash value. + //*************************************************************************** + template <typename THash> + size_t get_hash(parameter_t key) const + { + size_t hash = THash()(key); + + // Fold the hash down to fit the width. + return fold_bits<size_t, etl::log2<WIDTH>::value>(hash); + } + + /// The Bloom filter flags. + etl::bitset<WIDTH> flags; + }; +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c/ecl_timer.c Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,566 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#include <stdint.h> +#include <assert.h> + +#include "ecl_timer.h" + +//***************************************************************************** +// Internal timer list +//***************************************************************************** + +static ecl_timer_id_t head; +static ecl_timer_id_t tail; +static ecl_timer_id_t current; + +static struct ecl_timer_config* ptimers; + +static void ecl_timer_list_init(struct ecl_timer_config* const ptimers_) +{ + ptimers = ptimers_; + head = ECL_TIMER_NO_TIMER; + tail = ECL_TIMER_NO_TIMER; + current = ECL_TIMER_NO_TIMER; +} + +//******************************* +static struct ecl_timer_config* ecl_timer_list_front() +{ + return &ptimers[head]; +} + +//******************************* +static ecl_timer_id_t ecl_timer_list_begin() +{ + current = head; + return current; +} + +//******************************* +static ecl_timer_id_t ecl_timer_list_next(ecl_timer_id_t last) +{ + current = ptimers[last].next; + return current; +} + +//******************************* +static int ecl_timer_list_empty() +{ + return head == ECL_TIMER_NO_TIMER; +} + +//******************************* +// Inserts the timer at the correct delta position +//******************************* +static void ecl_timer_list_insert(ecl_timer_id_t id_) +{ + struct ecl_timer_config* ptimer = &ptimers[id_]; + + if (head == ECL_TIMER_NO_TIMER) + { + // No entries yet. + head = id_; + tail = id_; + ptimer->previous = ECL_TIMER_NO_TIMER; + ptimer->next = ECL_TIMER_NO_TIMER; + } + else + { + // We already have entries. + ecl_timer_id_t test_id = ecl_timer_list_begin(); + + while (test_id != ECL_TIMER_NO_TIMER) + { + struct ecl_timer_config* ptest = &ptimers[test_id]; + + // Find the correct place to insert. + if (ptimer->delta <= ptest->delta) + { + if (ptest->id == head) + { + head = ptimer->id; + } + + // Insert before ptest-> + ptimer->previous = ptest->previous; + ptest->previous = ptimer->id; + ptimer->next = ptest->id; + + // Adjust the next delta to compensate. + ptest->delta -= ptimer->delta; + + if (ptimer->previous != ECL_TIMER_NO_TIMER) + { + ptimers[ptimer->previous].next = ptimer->id; + } + break; + } + else + { + ptimer->delta -= ptest->delta; + } + + test_id = ecl_timer_list_next(test_id); + } + + // Reached the end? + if (test_id == ECL_TIMER_NO_TIMER) + { + // Tag on to the tail. + ptimers[tail].next = ptimer->id; + ptimer->previous = tail; + ptimer->next = ECL_TIMER_NO_TIMER; + tail = ptimer->id; + } + } +} + +//******************************* +static void ecl_timer_list_remove(ecl_timer_id_t id_, int has_expired) +{ + struct ecl_timer_config* ptimer = &ptimers[id_]; + + if (head == id_) + { + head = ptimer->next; + } + else + { + ptimers[ptimer->previous].next = ptimer->next; + } + + if (tail == id_) + { + tail = ptimer->previous; + } + else + { + ptimers[ptimer->next].previous = ptimer->previous; + } + + if (!has_expired) + { + // Adjust the next delta. + if (ptimer->next != ECL_TIMER_NO_TIMER) + { + ptimers[ptimer->next].delta += ptimer->delta; + } + } + + ptimer->previous = ECL_TIMER_NO_TIMER; + ptimer->next = ECL_TIMER_NO_TIMER; + ptimer->delta = ECL_TIMER_INACTIVE; +} + +//******************************* +static void ecl_timer_list_clear() +{ + ecl_timer_id_t id = ecl_timer_list_begin(); + + while (id != ECL_TIMER_NO_TIMER) + { + struct ecl_timer_config* ptimer = &ptimers[id]; + id = ecl_timer_list_next(id); + ptimer->next = ECL_TIMER_NO_TIMER; + } + + head = ECL_TIMER_NO_TIMER; + tail = ECL_TIMER_NO_TIMER; + current = ECL_TIMER_NO_TIMER; +} + +//***************************************************************************** +// Timer Framework +//***************************************************************************** + +//******************************************* +/// Default initialisation. +//******************************************* +void ecl_timer_data_init_default(struct ecl_timer_config* ptimer_data_) +{ + assert(ptimer_data_ != 0); + + ptimer_data_->pcallback = 0; + ptimer_data_->period = 0; + ptimer_data_->delta = ECL_TIMER_INACTIVE; + ptimer_data_->id = ECL_TIMER_NO_TIMER; + ptimer_data_->previous = ECL_TIMER_NO_TIMER; + ptimer_data_->next = ECL_TIMER_NO_TIMER; + ptimer_data_->repeating = ECL_TIMER_REPEATING; +} + +//******************************************* +/// Parameterised initialisation. +//******************************************* +void ecl_timer_data_init(struct ecl_timer_config* ptimer_data_, + ecl_timer_id_t id_, + void (*pcallback_)(), + ecl_timer_time_t period_, + ecl_timer_mode_t repeating_) +{ + assert(ptimer_data_ != 0); + assert(pcallback_ != 0); + + ptimer_data_->pcallback = pcallback_; + ptimer_data_->period = period_; + ptimer_data_->delta = ECL_TIMER_INACTIVE; + ptimer_data_->id = id_; + ptimer_data_->previous = ECL_TIMER_NO_TIMER; + ptimer_data_->next = ECL_TIMER_NO_TIMER; + ptimer_data_->repeating = repeating_; +} + +//******************************************* +/// Returns true if the timer is active. +//******************************************* +ecl_timer_result_t ecl_timer_is_active(struct ecl_timer_config* ptimer_data_) +{ + assert(ptimer_data_ != 0); + + return (ptimer_data_->delta != ECL_TIMER_INACTIVE) ? ECL_TIMER_PASS : ECL_TIMER_FAIL; +} + +//******************************************* +/// Sets the timer to the inactive state. +//******************************************* +void ecl_set_timer_inactive(struct ecl_timer_config* ptimer_data_) +{ + assert(ptimer_data_ != 0); + + ptimer_data_->delta = ECL_TIMER_INACTIVE; +} + +struct ecl_time_config +{ + struct ecl_timer_config* ptimers; + uint_least8_t max_timers; + volatile ecl_timer_enable_t enabled; + ECL_TIMER_TIMER_SEMAPHORE process_semaphore; + volatile uint_least8_t registered_timers; +}; + +static struct ecl_time_config ecl; + +void ecl_timer_init(struct ecl_timer_config* ptimers_, uint_least8_t max_timers_) +{ + assert(ptimers_ != 0); + + ecl.ptimers = ptimers_; + ecl.max_timers = max_timers_; + ecl.enabled = 0; + ecl.process_semaphore = 0; + ecl.registered_timers = 0; + + int i; + for (i = 0; i < max_timers_; ++i) + { + ecl_timer_data_init_default(&ecl.ptimers[i]); + } + + ecl_timer_list_init(ecl.ptimers); +} + +//******************************************* +/// Register a ptimer-> +//******************************************* +ecl_timer_id_t ecl_timer_register(void (*pcallback_)(), + ecl_timer_time_t period_, + ecl_timer_mode_t repeating_) +{ + assert(pcallback_ != 0); + assert(ecl.ptimers != 0); + + ecl_timer_id_t id = ECL_TIMER_NO_TIMER; + + ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); + + int is_space = (ecl.registered_timers < ecl.max_timers); + + if (is_space) + { + // Search for the free space. + uint_least8_t i; + for (i = 0; i < ecl.max_timers; ++i) + { + struct ecl_timer_config* ptimer = &ecl.ptimers[i]; + + if (ptimer->id == ECL_TIMER_NO_TIMER) + { + // Create in-place. + ecl_timer_data_init(ptimer, i, pcallback_, period_, repeating_); + ++ecl.registered_timers; + id = i; + break; + } + } + } + + ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); + + return id; +} + +//******************************************* +/// Unregister a ptimer-> +//******************************************* +ecl_timer_result_t ecl_timer_unregister(ecl_timer_id_t id_) +{ + assert(ecl.ptimers != 0); + + ecl_timer_result_t result = ECL_TIMER_FAIL; + + if (id_ != ECL_TIMER_NO_TIMER) + { + ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); + + struct ecl_timer_config* ptimer = &ecl.ptimers[id_]; + + if (ptimer->id != ECL_TIMER_NO_TIMER) + { + if (ecl_timer_is_active(ptimer)) + { + ecl_timer_list_remove(ptimer->id, 0); + + // Reset in-place. + ecl_timer_data_init_default(ptimer); + --ecl.registered_timers; + + result = ECL_TIMER_PASS; + } + } + + ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); + } + + return result; +} + +//******************************************* +/// Enable/disable the ptimer-> +//******************************************* +void ecl_timer_enable(ecl_timer_enable_t state_) +{ + assert(ecl.ptimers != 0); + assert((state_ == ECL_TIMER_ENABLED) || (state_ == ECL_TIMER_DISABLED)); + + ecl.enabled = state_; +} + +//******************************************* +/// Get the enable/disable state. +//******************************************* +ecl_timer_result_t ecl_timer_is_running() +{ + return ecl.enabled; +} + +//******************************************* +/// Clears the timer of data. +//******************************************* +void ecl_timer_clear() +{ + ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); + + ecl_timer_list_clear(); + + int i; + for (i = 0; i < ecl.max_timers; ++i) + { + ecl_timer_data_init_default(&ecl.ptimers[i]); + } + + ecl.registered_timers = 0; + + ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); +} + +//******************************************* +// Called by the timer service to indicate the +// amount of time that has elapsed since the last successful call to 'tick'. +// Returns true if the tick was processed, false if not. +//******************************************* +ecl_timer_result_t ecl_timer_tick(uint32_t count) +{ + assert(ecl.ptimers != 0); + + if (ecl.enabled) + { + if (ECL_TIMER_PROCESSING_ENABLED(ecl.process_semaphore)) + { + // We have something to do? + int has_active = !ecl_timer_list_empty(); + + if (has_active) + { + while (has_active && (count >= ecl_timer_list_front()->delta)) + { + struct ecl_timer_config* ptimer = ecl_timer_list_front(); + + count -= ptimer->delta; + + ecl_timer_list_remove(ptimer->id, 1); + + if (ptimer->repeating) + { + // Reinsert the ptimer-> + ptimer->delta = ptimer->period; + ecl_timer_list_insert(ptimer->id); + } + + if (ptimer->pcallback != 0) + { + // Call the C callback. + (ptimer->pcallback)(); + } + + has_active = !ecl_timer_list_empty(); + } + + if (has_active) + { + // Subtract any remainder from the next due timeout. + ecl_timer_list_front()->delta -= count; + } + } + + return ECL_TIMER_PASS; + } + } + + return ECL_TIMER_FAIL; +} + +//******************************************* +/// Starts a timer +//******************************************* +ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immediate_) +{ + assert(ecl.ptimers != 0); + + ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); + + ecl_timer_result_t result = ECL_TIMER_FAIL; + + // Valid timer id? + if (id_ != ECL_TIMER_NO_TIMER) + { + struct ecl_timer_config* ptimer = &ecl.ptimers[id_]; + + // Registered timer? + if (ptimer->id != ECL_TIMER_NO_TIMER) + { + // Has a valid period. + if (ptimer->period != ECL_TIMER_INACTIVE) + { + if (ecl_timer_is_active(ptimer)) + { + ecl_timer_list_remove(ptimer->id, 0); + } + + ptimer->delta = immediate_ ? 0 : ptimer->period; + ecl_timer_list_insert(ptimer->id); + + result = ECL_TIMER_PASS; + } + } + } + + ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); + + return result; +} + +//******************************************* +/// Stops a timer +//******************************************* +ecl_timer_result_t ecl_timer_stop(ecl_timer_id_t id_) +{ + assert(ecl.ptimers != 0); + + ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore); + + ecl_timer_result_t result = ECL_TIMER_FAIL; + + // Valid timer id? + if (id_ != ECL_TIMER_NO_TIMER) + { + struct ecl_timer_config* ptimer = &ecl.ptimers[id_]; + + // Registered timer? + if (ptimer->id != ECL_TIMER_NO_TIMER) + { + if (ecl_timer_is_active(ptimer)) + { + ecl_timer_list_remove(ptimer->id, 0); + result = ECL_TIMER_PASS; + } + } + } + + ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore); + + return result; +} + +//******************************************* +/// Sets a timer's period. +//******************************************* +ecl_timer_result_t ecl_timer_set_period(ecl_timer_id_t id_, ecl_timer_time_t period_) +{ + assert(ecl.ptimers != 0); + + if (ecl_timer_stop(id_)) + { + ecl.ptimers[id_].period = period_; + return ecl_timer_start(id_, 0); + } + + return ECL_TIMER_FAIL; +} + +//******************************************* +/// Sets a timer's mode. +//******************************************* +ecl_timer_result_t ecl_timer_set_mode(ecl_timer_id_t id_, ecl_timer_mode_t repeating_) +{ + assert(ecl.ptimers != 0); + + if (ecl_timer_stop(id_)) + { + ecl.ptimers[id_].repeating = repeating_; + return ecl_timer_start(id_, 0); + } + + return ECL_TIMER_FAIL; +} + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c/ecl_timer.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,119 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_C_TIMER_FRAMEWORK__ +#define __ETL_C_TIMER_FRAMEWORK__ + +#include <stdint.h> + +#include "ecl_user.h" + +// Pass/fail results. +enum +{ + ECL_TIMER_FAIL = 0, + ECL_TIMER_PASS = 1, +}; + +typedef int ecl_timer_result_t; + +// Enable states. +enum +{ + ECL_TIMER_DISABLED = ECL_TIMER_FAIL, + ECL_TIMER_ENABLED = ECL_TIMER_PASS +}; + +typedef int ecl_timer_enable_t; + +// Timer modes. +enum +{ + ECL_TIMER_SINGLE_SHOT = 0, + ECL_TIMER_REPEATING = 1 +}; + +typedef char ecl_timer_mode_t; + +// Timer start action. +enum +{ + ECL_TIMER_START_DELAYED = 0, + ECL_TIMER_START_IMMEDIATE = 1 +}; + +typedef char ecl_timer_start_t; + +// Timer identifiers. +enum +{ + ECL_TIMER_NO_TIMER = 255 +}; + +typedef uint_least8_t ecl_timer_id_t; + +// Timer times. +#define ECL_TIMER_INACTIVE 0xFFFFFFFF + +typedef uint32_t ecl_timer_time_t; + +//************************************************************************* +/// The configuration of a timer. +//************************************************************************* +struct ecl_timer_config +{ + void (*pcallback)(); + ecl_timer_time_t period; + ecl_timer_time_t delta; + ecl_timer_id_t id; + uint_least8_t previous; + uint_least8_t next; + char repeating; +}; + +//************************************************************************* +/// The API. +//************************************************************************* +void ecl_timer_data_init_default(struct ecl_timer_config* ptimer_data_); +void ecl_timer_data_init(struct ecl_timer_config* ptimer_data_, ecl_timer_id_t id_, void(*pcallback_)(), ecl_timer_time_t period_, ecl_timer_mode_t repeating_); +ecl_timer_result_t ecl_timer_is_active(struct ecl_timer_config* ptimer_data_); +void ecl_set_timer_inactive(struct ecl_timer_config* ptimer_data_); +void ecl_timer_init(struct ecl_timer_config* ptimers_, uint_least8_t max_timers_); +ecl_timer_id_t ecl_timer_register(void(*pcallback_)(), ecl_timer_time_t period_, ecl_timer_mode_t repeating_); +ecl_timer_result_t ecl_timer_unregister(ecl_timer_id_t id_); +void ecl_timer_enable(ecl_timer_enable_t state_); +ecl_timer_result_t ecl_timer_is_running(void); +void ecl_timer_clear(void); +ecl_timer_result_t ecl_timer_tick(uint32_t count); +ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immediate_); +ecl_timer_result_t ecl_timer_stop(ecl_timer_id_t id_); +ecl_timer_result_t ecl_timer_set_period(ecl_timer_id_t id_, ecl_timer_time_t period_); +ecl_timer_result_t ecl_timer_set_mode(ecl_timer_id_t id_, ecl_timer_mode_t repeating_); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/callback.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,81 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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_CALLBACK__ +#define __ETL_CALLBACK__ + +namespace etl +{ + //*************************************************************************** + /// A callback class designed to be multiply inherited by other client classes. + /// The class is parametrised with a callback parameter type and a unique id. + /// The unique id allows multiple callbacks with the same parameter type. + ///\tparam TParameter The callback parameter type. + ///\tparam ID The unique id for this callback. + //*************************************************************************** + template <typename TParameter, const int ID> + class callback + { + private: + + // Creates a parameter type unique to this ID. + template <typename T, const int I> + struct parameter + { + parameter(T value) + : value(value) + { + } + + typedef T value_type; + + T value; + + private: + + parameter(); + }; + + // Specialisation for void. + template <const int I> + struct parameter<void, I> + { + typedef void value_type; + }; + + public: + + typedef parameter<TParameter, ID> type; + + virtual void etl_callback(type p = type()) = 0; + }; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/callback_timer.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,694 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_CALLBACK_TIMER__ +#define __ETL_CALLBACK_TIMER__ + +#include <stdint.h> +#include <algorithm> + +#include "platform.h" +#include "nullptr.h" +#include "function.h" +#include "static_assert.h" +#include "timer.h" +#include "atomic.h" + +#undef ETL_FILE +#define ETL_FILE "42" + +namespace etl +{ + //************************************************************************* + /// The configuration of a timer. + struct callback_timer_data + { + //******************************************* + callback_timer_data() + : p_callback(std::nullptr), + period(0), + delta(etl::timer::state::INACTIVE), + id(etl::timer::id::NO_TIMER), + previous(etl::timer::id::NO_TIMER), + next(etl::timer::id::NO_TIMER), + repeating(true), + has_c_callback(true) + { + } + + //******************************************* + /// C function callback + //******************************************* + callback_timer_data(etl::timer::id::type id_, + void (*p_callback_)(), + uint32_t period_, + bool repeating_) + : p_callback(reinterpret_cast<void*>(p_callback_)), + period(period_), + delta(etl::timer::state::INACTIVE), + id(id_), + previous(etl::timer::id::NO_TIMER), + next(etl::timer::id::NO_TIMER), + repeating(repeating_), + has_c_callback(true) + { + } + + //******************************************* + /// ETL function callback + //******************************************* + callback_timer_data(etl::timer::id::type id_, + etl::ifunction<void>& callback_, + uint32_t period_, + bool repeating_) + : p_callback(reinterpret_cast<void*>(&callback_)), + period(period_), + delta(etl::timer::state::INACTIVE), + id(id_), + previous(etl::timer::id::NO_TIMER), + next(etl::timer::id::NO_TIMER), + repeating(repeating_), + has_c_callback(false) + { + } + + //******************************************* + /// Returns true if the timer is active. + //******************************************* + bool is_active() const + { + return delta != etl::timer::state::INACTIVE; + } + + //******************************************* + /// Sets the timer to the inactive state. + //******************************************* + void set_inactive() + { + delta = etl::timer::state::INACTIVE; + } + + void* p_callback; + uint32_t period; + uint32_t delta; + etl::timer::id::type id; + uint_least8_t previous; + uint_least8_t next; + bool repeating; + bool has_c_callback; + + private: + + // Disabled. + callback_timer_data(const callback_timer_data& other); + callback_timer_data& operator =(const callback_timer_data& other); + }; + + namespace __private_callback_timer__ + { + //************************************************************************* + /// A specialised intrusive linked list for timer data. + //************************************************************************* + class list + { + public: + + //******************************* + list(etl::callback_timer_data* ptimers_) + : head(etl::timer::id::NO_TIMER), + tail(etl::timer::id::NO_TIMER), + current(etl::timer::id::NO_TIMER), + ptimers(ptimers_) + { + } + + //******************************* + bool empty() const + { + return head == etl::timer::id::NO_TIMER; + } + + //******************************* + // Inserts the timer at the correct delta position + //******************************* + void insert(etl::timer::id::type id_) + { + etl::callback_timer_data& timer = ptimers[id_]; + + if (head == etl::timer::id::NO_TIMER) + { + // No entries yet. + head = id_; + tail = id_; + timer.previous = etl::timer::id::NO_TIMER; + timer.next = etl::timer::id::NO_TIMER; + } + else + { + // We already have entries. + etl::timer::id::type test_id = begin(); + + while (test_id != etl::timer::id::NO_TIMER) + { + etl::callback_timer_data& test = ptimers[test_id]; + + // Find the correct place to insert. + if (timer.delta <= test.delta) + { + if (test.id == head) + { + head = timer.id; + } + + // Insert before test. + timer.previous = test.previous; + test.previous = timer.id; + timer.next = test.id; + + // Adjust the next delta to compensate. + test.delta -= timer.delta; + + if (timer.previous != etl::timer::id::NO_TIMER) + { + ptimers[timer.previous].next = timer.id; + } + break; + } + else + { + timer.delta -= test.delta; + } + + test_id = next(test_id); + } + + // Reached the end? + if (test_id == etl::timer::id::NO_TIMER) + { + // Tag on to the tail. + ptimers[tail].next = timer.id; + timer.previous = tail; + timer.next = etl::timer::id::NO_TIMER; + tail = timer.id; + } + } + } + + //******************************* + void remove(etl::timer::id::type id_, bool has_expired) + { + etl::callback_timer_data& timer = ptimers[id_]; + + if (head == id_) + { + head = timer.next; + } + else + { + ptimers[timer.previous].next = timer.next; + } + + if (tail == id_) + { + tail = timer.previous; + } + else + { + ptimers[timer.next].previous = timer.previous; + } + + if (!has_expired) + { + // Adjust the next delta. + if (timer.next != etl::timer::id::NO_TIMER) + { + ptimers[timer.next].delta += timer.delta; + } + } + + timer.previous = etl::timer::id::NO_TIMER; + timer.next = etl::timer::id::NO_TIMER; + timer.delta = etl::timer::state::INACTIVE; + } + + //******************************* + etl::callback_timer_data& front() + { + return ptimers[head]; + } + + //******************************* + etl::timer::id::type begin() + { + current = head; + return current; + } + + //******************************* + etl::timer::id::type previous(etl::timer::id::type last) + { + current = ptimers[last].previous; + return current; + } + + //******************************* + etl::timer::id::type next(etl::timer::id::type last) + { + current = ptimers[last].next; + return current; + } + + //******************************* + void clear() + { + etl::timer::id::type id = begin(); + + while (id != etl::timer::id::NO_TIMER) + { + etl::callback_timer_data& timer = ptimers[id]; + id = next(id); + timer.next = etl::timer::id::NO_TIMER; + } + + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; + current = etl::timer::id::NO_TIMER; + } + + private: + + etl::timer::id::type head; + etl::timer::id::type tail; + etl::timer::id::type current; + + etl::callback_timer_data* const ptimers; + }; + } + + //*************************************************************************** + /// Interface for callback timer + //*************************************************************************** + class icallback_timer + { + public: + + //******************************************* + /// Register a timer. + //******************************************* + etl::timer::id::type register_timer(void (*p_callback_)(), + uint32_t period_, + bool repeating_) + { + etl::timer::id::type id = etl::timer::id::NO_TIMER; + + disable_timer_updates(); + + bool is_space = (registered_timers < MAX_TIMERS); + + if (is_space) + { + // Search for the free space. + for (uint_least8_t i = 0; i < MAX_TIMERS; ++i) + { + etl::callback_timer_data& timer = timer_array[i]; + + if (timer.id == etl::timer::id::NO_TIMER) + { + // Create in-place. + new (&timer) callback_timer_data(i, p_callback_, period_, repeating_); + ++registered_timers; + id = i; + break; + } + } + } + + enable_timer_updates(); + + return id; + } + + //******************************************* + /// Register a timer. + //******************************************* + etl::timer::id::type register_timer(etl::ifunction<void>& callback_, + uint32_t period_, + bool repeating_) + { + etl::timer::id::type id = etl::timer::id::NO_TIMER; + + disable_timer_updates(); + + bool is_space = (registered_timers < MAX_TIMERS); + + if (is_space) + { + // Search for the free space. + for (uint_least8_t i = 0; i < MAX_TIMERS; ++i) + { + etl::callback_timer_data& timer = timer_array[i]; + + if (timer.id == etl::timer::id::NO_TIMER) + { + // Create in-place. + new (&timer) callback_timer_data(i, callback_, period_, repeating_); + ++registered_timers; + id = i; + break; + } + } + } + + enable_timer_updates(); + + return id; + } + + //******************************************* + /// Unregister a timer. + //******************************************* + bool unregister_timer(etl::timer::id::type id_) + { + bool result = false; + + if (id_ != etl::timer::id::NO_TIMER) + { + disable_timer_updates(); + + etl::callback_timer_data& timer = timer_array[id_]; + + if (timer.id != etl::timer::id::NO_TIMER) + { + if (timer.is_active()) + { + active_list.remove(timer.id, false); + + // Reset in-place. + new (&timer) callback_timer_data(); + --registered_timers; + + result = true; + } + } + + enable_timer_updates(); + } + + return result; + } + + //******************************************* + /// Enable/disable the timer. + //******************************************* + void enable(bool state_) + { + enabled = state_; + } + + //******************************************* + /// Get the enable/disable state. + //******************************************* + bool is_running() const + { + return enabled; + } + + //******************************************* + /// Clears the timer of data. + //******************************************* + void clear() + { + disable_timer_updates(); + + active_list.clear(); + + for (int i = 0; i < MAX_TIMERS; ++i) + { + new (&timer_array[i]) callback_timer_data(); + } + + registered_timers = 0; + + enable_timer_updates(); + } + + //******************************************* + // Called by the timer service to indicate the + // amount of time that has elapsed since the last successful call to 'tick'. + // Returns true if the tick was processed, + // false if not. + //******************************************* + bool tick(uint32_t count) + { + if (enabled) + { + if (process_semaphore.load() == 0) + { + // We have something to do? + bool has_active = !active_list.empty(); + + if (has_active) + { + while (has_active && (count >= active_list.front().delta)) + { + etl::callback_timer_data& timer = active_list.front(); + + count -= timer.delta; + + active_list.remove(timer.id, true); + + if (timer.repeating) + { + // Reinsert the timer. + timer.delta = timer.period; + active_list.insert(timer.id); + } + + if (timer.p_callback != std::nullptr) + { + if (timer.has_c_callback) + { + // Call the C callback. + reinterpret_cast<void(*)()>(timer.p_callback)(); + } + else + { + // Call the function wrapper callback. + (*reinterpret_cast<etl::ifunction<void>*>(timer.p_callback))(); + } + } + + has_active = !active_list.empty(); + } + + if (has_active) + { + // Subtract any remainder from the next due timeout. + active_list.front().delta -= count; + } + } + + return true; + } + } + + return false; + } + + //******************************************* + /// Starts a timer. + //******************************************* + bool start(etl::timer::id::type id_, bool immediate_ = false) + { + disable_timer_updates(); + + bool result = false; + + // Valid timer id? + if (id_ != etl::timer::id::NO_TIMER) + { + etl::callback_timer_data& timer = timer_array[id_]; + + // Registered timer? + if (timer.id != etl::timer::id::NO_TIMER) + { + // Has a valid period. + if (timer.period != etl::timer::state::INACTIVE) + { + if (timer.is_active()) + { + active_list.remove(timer.id, false); + } + + timer.delta = immediate_ ? 0 : timer.period; + active_list.insert(timer.id); + + result = true; + } + } + } + + enable_timer_updates(); + + return result; + } + + //******************************************* + /// Stops a timer. + //******************************************* + bool stop(etl::timer::id::type id_) + { + disable_timer_updates(); + + bool result = false; + + // Valid timer id? + if (id_ != etl::timer::id::NO_TIMER) + { + etl::callback_timer_data& timer = timer_array[id_]; + + // Registered timer? + if (timer.id != etl::timer::id::NO_TIMER) + { + if (timer.is_active()) + { + active_list.remove(timer.id, false); + result = true; + } + } + } + + enable_timer_updates(); + + return result; + } + + //******************************************* + /// Sets a timer's period. + //******************************************* + bool set_period(etl::timer::id::type id_, uint32_t period_) + { + if (stop(id_)) + { + timer_array[id_].period = period_; + return start(id_); + } + + return false; + } + + //******************************************* + /// Sets a timer's mode. + //******************************************* + bool set_mode(etl::timer::id::type id_, bool repeating_) + { + if (stop(id_)) + { + timer_array[id_].repeating = repeating_; + return start(id_); + } + + return false; + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + icallback_timer(callback_timer_data* const timer_array_, const uint_least8_t MAX_TIMERS_) + : timer_array(timer_array_), + active_list(timer_array_), + enabled(false), + process_semaphore(0), + registered_timers(0), + MAX_TIMERS(MAX_TIMERS_) + { + } + + private: + + //******************************************* + /// Enable timer callback events. + //******************************************* + void enable_timer_updates() + { + --process_semaphore; + } + + //******************************************* + /// Disable timer callback events. + //******************************************* + void disable_timer_updates() + { + ++process_semaphore; + } + + // The array of timer data structures. + callback_timer_data* const timer_array; + + // The list of active timers. + __private_callback_timer__::list active_list; + + volatile bool enabled; + volatile etl::timer_semaphore_t process_semaphore; + volatile uint_least8_t registered_timers; + + public: + + const uint_least8_t MAX_TIMERS; + }; + + //*************************************************************************** + /// The callback timer + //*************************************************************************** + template <const uint_least8_t MAX_TIMERS_> + class callback_timer : public etl::icallback_timer + { + public: + + STATIC_ASSERT(MAX_TIMERS_ <= 254, "No more than 254 timers are allowed"); + + //******************************************* + /// Constructor. + //******************************************* + callback_timer() + : icallback_timer(timer_array, MAX_TIMERS_) + { + } + + private: + + callback_timer_data timer_array[MAX_TIMERS_]; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/char_traits.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,244 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_CHAR_TRAITS__ +#define __ETL_CHAR_TRAITS__ + +#include <algorithm> + +#include "platform.h" +#include <stdint.h> +#include "algorithm.h" + +//***************************************************************************** +///\defgroup char_traits char_traits +/// Character traits +///\ingroup string +//***************************************************************************** + +// Define the large character types if necessary. +#if (ETL_NO_LARGE_CHAR_SUPPORT) +typedef int16_t char16_t; +typedef int32_t char32_t; +#endif + +namespace etl +{ + template<typename T> struct char_traits_types; + + template<> struct char_traits_types<char> + { + typedef char char_type; + typedef int int_type; + typedef long long off_type; + typedef size_t pos_type; + typedef char state_type; + }; + + template<> struct char_traits_types<wchar_t> + { + typedef wchar_t char_type; + typedef wchar_t int_type; + typedef long long off_type; + typedef size_t pos_type; + typedef char state_type; + }; + + template<> struct char_traits_types<char16_t> + { + typedef char16_t char_type; + typedef uint_least16_t int_type; + typedef long long off_type; + typedef size_t pos_type; + typedef char state_type; + }; + + template<> struct char_traits_types<char32_t> + { + typedef char32_t char_type; + typedef uint_least32_t int_type; + typedef long long off_type; + typedef size_t pos_type; + typedef char state_type; + }; + + //*************************************************************************** + /// Character traits for any character type. + //*************************************************************************** + template<typename T> + struct char_traits : public char_traits_types<T> + { + typedef typename char_traits_types<T>::char_type char_type; + typedef typename char_traits_types<T>::int_type int_type; + typedef typename char_traits_types<T>::off_type off_type; + typedef typename char_traits_types<T>::pos_type pos_type; + typedef typename char_traits_types<T>::state_type state_type; + + //************************************************************************* + static bool eq(char_type a, char_type b) + { + return a == b; + } + + //************************************************************************* + static bool lt(char_type a, char_type b) + { + return a < b; + } + + //************************************************************************* + static size_t length(const char_type* str) + { + size_t count = 0; + + if (str != 0) + { + while (*str++ != 0) + { + ++count; + } + } + + return count; + } + + //************************************************************************* + static void assign(char_type& r, const char_type& c) + { + r = c; + } + + //************************************************************************* + static char_type* assign(char_type* p, size_t n, char_type c) + { + if (p != 0) + { + std::fill_n(p, n, c); + } + + return p; + } + + //************************************************************************* + static char_type* move(char_type* dest, const char_type* src, size_t count) + { + if ((dest < src) || (dest > (src + count))) + { + etl::copy_n(src, src + count, dest); + } + else + { + etl::copy_n(std::reverse_iterator<char_type*>(src + count), + count, + std::reverse_iterator<char_type*>(dest + count)); + } + + return dest; + } + + //************************************************************************* + static char_type* copy(char_type* dest, const char_type* src, size_t count) + { + etl::copy_n(src, src + count, dest); + + return dest; + } + + //************************************************************************* + static int compare(const char_type* s1, const char_type* s2, size_t count) + { + for (size_t i = 0; i < count; ++i) + { + if (*s1 < *s2) + { + return -1; + } + else if (*s1 > *s2) + { + return 1; + } + + ++s1; + ++s2; + } + + return 0; + } + + //************************************************************************* + static const char_type* find(const char_type* p, size_t count, const char_type& ch) + { + for (size_t i = 0; i < count; ++i) + { + if (*p == ch) + { + return p; + } + + ++p; + } + + return 0; + } + + //************************************************************************* + static char_type to_char_type(int_type c) + { + return static_cast<char_type>(c); + } + + //************************************************************************* + static int_type to_int_type(char_type c) + { + return static_cast<int_type>(c); + } + + //************************************************************************* + static bool eq_int_type(int_type c1, int_type c2) + { + return (c1 == c2); + } + + //************************************************************************* + static int_type eof() + { + return -1; + } + + //************************************************************************* + static int_type not_eof(int_type e) + { + return (e == eof()) ? eof() - 1 : e; + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/checksum.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,255 @@ + +///\file + +/****************************************************************************** +The MIT License(MIT) +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com +Copyright(c) 2014 jwellbelove +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_CHECKSUM__ +#define __ETL_CHECKSUM__ + +#include <stdint.h> + +#include "platform.h" +#include "binary.h" +#include "frame_check_sequence.h" + +///\defgroup checksum Checksum calculation +///\ingroup maths + +namespace etl +{ + //*************************************************************************** + /// Standard addition checksum policy. + //*************************************************************************** + template <typename T> + struct checksum_policy_sum + { + typedef T value_type; + + inline T initial() const + { + return 0; + } + + inline T add(T sum, uint8_t value) const + { + return sum + value; + } + + inline T final(T sum) const + { + return sum; + } + }; + + //*************************************************************************** + /// BSD checksum policy. + //*************************************************************************** + template <typename T> + struct checksum_policy_bsd + { + typedef T value_type; + + inline T initial() const + { + return 0; + } + + inline T add(T sum, uint8_t value) const + { + return etl::rotate_right(sum) + value; + } + + inline T final(T sum) const + { + return sum; + } + }; + + //*************************************************************************** + /// Standard XOR checksum policy. + //*************************************************************************** + template <typename T> + struct checksum_policy_xor + { + typedef T value_type; + + inline T initial() const + { + return 0; + } + + inline T add(T sum, uint8_t value) const + { + return sum ^ value; + } + + inline T final(T sum) const + { + return sum; + } + }; + + //*************************************************************************** + /// XOR-rotate checksum policy. + //*************************************************************************** + template <typename T> + struct checksum_policy_xor_rotate + { + typedef T value_type; + + inline T initial() const + { + return 0; + } + + inline T add(T sum, uint8_t value) const + { + return etl::rotate_left(sum) ^ value; + } + + inline T final(T sum) const + { + return sum; + } + }; + + //************************************************************************* + /// Standard Checksum. + //************************************************************************* + template <typename T> + class checksum : public etl::frame_check_sequence<etl::checksum_policy_sum<T> > + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + checksum() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + checksum(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; + + //************************************************************************* + /// BSD Checksum. + //************************************************************************* + template <typename T> + class bsd_checksum : public etl::frame_check_sequence<etl::checksum_policy_bsd<T> > + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + bsd_checksum() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + bsd_checksum(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; + + //************************************************************************* + /// XOR Checksum. + //************************************************************************* + template <typename T> + class xor_checksum : public etl::frame_check_sequence<etl::checksum_policy_xor<T> > + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + xor_checksum() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + xor_checksum(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; + + //************************************************************************* + /// XOR-shift Checksum. + //************************************************************************* + template <typename T> + class xor_rotate_checksum : public etl::frame_check_sequence<etl::checksum_policy_xor_rotate<T> > + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + xor_rotate_checksum() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + xor_rotate_checksum(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/compare.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,81 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_COMPARE__ +#define __ETL_COMPARE__ + +#include <functional> + +#include "platform.h" +#include "parameter_type.h" + +//***************************************************************************** +///\defgroup compare compare +/// Comparisons only using less than operator +///\ingroup utilities +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Defines <=, >, >= interms of < + /// Default + //*************************************************************************** + template <typename T, typename TLess = std::less<T> > + struct compare + { + typedef typename etl::parameter_type<T>::type first_argument_type; + typedef typename etl::parameter_type<T>::type second_argument_type; + typedef bool result_type; + + static result_type lt(first_argument_type lhs, second_argument_type rhs) + { + return TLess()(lhs, rhs); + } + + static result_type gt(first_argument_type lhs, second_argument_type rhs) + { + return TLess()(rhs, lhs); + } + + static result_type lte(first_argument_type lhs, second_argument_type rhs) + { + return !gt(lhs, rhs); + } + + static result_type gte(first_argument_type lhs, second_argument_type rhs) + { + return !lt(lhs, rhs); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/constant.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,58 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_CONSTANT__ +#define __ETL_CONSTANT__ + +#include "platform.h" + +//***************************************************************************** +///\defgroup constant constant +///\ingroup utilities +//***************************************************************************** + +namespace etl +{ + template <typename T, const T VALUE> + class constant + { + public: + + typedef T value_type; + + static const T value = VALUE; + }; + + template <typename T, const T VALUE> + const T constant<T, VALUE>::value; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/container.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,306 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_CONTAINER__ +#define __ETL_CONTAINER__ + +#include <stddef.h> +#include <iterator> + +#include "platform.h" + +///\defgroup container container +///\ingroup utilities + +namespace etl +{ + //***************************************************************************** + /// Get the 'begin' iterator. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::iterator begin(TContainer& container) + { + return container.begin(); + } + + //***************************************************************************** + /// Get the 'begin' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::const_iterator begin(const TContainer& container) + { + return container.begin(); + } + + //***************************************************************************** + /// Get the 'begin' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::const_iterator cbegin(const TContainer& container) + { + return container.cbegin(); + } + + //***************************************************************************** + /// Get the 'begin' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::reverse_iterator rbegin(const TContainer& container) + { + return container.rbegin(); + } + + //***************************************************************************** + /// Get the 'begin' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::reverse_iterator crbegin(const TContainer& container) + { + return container.crbegin(); + } + + //***************************************************************************** + /// Get the 'end' iterator for a container. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::iterator end(TContainer& container) + { + return container.end(); + } + + //***************************************************************************** + /// Get the 'end' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::const_iterator end(const TContainer& container) + { + return container.end(); + } + + //***************************************************************************** + /// Get the 'end' const_iterator for a container. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::const_iterator cend(const TContainer& container) + { + return container.cend(); + } + + //***************************************************************************** + /// Get the 'end' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::const_iterator rend(const TContainer& container) + { + return container.rend(); + } + + //***************************************************************************** + /// Get the 'end' reverse_iterator for a container. + ///\ingroup container + //***************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::reverse_iterator crend(const TContainer& container) + { + return container.crend(); + } + + //***************************************************************************** + /// Get the 'begin' pointer for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR TValue* begin(TValue(&data)[ARRAY_SIZE]) + { + return &data[0]; + } + + //***************************************************************************** + /// Get the 'begin' const iterator for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR const TValue* begin(const TValue(&data)[ARRAY_SIZE]) + { + return &data[0]; + } + + //***************************************************************************** + /// Get the 'begin' const iterator for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR const TValue* cbegin(const TValue(&data)[ARRAY_SIZE]) + { + return &data[0]; + } + + //***************************************************************************** + /// Get the 'begin' reverse_iterator for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR std::reverse_iterator<TValue*> rbegin(const TValue(&data)[ARRAY_SIZE]) + { + return std::reverse_iterator<TValue*>(&data[ARRAY_SIZE]); + } + + //***************************************************************************** + /// Get the 'begin' const reverse_iterator for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR std::reverse_iterator<const TValue*> crbegin(const TValue(&data)[ARRAY_SIZE]) + { + return std::reverse_iterator<const TValue*>(&data[ARRAY_SIZE]); + } + + //***************************************************************************** + /// Get the 'end' iterator for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR TValue* end(TValue(&data)[ARRAY_SIZE]) + { + return &data[ARRAY_SIZE]; + } + + //***************************************************************************** + /// Get the 'end' const iterator for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR const TValue* end(const TValue(&data)[ARRAY_SIZE]) + { + return &data[ARRAY_SIZE]; + } + + //***************************************************************************** + /// Get the 'end' const iterator for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR const TValue* cend(const TValue(&data)[ARRAY_SIZE]) + { + return &data[ARRAY_SIZE]; + } + + //***************************************************************************** + /// Get the 'end' reverse_iterator for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR std::reverse_iterator<TValue*> rend(const TValue(&data)[ARRAY_SIZE]) + { + return std::reverse_iterator<TValue*>(&data[0]); + } + + //***************************************************************************** + /// Get the 'end' const reverse_iterator for an array. + ///\ingroup container + //***************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR std::reverse_iterator<const TValue*> crend(const TValue(&data)[ARRAY_SIZE]) + { + return std::reverse_iterator<const TValue*>(&data[0]); + } + + //***************************************************************************** + /// Get the next iterator. + ///\ingroup container + //***************************************************************************** + template<class TIterator> + TIterator next(TIterator iterator, ptrdiff_t n = 1) + { + std::advance(iterator, n); + return iterator; + } + + //***************************************************************************** + /// Get the previous iterator. + ///\ingroup container + //***************************************************************************** + template<class TIterator> + TIterator prev(TIterator iterator, ptrdiff_t n = 1) + { + std::advance(iterator, -n); + return iterator; + } + + ///************************************************************************** + /// Get the size of a container. + /// Expects the container to have defined 'size_type'. + ///\ingroup container + ///************************************************************************** + template<typename TContainer> + ETL_CONSTEXPR typename TContainer::size_type size(const TContainer& container) + { + return container.size(); + } + + ///************************************************************************** + /// Get the size of an array in elements at run time, or compile time if C++11 or above. + ///\ingroup container + ///************************************************************************** + template<typename TValue, const size_t ARRAY_SIZE> + ETL_CONSTEXPR size_t size(TValue(&)[ARRAY_SIZE]) + { + return ARRAY_SIZE; + } + + ///************************************************************************** + /// Get the size of an array in elements at compile time for C++03 + ///\code + /// sizeof(array_size(array)) + ///\endcode + ///\ingroup container + ///************************************************************************** + template <typename T, const size_t ARRAY_SIZE> + char(&array_size(T(&array)[ARRAY_SIZE]))[ARRAY_SIZE]; +} + +#if ETL_CPP11_SUPPORTED + #define ETL_ARRAY_SIZE(a) (etl::size(a)) +#else + #define ETL_ARRAY_SIZE(a) sizeof(etl::array_size(a)) +#endif + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc16.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,61 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#include <stdint.h> + +#include "platform.h" + +namespace etl +{ + //*************************************************************************** + /// CRC16 table + /// \ingroup crc16 + //*************************************************************************** + extern const uint16_t CRC16[] = + { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 + }; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc16.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,109 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_CRC16__ +#define __ETL_CRC16__ + +#include <stdint.h> +#include <iterator> + +#include "platform.h" +#include "frame_check_sequence.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup crc16 16 bit CRC calculation +///\ingroup crc + +namespace etl +{ + //*************************************************************************** + /// CRC16 table + /// \ingroup crc16 + //*************************************************************************** + extern const uint16_t CRC16[]; + + //*************************************************************************** + /// CRC16 policy. + /// Calculates CRC16 using polynomial 0x8005. + //*************************************************************************** + struct crc_policy_16 + { + typedef uint16_t value_type; + + inline uint16_t initial() const + { + return 0; + } + + inline uint16_t add(uint16_t crc, uint8_t value) const + { + return (crc >> 8) ^ CRC16[(crc ^ value) & 0xFF]; + } + + inline uint16_t final(uint16_t crc) const + { + return crc; + } + }; + + //************************************************************************* + /// CRC16 + //************************************************************************* + class crc16 : public etl::frame_check_sequence<etl::crc_policy_16> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + crc16() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + crc16(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc16_ccitt.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,61 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#include <stdint.h> + +#include "platform.h" + +namespace etl +{ + //*************************************************************************** + /// CRC-CCITT table + /// \ingroup crc16_ccitt + //*************************************************************************** + extern const uint16_t CRC_CCITT[] = + { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 + }; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc16_ccitt.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,109 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_CRC16_CCITT__ +#define __ETL_CRC16_CCITT__ + +#include <stdint.h> +#include <iterator> + +#include "platform.h" +#include "frame_check_sequence.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup crc16_ccitt 16 bit CRC CCITT calculation +///\ingroup crc + +namespace etl +{ + //*************************************************************************** + /// CRC-CCITT table + /// \ingroup crc16_ccitt + //*************************************************************************** + extern const uint16_t CRC_CCITT[]; + + //*************************************************************************** + /// CRC16 CCITT policy. + /// Calculates CRC16 CCITT using polynomial 0x1021 + //*************************************************************************** + struct crc_policy_16_ccitt + { + typedef uint16_t value_type; + + inline uint16_t initial() const + { + return 0xFFFF; + } + + inline uint16_t add(uint16_t crc, uint8_t value) const + { + return (crc << 8) ^ CRC_CCITT[((crc >> 8) ^ value) & 0xFF]; + } + + inline uint16_t final(uint16_t crc) const + { + return crc; + } + }; + + //************************************************************************* + /// CRC16 CCITT + //************************************************************************* + class crc16_ccitt : public etl::frame_check_sequence<etl::crc_policy_16_ccitt> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + crc16_ccitt() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + crc16_ccitt(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc16_kermit.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,61 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#include <stdint.h> + +#include "platform.h" + +namespace etl +{ + //*************************************************************************** + /// CRC Kermit table + /// \ingroup crc16_kermit + //*************************************************************************** + extern const uint16_t CRC_KERMIT[] = + { + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, + 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, + 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, + 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, + 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, + 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, + 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, + 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, + 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, + 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, + 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, + 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, + 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, + 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, + 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, + 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 + }; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc16_kermit.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,109 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_CRC16_KERMIT__ +#define __ETL_CRC16_KERMIT__ + +#include <stdint.h> +#include <iterator> + +#include "platform.h" +#include "frame_check_sequence.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup crc16_kermit 16 bit CRC Kermit calculation +///\ingroup crc + +namespace etl +{ + //*************************************************************************** + /// CRC Kermit table + /// \ingroup crc + //*************************************************************************** + extern const uint16_t CRC_KERMIT[]; + + //*************************************************************************** + /// CRC16 Kermit policy. + /// Calculates CRC16 Kermit using polynomial 0x1021 + //*************************************************************************** + struct crc_policy_16_kermit + { + typedef uint16_t value_type; + + inline uint16_t initial() const + { + return 0; + } + + inline uint16_t add(uint16_t crc, uint8_t value) const + { + return (crc >> 8) ^ CRC_KERMIT[(crc ^ value) & 0xFF]; + } + + inline uint16_t final(uint16_t crc) const + { + return crc; + } + }; + + //************************************************************************* + /// CRC16 Kermit + //************************************************************************* + class crc16_kermit : public etl::frame_check_sequence<etl::crc_policy_16_kermit> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + crc16_kermit() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + crc16_kermit(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc32.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,77 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#include <stdint.h> + +#include "platform.h" + +namespace etl +{ + //*************************************************************************** + /// CRC32 table + /// \ingroup crc32 + //*************************************************************************** + extern const uint32_t CRC32[] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc32.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,109 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_CRC32__ +#define __ETL_CRC32__ + +#include <stdint.h> +#include <iterator> + +#include "platform.h" +#include "frame_check_sequence.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup crc32 32 bit CRC calculation +///\ingroup crc + +namespace etl +{ + //*************************************************************************** + /// CRC32 table + /// \ingroup crc32 + //*************************************************************************** + extern const uint32_t CRC32[]; + + //*************************************************************************** + /// CRC32 policy. + /// Calculates CRC32 using polynomial 0x04C11DB7. + //*************************************************************************** + struct crc_policy_32 + { + typedef uint32_t value_type; + + inline uint32_t initial() const + { + return 0xFFFFFFFF; + } + + inline uint32_t add(uint32_t crc, uint8_t value) const + { + return (crc >> 8) ^ CRC32[(crc ^ value) & 0xFF]; + } + + inline uint32_t final(uint32_t crc) const + { + return crc ^ 0xFFFFFFFF; + } + }; + + //************************************************************************* + /// CRC32 + //************************************************************************* + class crc32 : public etl::frame_check_sequence<etl::crc_policy_32> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + crc32() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + crc32(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc64_ecma.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,109 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#include <stdint.h> + +#include "platform.h" + +namespace etl +{ + //*************************************************************************** + /// CRC64_ECMA table + /// \ingroup crc64_ecma + //*************************************************************************** + extern const uint64_t CRC64_ECMA[] = + { + 0x0000000000000000, 0x42F0E1EBA9EA3693, 0x85E1C3D753D46D26, 0xC711223CFA3E5BB5, + 0x493366450E42ECDF, 0x0BC387AEA7A8DA4C, 0xCCD2A5925D9681F9, 0x8E224479F47CB76A, + 0x9266CC8A1C85D9BE, 0xD0962D61B56FEF2D, 0x17870F5D4F51B498, 0x5577EEB6E6BB820B, + 0xDB55AACF12C73561, 0x99A54B24BB2D03F2, 0x5EB4691841135847, 0x1C4488F3E8F96ED4, + 0x663D78FF90E185EF, 0x24CD9914390BB37C, 0xE3DCBB28C335E8C9, 0xA12C5AC36ADFDE5A, + 0x2F0E1EBA9EA36930, 0x6DFEFF5137495FA3, 0xAAEFDD6DCD770416, 0xE81F3C86649D3285, + 0xF45BB4758C645C51, 0xB6AB559E258E6AC2, 0x71BA77A2DFB03177, 0x334A9649765A07E4, + 0xBD68D2308226B08E, 0xFF9833DB2BCC861D, 0x388911E7D1F2DDA8, 0x7A79F00C7818EB3B, + 0xCC7AF1FF21C30BDE, 0x8E8A101488293D4D, 0x499B3228721766F8, 0x0B6BD3C3DBFD506B, + 0x854997BA2F81E701, 0xC7B97651866BD192, 0x00A8546D7C558A27, 0x4258B586D5BFBCB4, + 0x5E1C3D753D46D260, 0x1CECDC9E94ACE4F3, 0xDBFDFEA26E92BF46, 0x990D1F49C77889D5, + 0x172F5B3033043EBF, 0x55DFBADB9AEE082C, 0x92CE98E760D05399, 0xD03E790CC93A650A, + 0xAA478900B1228E31, 0xE8B768EB18C8B8A2, 0x2FA64AD7E2F6E317, 0x6D56AB3C4B1CD584, + 0xE374EF45BF6062EE, 0xA1840EAE168A547D, 0x66952C92ECB40FC8, 0x2465CD79455E395B, + 0x3821458AADA7578F, 0x7AD1A461044D611C, 0xBDC0865DFE733AA9, 0xFF3067B657990C3A, + 0x711223CFA3E5BB50, 0x33E2C2240A0F8DC3, 0xF4F3E018F031D676, 0xB60301F359DBE0E5, + 0xDA050215EA6C212F, 0x98F5E3FE438617BC, 0x5FE4C1C2B9B84C09, 0x1D14202910527A9A, + 0x93366450E42ECDF0, 0xD1C685BB4DC4FB63, 0x16D7A787B7FAA0D6, 0x5427466C1E109645, + 0x4863CE9FF6E9F891, 0x0A932F745F03CE02, 0xCD820D48A53D95B7, 0x8F72ECA30CD7A324, + 0x0150A8DAF8AB144E, 0x43A04931514122DD, 0x84B16B0DAB7F7968, 0xC6418AE602954FFB, + 0xBC387AEA7A8DA4C0, 0xFEC89B01D3679253, 0x39D9B93D2959C9E6, 0x7B2958D680B3FF75, + 0xF50B1CAF74CF481F, 0xB7FBFD44DD257E8C, 0x70EADF78271B2539, 0x321A3E938EF113AA, + 0x2E5EB66066087D7E, 0x6CAE578BCFE24BED, 0xABBF75B735DC1058, 0xE94F945C9C3626CB, + 0x676DD025684A91A1, 0x259D31CEC1A0A732, 0xE28C13F23B9EFC87, 0xA07CF2199274CA14, + 0x167FF3EACBAF2AF1, 0x548F120162451C62, 0x939E303D987B47D7, 0xD16ED1D631917144, + 0x5F4C95AFC5EDC62E, 0x1DBC74446C07F0BD, 0xDAAD56789639AB08, 0x985DB7933FD39D9B, + 0x84193F60D72AF34F, 0xC6E9DE8B7EC0C5DC, 0x01F8FCB784FE9E69, 0x43081D5C2D14A8FA, + 0xCD2A5925D9681F90, 0x8FDAB8CE70822903, 0x48CB9AF28ABC72B6, 0x0A3B7B1923564425, + 0x70428B155B4EAF1E, 0x32B26AFEF2A4998D, 0xF5A348C2089AC238, 0xB753A929A170F4AB, + 0x3971ED50550C43C1, 0x7B810CBBFCE67552, 0xBC902E8706D82EE7, 0xFE60CF6CAF321874, + 0xE224479F47CB76A0, 0xA0D4A674EE214033, 0x67C58448141F1B86, 0x253565A3BDF52D15, + 0xAB1721DA49899A7F, 0xE9E7C031E063ACEC, 0x2EF6E20D1A5DF759, 0x6C0603E6B3B7C1CA, + 0xF6FAE5C07D3274CD, 0xB40A042BD4D8425E, 0x731B26172EE619EB, 0x31EBC7FC870C2F78, + 0xBFC9838573709812, 0xFD39626EDA9AAE81, 0x3A28405220A4F534, 0x78D8A1B9894EC3A7, + 0x649C294A61B7AD73, 0x266CC8A1C85D9BE0, 0xE17DEA9D3263C055, 0xA38D0B769B89F6C6, + 0x2DAF4F0F6FF541AC, 0x6F5FAEE4C61F773F, 0xA84E8CD83C212C8A, 0xEABE6D3395CB1A19, + 0x90C79D3FEDD3F122, 0xD2377CD44439C7B1, 0x15265EE8BE079C04, 0x57D6BF0317EDAA97, + 0xD9F4FB7AE3911DFD, 0x9B041A914A7B2B6E, 0x5C1538ADB04570DB, 0x1EE5D94619AF4648, + 0x02A151B5F156289C, 0x4051B05E58BC1E0F, 0x87409262A28245BA, 0xC5B073890B687329, + 0x4B9237F0FF14C443, 0x0962D61B56FEF2D0, 0xCE73F427ACC0A965, 0x8C8315CC052A9FF6, + 0x3A80143F5CF17F13, 0x7870F5D4F51B4980, 0xBF61D7E80F251235, 0xFD913603A6CF24A6, + 0x73B3727A52B393CC, 0x31439391FB59A55F, 0xF652B1AD0167FEEA, 0xB4A25046A88DC879, + 0xA8E6D8B54074A6AD, 0xEA16395EE99E903E, 0x2D071B6213A0CB8B, 0x6FF7FA89BA4AFD18, + 0xE1D5BEF04E364A72, 0xA3255F1BE7DC7CE1, 0x64347D271DE22754, 0x26C49CCCB40811C7, + 0x5CBD6CC0CC10FAFC, 0x1E4D8D2B65FACC6F, 0xD95CAF179FC497DA, 0x9BAC4EFC362EA149, + 0x158E0A85C2521623, 0x577EEB6E6BB820B0, 0x906FC95291867B05, 0xD29F28B9386C4D96, + 0xCEDBA04AD0952342, 0x8C2B41A1797F15D1, 0x4B3A639D83414E64, 0x09CA82762AAB78F7, + 0x87E8C60FDED7CF9D, 0xC51827E4773DF90E, 0x020905D88D03A2BB, 0x40F9E43324E99428, + 0x2CFFE7D5975E55E2, 0x6E0F063E3EB46371, 0xA91E2402C48A38C4, 0xEBEEC5E96D600E57, + 0x65CC8190991CB93D, 0x273C607B30F68FAE, 0xE02D4247CAC8D41B, 0xA2DDA3AC6322E288, + 0xBE992B5F8BDB8C5C, 0xFC69CAB42231BACF, 0x3B78E888D80FE17A, 0x7988096371E5D7E9, + 0xF7AA4D1A85996083, 0xB55AACF12C735610, 0x724B8ECDD64D0DA5, 0x30BB6F267FA73B36, + 0x4AC29F2A07BFD00D, 0x08327EC1AE55E69E, 0xCF235CFD546BBD2B, 0x8DD3BD16FD818BB8, + 0x03F1F96F09FD3CD2, 0x41011884A0170A41, 0x86103AB85A2951F4, 0xC4E0DB53F3C36767, + 0xD8A453A01B3A09B3, 0x9A54B24BB2D03F20, 0x5D45907748EE6495, 0x1FB5719CE1045206, + 0x919735E51578E56C, 0xD367D40EBC92D3FF, 0x1476F63246AC884A, 0x568617D9EF46BED9, + 0xE085162AB69D5E3C, 0xA275F7C11F7768AF, 0x6564D5FDE549331A, 0x279434164CA30589, + 0xA9B6706FB8DFB2E3, 0xEB46918411358470, 0x2C57B3B8EB0BDFC5, 0x6EA7525342E1E956, + 0x72E3DAA0AA188782, 0x30133B4B03F2B111, 0xF7021977F9CCEAA4, 0xB5F2F89C5026DC37, + 0x3BD0BCE5A45A6B5D, 0x79205D0E0DB05DCE, 0xBE317F32F78E067B, 0xFCC19ED95E6430E8, + 0x86B86ED5267CDBD3, 0xC4488F3E8F96ED40, 0x0359AD0275A8B6F5, 0x41A94CE9DC428066, + 0xCF8B0890283E370C, 0x8D7BE97B81D4019F, 0x4A6ACB477BEA5A2A, 0x089A2AACD2006CB9, + 0x14DEA25F3AF9026D, 0x562E43B4931334FE, 0x913F6188692D6F4B, 0xD3CF8063C0C759D8, + 0x5DEDC41A34BBEEB2, 0x1F1D25F19D51D821, 0xD80C07CD676F8394, 0x9AFCE626CE85B507 + }; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc64_ecma.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,109 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_CRC64_ECMA__ +#define __ETL_CRC64_ECMA__ + +#include <stdint.h> +#include <iterator> + +#include "platform.h" +#include "frame_check_sequence.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup crc64_ecma 64 bit CRC ECMA calculation +///\ingroup crc + +namespace etl +{ + //*************************************************************************** + /// CRC64_ECMA table + /// \ingroup crc64_ecma + //*************************************************************************** + extern const uint64_t CRC64_ECMA[]; + + //*************************************************************************** + /// CRC64 policy. + /// Calculates CRC64 ECMA using polynomial 0x42F0E1EBA9EA3693. + //*************************************************************************** + struct crc_policy_64_ecma + { + typedef uint64_t value_type; + + inline uint64_t initial() const + { + return 0; + } + + inline uint64_t add(uint64_t crc, uint8_t value) const + { + return (crc << 8) ^ CRC64_ECMA[((crc >> 56) ^ value) & 0xFF]; + } + + inline uint64_t final(uint64_t crc) const + { + return crc; + } + }; + + //************************************************************************* + /// CRC64 ECMA + //************************************************************************* + class crc64_ecma : public etl::frame_check_sequence<etl::crc_policy_64_ecma> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + crc64_ecma() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + crc64_ecma(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc8_ccitt.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,64 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#include <stdint.h> + +#include "platform.h" +#include "static_assert.h" + +STATIC_ASSERT(ETL_8BIT_SUPPORT, "This file does not currently support targets with no 8bit type"); + +namespace etl +{ + //*************************************************************************** + /// CRC8 table + /// \ingroup crc8_ccitt + //*************************************************************************** + extern const uint8_t CRC8_CCITT[] = + { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 + }; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc8_ccitt.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,109 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_CRC8_CCITT__ +#define __ETL_CRC8_CCITT__ + +#include <stdint.h> +#include <iterator> + +#include "platform.h" +#include "frame_check_sequence.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup crc8_ccitt 8 bit CRC calculation +///\ingroup crc + +namespace etl +{ + //*************************************************************************** + /// CRC8 table + /// \ingroup crc8_ccitt + //*************************************************************************** + extern const uint8_t CRC8_CCITT[]; + + //*************************************************************************** + /// CRC8 CCITT policy. + /// Calculates CRC8 CCITT using polynomial 0x07. + //*************************************************************************** + struct crc_policy_8_ccitt + { + typedef uint8_t value_type; + + inline uint8_t initial() const + { + return 0; + } + + inline uint8_t add(uint8_t crc, uint8_t value) const + { + return CRC8_CCITT[crc ^ value]; + } + + inline uint8_t final(uint8_t crc) const + { + return crc; + } + }; + + //************************************************************************* + /// CRC8 CCITT + //************************************************************************* + class crc8_ccitt : public etl::frame_check_sequence<etl::crc_policy_8_ccitt> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + crc8_ccitt() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + crc8_ccitt(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cstring.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,220 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_STRING__ +#define __ETL_STRING__ + +#include "platform.h" +#include "basic_string.h" +#include "hash.h" + +#if defined(ETL_COMPILER_MICROSOFT) +#undef min +#endif + +namespace etl +{ + typedef etl::ibasic_string<char> istring; + + //*************************************************************************** + /// A string implementation that uses a fixed size buffer. + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup string + //*************************************************************************** + template <const size_t MAX_SIZE_> + class string : public istring + { + public: + + typedef istring::value_type value_type; + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + string() + : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + istring::initialise(); + } + + //************************************************************************* + /// Copy constructor. + ///\param other The other string. + //************************************************************************* + string(const etl::string<MAX_SIZE_>& other) + : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + istring::assign(other.begin(), other.end()); + } + + //************************************************************************* + /// From other string, position, length. + ///\param other The other string. + ///\param position The position of the first character. + ///\param length The number of characters. Default = npos. + //************************************************************************* + string(const etl::string<MAX_SIZE_>& other, size_t position, size_t length_ = npos) + : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds)); + + // Set the length to the exact amount. + length_ = (length_ > MAX_SIZE_) ? MAX_SIZE_ : length_; + + istring::assign(other.begin() + position, other.begin() + position + length_); + } + + //************************************************************************* + /// Constructor, from null terminated text. + ///\param text The initial text of the string. + //************************************************************************* + string(const value_type* text) + : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + istring::assign(text, text + etl::char_traits<value_type>::length(text)); + } + + //************************************************************************* + /// Constructor, from null terminated text and count. + ///\param text The initial text of the string. + ///\param count The number of characters to copy. + //************************************************************************* + string(const value_type* text, size_t count) + : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + istring::assign(text, text + count); + } + + //************************************************************************* + /// Constructor, from initial size and value. + ///\param initialSize The initial size of the string. + ///\param value The value to fill the string with. + //************************************************************************* + string(size_t count, value_type c) + : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + istring::initialise(); + istring::resize(count, c); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + string(TIterator first, TIterator last) + : istring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + istring::assign(first, last); + } + + //************************************************************************* + /// Returns a sub-string. + ///\param position The position of the first character. Default = 0. + ///\param length The number of characters. Default = npos. + //************************************************************************* + etl::string<MAX_SIZE_> substr(size_t position = 0, size_t length_ = npos) const + { + etl::string<MAX_SIZE_> new_string; + + if (position != this->size()) + { + ETL_ASSERT(position < this->size(), ETL_ERROR(string_out_of_bounds)); + + length_ = std::min(length_, this->size() - position); + + new_string.assign(buffer + position, buffer + position + length_); + } + + return new_string; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + string& operator = (const string& rhs) + { + if (&rhs != this) + { + istring::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair() + { + etl::istring::repair(buffer); + } + + private: + + value_type buffer[MAX_SIZE + 1]; + }; + + //************************************************************************* + /// Hash function. + //************************************************************************* +#if ETL_8BIT_SUPPORT + template <> + struct hash<etl::istring> + { + size_t operator()(const etl::istring& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; + + template <const size_t SIZE> + struct hash<etl::string<SIZE> > + { + size_t operator()(const etl::string<SIZE>& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; +#endif +} + +#if defined(ETL_COMPILER_MICROSOFT) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cyclic_value.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,582 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_CYCLIC_VALUE__ +#define __ETL_CYCLIC_VALUE__ + +#include <stddef.h> + +///\defgroup cyclic_value cyclic_value +/// Provides a value that cycles between two limits. +/// \ingroup utilities + +#include <algorithm> + +#include "platform.h" +#include "static_assert.h" +#include "exception.h" +#include "static_assert.h" +#include "type_traits.h" + +namespace etl +{ + //*************************************************************************** + /// Provides a value that cycles between two limits. + /// Supports incrementing and decrementing. + ///\tparam T The type of the variable. + ///\tparam FIRST The first value of the range. + ///\tparam LAST The last value of the range. + ///\ingroup cyclic_value + //*************************************************************************** + template <typename T, T FIRST = 0, T LAST = 0, typename = void> + class cyclic_value + { + public: + + //************************************************************************* + /// Constructor. + /// The initial value is set to the first value. + //************************************************************************* + cyclic_value() + : value(FIRST) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + cyclic_value(const cyclic_value<T, FIRST, LAST>& other) + : value(other.value) + { + } + + //************************************************************************* + /// Sets the value. + ///\param value The value. + //************************************************************************* + void set(T value_) + { + if (value_ > LAST) + { + value_ = LAST; + } + else if (value_ < FIRST) + { + value_ = FIRST; + } + + value = value_; + } + + //************************************************************************* + /// Resets the value to the first in the range. + //************************************************************************* + void to_first() + { + value = FIRST; + } + + //************************************************************************* + /// Resets the value to the last in the range. + //************************************************************************* + void to_last() + { + value = LAST; + } + + //************************************************************************* + /// Advances to value by a number of steps. + ///\param n The number of steps to advance. + //************************************************************************* + void advance(int n) + { + T range = LAST - FIRST + T(1); + + n = n % range; + + if (n > 0) + { + for (int i = 0; i < n; ++i) + { + operator ++(); + } + } + else + { + for (int i = 0; i < -n; ++i) + { + operator --(); + } + } + } + + //************************************************************************* + /// Conversion operator. + /// \return The value of the underlying type. + //************************************************************************* + operator T() + { + return value; + } + + //************************************************************************* + /// Const conversion operator. + /// \return The value of the underlying type. + //************************************************************************* + operator const T() const + { + return value; + } + + //************************************************************************* + /// ++ operator. + //************************************************************************* + cyclic_value& operator ++() + { + if (value >= LAST) + { + value = FIRST; + } + else + { + ++value; + } + + return *this; + } + + //************************************************************************* + /// ++ operator. + //************************************************************************* + cyclic_value operator ++(int) + { + cyclic_value temp(*this); + + operator++(); + + return temp; + } + + //************************************************************************* + /// -- operator. + //************************************************************************* + cyclic_value& operator --() + { + if (value <= FIRST) + { + value = LAST; + } + else + { + --value; + } + + return *this; + } + + //************************************************************************* + /// -- operator. + //************************************************************************* + cyclic_value operator --(int) + { + cyclic_value temp(*this); + + operator--(); + + return temp; + } + + //************************************************************************* + /// = operator. + //************************************************************************* + cyclic_value& operator =(T t) + { + set(t); + return *this; + } + + //************************************************************************* + /// = operator. + //************************************************************************* + template <const T FIRST2, const T LAST2> + cyclic_value& operator =(const cyclic_value<T, FIRST2, LAST2>& other) + { + set(other.get()); + return *this; + } + + //************************************************************************* + /// Gets the value. + //************************************************************************* + T get() const + { + return value; + } + + //************************************************************************* + /// Gets the first value. + //************************************************************************* + const T first() const + { + return FIRST; + } + + //************************************************************************* + /// Gets the last value. + //************************************************************************* + const T last() const + { + return LAST; + } + + //************************************************************************* + /// Swaps the values. + //************************************************************************* + void swap(cyclic_value<T, FIRST, LAST>& other) + { + std::swap(value, other.value); + } + + //************************************************************************* + /// Swaps the values. + //************************************************************************* + friend void swap(cyclic_value<T, FIRST, LAST>& lhs, cyclic_value<T, FIRST, LAST>& rhs) + { + lhs.swap(rhs); + } + + //************************************************************************* + /// Operator ==. + //************************************************************************* + friend bool operator == (const cyclic_value<T, FIRST, LAST>& lhs, const cyclic_value<T, FIRST, LAST>& rhs) + { + return lhs.value == rhs.value; + } + + //************************************************************************* + /// Operator !=. + //************************************************************************* + friend bool operator != (const cyclic_value<T, FIRST, LAST>& lhs, const cyclic_value<T, FIRST, LAST>& rhs) + { + return !(lhs == rhs); + } + + private: + + T value; ///< The current value. + }; + + //*************************************************************************** + /// Provides a value that cycles between two limits. + /// Supports incrementing and decrementing. + ///\tparam T The type of the variable. + ///\tparam FIRST The first value of the range. + ///\tparam LAST The last value of the range. + ///\ingroup cyclic_value + //*************************************************************************** + template <typename T, const T FIRST, const T LAST> + class cyclic_value<T, FIRST, LAST, typename etl::enable_if<(FIRST == 0) && (LAST == 0)>::type> + { + public: + + //************************************************************************* + /// Constructor. + /// Sets 'first' and 'last' to the template parameter values. + /// The initial value is set to the first value. + //************************************************************************* + cyclic_value() + : value(FIRST), + first_value(FIRST), + last_value(LAST) + { + } + + //************************************************************************* + /// Constructor. + /// Sets the value to the first of the range. + ///\param first The first value in the range. + ///\param last The last value in the range. + //************************************************************************* + cyclic_value(T first_, T last_) + : value(first_), + first_value(first_), + last_value(last_) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + cyclic_value(const cyclic_value& other) + : value(other.value), + first_value(other.first_value), + last_value(other.last_value) + { + } + + //************************************************************************* + /// Sets the range. + /// Sets the value to the first of the range. + ///\param first The first value in the range. + ///\param last The last value in the range. + //************************************************************************* + void set(T first_, T last_) + { + first_value = first_; + last_value = last_; + value = first_; + } + + //************************************************************************* + /// Sets the value. + ///\param value The value. + //************************************************************************* + void set(T value_) + { + if (value_ > last_value) + { + value_ = last_value; + } + else if (value_ < first_value) + { + value_ = first_value; + } + + value = value_; + } + + //************************************************************************* + /// Resets the value to the first in the range. + //************************************************************************* + void to_first() + { + value = first_value; + } + + //************************************************************************* + /// Resets the value to the last in the range. + //************************************************************************* + void to_last() + { + value = last_value; + } + + //************************************************************************* + /// Advances to value by a number of steps. + ///\param n The number of steps to advance. + //************************************************************************* + void advance(int n) + { + T range = last_value - first_value + T(1); + + n = n % range; + + if (n > 0) + { + for (int i = 0; i < n; ++i) + { + operator ++(); + } + } + else + { + for (int i = 0; i < -n; ++i) + { + operator --(); + } + } + } + + //************************************************************************* + /// Conversion operator. + /// \return The value of the underlying type. + //************************************************************************* + operator T() + { + return value; + } + + //************************************************************************* + /// Const conversion operator. + /// \return The value of the underlying type. + //************************************************************************* + operator const T() const + { + return value; + } + + //************************************************************************* + /// ++ operator. + //************************************************************************* + cyclic_value& operator ++() + { + if (value >= last_value) + { + value = first_value; + } + else + { + ++value; + } + + return *this; + } + + //************************************************************************* + /// ++ operator. + //************************************************************************* + cyclic_value operator ++(int) + { + cyclic_value temp(*this); + + operator++(); + + return temp; + } + + //************************************************************************* + /// -- operator. + //************************************************************************* + cyclic_value& operator --() + { + if (value <= first_value) + { + value = last_value; + } + else + { + --value; + } + + return *this; + } + + //************************************************************************* + /// -- operator. + //************************************************************************* + cyclic_value operator --(int) + { + cyclic_value temp(*this); + + operator--(); + + return temp; + } + + //************************************************************************* + /// = operator. + //************************************************************************* + cyclic_value& operator =(T t) + { + set(t); + return *this; + } + + //************************************************************************* + /// = operator. + //************************************************************************* + cyclic_value& operator =(const cyclic_value& other) + { + value = other.value; + first_value = other.first_value; + last_value = other.last_value; + return *this; + } + + //************************************************************************* + /// Gets the value. + //************************************************************************* + T get() const + { + return value; + } + + //************************************************************************* + /// Gets the first value. + //************************************************************************* + T first() const + { + return first_value; + } + + //************************************************************************* + /// Gets the last value. + //************************************************************************* + T last() const + { + return last_value; + } + + //************************************************************************* + /// Swaps the values. + //************************************************************************* + void swap(cyclic_value<T, FIRST, LAST>& other) + { + std::swap(first_value, other.first_value); + std::swap(last_value, other.last_value); + std::swap(value, other.value); + } + + //************************************************************************* + /// Swaps the values. + //************************************************************************* + friend void swap(cyclic_value<T, FIRST, LAST>& lhs, cyclic_value<T, FIRST, LAST>& rhs) + { + lhs.swap(rhs); + } + + //************************************************************************* + /// Operator ==. + //************************************************************************* + friend bool operator == (const cyclic_value<T, FIRST, LAST>& lhs, const cyclic_value<T, FIRST, LAST>& rhs) + { + return (lhs.value == rhs.value) && + (lhs.first_value == rhs.first_value) && + (lhs.last_value == rhs.last_value); + } + + //************************************************************************* + /// Operator !=. + //************************************************************************* + friend bool operator != (const cyclic_value<T, FIRST, LAST>& lhs, const cyclic_value<T, FIRST, LAST>& rhs) + { + return !(lhs == rhs); + } + + private: + + T value; ///< The current value. + T first_value; ///< The first value in the range. + T last_value; ///< The last value in the range. + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debounce.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,490 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_DEBOUNCE__ +#define __ETL_DEBOUNCE__ + +#include <stdint.h> + +#include "platform.h" +#include "static_assert.h" + +namespace etl +{ + namespace __private_debounce__ + { + class debounce_base + { + public: + + void add(bool sample) + { + state &= ~CHANGED; + + // Changed from last time? + if (sample != bool((state & LAST) != 0)) + { + count = START_COUNT; + } + } + + //************************************************************************* + /// Gets the current debouncer change state. + ///\return 'true' if the debouncer has changed state. + //************************************************************************* + bool has_changed() const + { + return (state & CHANGED) != 0; + } + + //************************************************************************* + /// Gets the current debouncer state. + ///\return 'true' if the debouncer is in the true state. + //************************************************************************* + bool is_set() const + { + return (state & CURRENT) != 0; + } + + //************************************************************************* + /// Gets the debouncer hold state. + ///\return 'true' if the debouncer is in the hold state. + //************************************************************************* + bool is_held() const + { + return (state & HELD) != 0; + } + + //************************************************************************* + /// Gets the debouncer repeat state. + ///\return 'true' if the debouncer is repeating. + //************************************************************************* + bool is_repeating() const + { + return (state & REPEATING) != 0; + } + + protected: + + //************************************************************************* + /// Constructor. + ///\param initial_state The initial state. Default = false. + //************************************************************************* + debounce_base(bool initial_state = false) + : state(initial_state ? (CURRENT | LAST) : 0), + count(START_COUNT) + { + } + + enum + { + START_COUNT = 0 + }; + + enum + { + CURRENT = 1, + LAST = 2, + HELD = 4, + CHANGED = 8, + REPEATING = 16 + }; + + uint_least8_t state; + + /// The state count. + uint16_t count; + }; + } + + //*************************************************************************** + /// A class to debounce signals. + /// The state is decided over N samples, defined by the VALID_COUNT value. + /// If the samples are consistent for VALID_COUNT times then the debouncer state is defined. + /// If the samples change then the debouncer will change state after VALID_COUNT samples. + /// If the samples are true for a count of HOLD_COUNT then the debouncer input is 'held'. + /// The debouncer may be constructed in either state. + //*************************************************************************** + template <const uint16_t VALID_COUNT = 0, const uint16_t HOLD_COUNT = 0, const uint16_t REPEAT_COUNT = 0> + class debounce : public __private_debounce__::debounce_base + { + private: + + enum + { + VALID_THRESHOLD = VALID_COUNT, + HOLD_THRESHOLD = VALID_THRESHOLD + HOLD_COUNT, + REPEAT_THRESHOLD = HOLD_THRESHOLD + REPEAT_COUNT + }; + + using debounce_base::add; + + public: + + //************************************************************************* + /// Constructor. + ///\param initial_state The initial state. Default = false. + //************************************************************************* + debounce(bool initial_state = false) + : debounce_base(initial_state) + { + } + + //************************************************************************* + /// Adds a new sample. + /// Returns 'true' if the debouncer changes state from... + /// 1. Clear to Set. + /// 2. Set to Clear. + /// 3. Not Held to Held. + /// 4. Key repeats. + ///\param sample The new sample. + ///\return 'true' if the debouncer changed state. + //************************************************************************* + bool add(bool sample) + { + debounce_base::add(sample); + + if (count < REPEAT_THRESHOLD) + { + ++count; + + if (sample) + { + if (count == VALID_THRESHOLD) + { + // Set. + state |= CHANGED; + state |= CURRENT; + } + else if (count == HOLD_THRESHOLD) + { + // Held. + state |= CHANGED; + state |= HELD; + } + else if (count == REPEAT_THRESHOLD) + { + // Repeat. + state |= CHANGED; + state |= REPEATING; + count = HOLD_THRESHOLD; + } + + state |= LAST; + } + else + { + if (count == VALID_THRESHOLD) + { + // Clear. + state |= CHANGED; + state &= ~CURRENT; + state &= ~HELD; + state &= ~REPEATING; + } + + state &= ~LAST; + } + } + + return (state & CHANGED) != 0; + } + }; + + template <const uint16_t VALID_COUNT, const uint16_t HOLD_COUNT> + class debounce<VALID_COUNT, HOLD_COUNT, 0> : public __private_debounce__::debounce_base + { + private: + + enum + { + VALID_THRESHOLD = VALID_COUNT, + HOLD_THRESHOLD = VALID_THRESHOLD + HOLD_COUNT + }; + + using debounce_base::add; + + public: + + //************************************************************************* + /// Constructor. + ///\param initial_state The initial state. Default = false. + //************************************************************************* + debounce(bool initial_state = false) + : debounce_base(initial_state) + { + } + + //************************************************************************* + /// Adds a new sample. + /// Returns 'true' if the debouncer changes state from... + /// 1. Clear to Set. + /// 2. Set to Clear. + /// 3. Not Held to Held. + ///\param sample The new sample. + ///\return 'true' if the debouncer changed state. + //************************************************************************* + bool add(bool sample) + { + debounce_base::add(sample); + + if (count < HOLD_THRESHOLD) + { + ++count; + + if (sample) + { + if (count == VALID_THRESHOLD) + { + // Set. + state |= CHANGED; + state |= CURRENT; + } + else if (count == HOLD_THRESHOLD) + { + // Held. + state |= CHANGED; + state |= HELD; + } + + state |= LAST; + } + else + { + if (count == VALID_THRESHOLD) + { + // Clear. + state |= CHANGED; + state &= ~CURRENT; + state &= ~HELD; + state &= ~REPEATING; + } + + state &= ~LAST; + } + } + + return (state & CHANGED) != 0; + } + }; + + template <const uint16_t VALID_COUNT> + class debounce<VALID_COUNT, 0, 0> : public __private_debounce__::debounce_base + { + private: + + enum + { + VALID_THRESHOLD = VALID_COUNT + }; + + using debounce_base::add; + + public: + + //************************************************************************* + /// Constructor. + ///\param initial_state The initial state. Default = false. + //************************************************************************* + debounce(bool initial_state = false) + : debounce_base(initial_state) + { + } + + //************************************************************************* + /// Adds a new sample. + /// Returns 'true' if the debouncer changes state from... + /// 1. Clear to Set. + /// 2. Set to Clear. + ///\param sample The new sample. + ///\return 'true' if the debouncer changed state. + //************************************************************************* + bool add(bool sample) + { + debounce_base::add(sample); + + if (count < VALID_THRESHOLD) + { + ++count; + + if (sample) + { + if (count == VALID_THRESHOLD) + { + // Set. + state |= CHANGED; + state |= CURRENT; + } + + state |= LAST; + } + else + { + if (count == VALID_THRESHOLD) + { + // Clear. + state |= CHANGED; + state &= ~CURRENT; + state &= ~HELD; + state &= ~REPEATING; + } + + state &= ~LAST; + } + } + + return (state & CHANGED) != 0; + } + }; + + template <> + class debounce<0, 0, 0> : public __private_debounce__::debounce_base + { + public: + + using debounce_base::add; + + //************************************************************************* + /// Constructor. + ///\param initial_state The initial state. Default = false. + //************************************************************************* + debounce() + : debounce_base(false), + valid_threshold(1), + hold_threshold(0), + repeat_threshold(0) + { + } + + //************************************************************************* + /// Constructor. + ///\param initial_state The initial state. + ///\param valid_count The count for a valid state. Default = 1. + ///\param hold_count The count after valid_count for a hold state. Default = 0. + ///\param repeat_count The count after hold_count for a key repeat. Default = 0. + //************************************************************************* + debounce(bool initial_state, uint16_t valid_count = 1, uint16_t hold_count = 0, uint16_t repeat_count = 0) + : debounce_base(initial_state) + { + set(valid_count, hold_count, repeat_count); + } + + //************************************************************************* + /// Constructor. + ///\param initial_state The initial state. Default = false. + //************************************************************************* + void set(uint16_t valid_count, uint16_t hold_count = 0, uint16_t repeat_count = 0) + { + valid_threshold = valid_count; + hold_threshold = valid_threshold + hold_count; + repeat_threshold = hold_threshold + repeat_count; + } + + //************************************************************************* + /// Adds a new sample. + /// Returns 'true' if the debouncer changes state from... + /// 1. Clear to Set. + /// 2. Set to Clear. + /// 3. Not Held to Held. + /// 4. Key repeats. + ///\param sample The new sample. + ///\return 'true' if the debouncer changed state. + //************************************************************************* + bool add(bool sample) + { + debounce_base::add(sample); + + if (count < repeat_threshold) + { + ++count; + + if (sample) + { + if (count == valid_threshold) + { + if (sample) + { + // Set. + state |= CHANGED; + state |= CURRENT; + } + } + + if (hold_threshold != valid_threshold) + { + if ((count == hold_threshold) && sample) + { + // Held. + state |= CHANGED; + state |= HELD; + } + } + + if (repeat_threshold != hold_threshold) + { + if ((count == repeat_threshold) && sample) + { + // Repeat. + state |= CHANGED; + state |= REPEATING; + count = hold_threshold; + } + } + + state |= LAST; + } + else + { + if (count == valid_threshold) + { + // Clear. + state |= CHANGED; + state &= ~CURRENT; + state &= ~HELD; + state &= ~REPEATING; + } + + state &= ~LAST; + } + } + + return (state & CHANGED) != 0; + } + + private: + + uint16_t valid_threshold; + uint16_t hold_threshold; + uint16_t repeat_threshold; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug_count.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,148 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_DEBUG_COUNT__ +#define __ETL_DEBUG_COUNT__ + +#include <stdint.h> +#include <assert.h> + +#include "platform.h" + +///\defgroup debug_count debug count +///\ingroup utilities + +namespace etl +{ + //*************************************************************************** + /// Used to count instances. + /// Asserts if the count is decremented below zero. + /// Asserts if the count is not zero when destructed. + /// Does nothing in a non-debug build. + ///\ingroup reference + //*************************************************************************** + class debug_count + { + public: + +#if defined(ETL_DEBUG) + inline debug_count() + : count(0) + { + } + + inline ~debug_count() + { + assert(count == 0); + } + + inline debug_count& operator ++() + { + ++count; + return *this; + } + + inline debug_count& operator --() + { + --count; + assert(count >= 0); + return *this; + } + + inline debug_count& operator +=(int32_t n) + { + count += n; + return *this; + } + + inline debug_count& operator -=(int32_t n) + { + count -= n; + return *this; + } + + inline operator int32_t() + { + return count; + } + + inline void clear() + { + count = 0; + } + + private: + + int32_t count; +#else + inline debug_count() + { + } + + inline ~debug_count() + { + } + + inline debug_count& operator ++() + { + return *this; + } + + inline debug_count& operator --() + { + return *this; + } + + inline debug_count& operator +=(int32_t /*n*/) + { + return *this; + } + + inline debug_count& operator -=(int32_t /*n*/) + { + return *this; + } + + inline operator int32_t() + { + return 0; + } + + inline void clear() + { + } + +#endif + }; +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/deque.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,2157 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_DEQUE__ +#define __ETL_DEQUE__ + +#include <stddef.h> +#include <stdint.h> +#include <iterator> +#include <algorithm> + +#include "platform.h" +#include "container.h" +#include "alignment.h" +#include "array.h" +#include "memory.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "algorithm.h" +#include "type_traits.h" +#include "parameter_type.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#undef ETL_FILE +#define ETL_FILE "1" + +//***************************************************************************** +///\defgroup deque deque +/// A double ended queue with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception base for deques + ///\ingroup deque + //*************************************************************************** + class deque_exception : public etl::exception + { + public: + + deque_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Deque full exception. + ///\ingroup deque + //*************************************************************************** + class deque_full : public etl::deque_exception + { + public: + + deque_full(string_type file_name_, numeric_type line_number_) + : etl::deque_exception(ETL_ERROR_TEXT("deque:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Deque empty exception. + ///\ingroup deque + //*************************************************************************** + class deque_empty : public etl::deque_exception + { + public: + + deque_empty(string_type file_name_, numeric_type line_number_) + : etl::deque_exception(ETL_ERROR_TEXT("deque:empty", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Deque out of bounds exception. + ///\ingroup deque + //*************************************************************************** + class deque_out_of_bounds : public etl::deque_exception + { + public: + + deque_out_of_bounds(string_type file_name_, numeric_type line_number_) + : etl::deque_exception(ETL_ERROR_TEXT("deque:bounds", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup vector + /// Deque incompatible type exception. + //*************************************************************************** + class deque_incompatible_type : public deque_exception + { + public: + + deque_incompatible_type(string_type file_name_, numeric_type line_number_) + : deque_exception(ETL_ERROR_TEXT("deque:type", ETL_FILE"D"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for all templated deque types. + ///\ingroup deque + //*************************************************************************** + class deque_base + { + public: + + typedef size_t size_type; + + //************************************************************************* + /// Gets the current size of the deque. + ///\return The current size of the deque. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Checks the 'empty' state of the deque. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return (current_size == 0); + } + + //************************************************************************* + /// Checks the 'full' state of the deque. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return current_size == CAPACITY; + } + + //************************************************************************* + /// Returns the maximum possible size of the deque. + ///\return The maximum size of the deque. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + deque_base(size_t max_size_, size_t buffer_size_) + : current_size(0), + CAPACITY(max_size_), + BUFFER_SIZE(buffer_size_) + { + } + + size_type current_size; ///< The current number of elements in the deque. + const size_type CAPACITY; ///< The maximum number of elements in the deque. + const size_type BUFFER_SIZE; ///< The number of elements in the buffer. + etl::debug_count construct_count; ///< Internal debugging. + }; + + //*************************************************************************** + /// The base class for all etl::deque classes. + ///\tparam T The type of values this deque should hold. + ///\ingroup deque + //*************************************************************************** + template <typename T> + class ideque : public etl::deque_base + { + public: + + typedef T value_type; + typedef size_t size_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef typename std::iterator_traits<pointer>::difference_type difference_type; + + protected: + + typedef typename etl::parameter_type<T>::type parameter_t; + + //************************************************************************* + /// Test for an iterator. + //************************************************************************* + template <typename TIterator> + struct is_iterator : public etl::integral_constant<bool, !etl::is_integral<TIterator>::value && !etl::is_floating_point<TIterator>::value> + { + }; + + public: + + //************************************************************************* + /// Iterator + //************************************************************************* + struct iterator : public std::iterator<std::random_access_iterator_tag, T> + { + friend class ideque; + + //*************************************************** + iterator() + : index(0), + p_deque(0), + p_buffer(0) + { + } + + //*************************************************** + iterator(const iterator& other) + : index(other.index), + p_deque(other.p_deque), + p_buffer(other.p_buffer) + { + } + + //*************************************************** + iterator& operator ++() + { + index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1; + + return *this; + } + + //*************************************************** + iterator operator ++(int) + { + iterator previous(*this); + index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1; + + return previous; + } + + //*************************************************** + iterator& operator +=(difference_type offset) + { + if (offset > 0) + { + index += offset; + index = (static_cast<size_t>(index) > p_deque->BUFFER_SIZE - 1) ? index - p_deque->BUFFER_SIZE : index; + } + else if (offset < 0) + { + operator -= (-offset); + } + + return *this; + } + + //*************************************************** + iterator& operator -=(difference_type offset) + { + if (offset > 0) + { + index -= offset; + index = (index < 0) ? index + p_deque->BUFFER_SIZE : index; + } + else if (offset < 0) + { + operator += (-offset); + } + + return *this; + } + + //*************************************************** + iterator& operator --() + { + index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1; + + return *this; + } + + //*************************************************** + iterator operator --(int) + { + iterator previous(*this); + index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1; + + return previous; + } + + //*************************************************** + reference operator *() + { + return p_buffer[index]; + } + + //*************************************************** + const_reference operator *() const + { + return p_buffer[index]; + } + + //*************************************************** + pointer operator ->() + { + return &p_buffer[index]; + } + + //*************************************************** + const_pointer operator ->() const + { + return &p_buffer[index]; + } + + //*************************************************** + bool operator <(const iterator& other) const + { + return ideque::distance(*this, other) > 0; + } + + //*************************************************** + friend iterator operator +(const iterator& lhs, difference_type offset) + { + iterator result(lhs); + result += offset; + return result; + } + + //*************************************************** + friend iterator operator -(const iterator& lhs, difference_type offset) + { + iterator result(lhs); + result -= offset; + return result; + } + + //*************************************************** + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.index == rhs.index; + } + + //*************************************************** + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + //*************************************************** + difference_type get_index() const + { + return index; + } + + //*************************************************** + ideque& get_deque() const + { + return *p_deque; + } + + //*************************************************** + pointer get_buffer() const + { + return p_buffer; + } + + //*************************************************** + void swap(iterator& other) + { + std::swap(index, other.index); + } + + private: + + //*************************************************** + iterator(difference_type index_, ideque& the_deque, pointer p_buffer_) + : index(index_), + p_deque(&the_deque), + p_buffer(p_buffer_) + { + } + + difference_type index; + ideque* p_deque; + pointer p_buffer; + }; + + //************************************************************************* + /// Const Iterator + //************************************************************************* + struct const_iterator : public std::iterator<std::random_access_iterator_tag, const T> + { + friend class ideque; + + //*************************************************** + const_iterator() + : index(0), + p_deque(0), + p_buffer(0) + { + } + + //*************************************************** + const_iterator(const const_iterator& other) + : index(other.index), + p_deque(other.p_deque), + p_buffer(other.p_buffer) + { + } + + //*************************************************** + const_iterator(const typename ideque::iterator& other) + : index(other.index), + p_deque(other.p_deque), + p_buffer(other.p_buffer) + { + } + + //*************************************************** + const_iterator& operator ++() + { + index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1; + + return *this; + } + + //*************************************************** + const_iterator operator ++(int) + { + const_iterator previous(*this); + index = (static_cast<size_t>(index) == p_deque->BUFFER_SIZE - 1) ? 0 : index + 1; + + return previous; + } + + //*************************************************** + const_iterator& operator +=(difference_type offset) + { + if (offset > 0) + { + index += offset; + index = (static_cast<size_t>(index) > p_deque->BUFFER_SIZE - 1) ? index - p_deque->BUFFER_SIZE : index; + } + else if (offset < 0) + { + operator -= (-offset); + } + + return *this; + } + + //*************************************************** + const_iterator& operator -=(difference_type offset) + { + if (offset > 0) + { + index -= offset; + index = (index < 0) ? static_cast<size_t>(index) + p_deque->BUFFER_SIZE : index; + } + else if (offset < 0) + { + operator += (-offset); + } + + return *this; + } + + //*************************************************** + const_iterator& operator --() + { + index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1; + + return *this; + } + + //*************************************************** + const_iterator operator --(int) + { + const_iterator previous(*this); + index = (index == 0) ? p_deque->BUFFER_SIZE - 1 : index - 1; + + return previous; + } + + //*************************************************** + const_reference operator *() const + { + return p_buffer[index]; + } + + //*************************************************** + const_pointer operator ->() const + { + return &p_buffer[index]; + } + + //*************************************************** + bool operator <(const const_iterator& other) const + { + return ideque::distance(*this, other) > 0; + } + + //*************************************************** + friend const_iterator operator +(const const_iterator& lhs, difference_type offset) + { + const_iterator result(lhs); + result += offset; + return result; + } + + //*************************************************** + friend const_iterator operator -(const const_iterator& lhs, difference_type offset) + { + const_iterator result(lhs); + result -= offset; + return result; + } + + //*************************************************** + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.index == rhs.index; + } + + //*************************************************** + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + //*************************************************** + difference_type get_index() const + { + return index; + } + + //*************************************************** + ideque& get_deque() const + { + return *p_deque; + } + + //*************************************************** + pointer get_buffer() const + { + return p_buffer; + } + + //*************************************************** + void swap(const_iterator& other) + { + std::swap(index, other.index); + } + + private: + + //*************************************************** + difference_type distance(difference_type firstIndex, difference_type index_) + { + if (index_ < firstIndex) + { + return p_deque->BUFFER_SIZE + index_ - firstIndex; + } + else + { + return index_ - firstIndex; + } + } + + //*************************************************** + const_iterator(difference_type index_, ideque& the_deque, pointer p_buffer_) + : index(index_), + p_deque(&the_deque), + p_buffer(p_buffer_) + { + } + + difference_type index; + ideque* p_deque; + pointer p_buffer; + }; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + //************************************************************************* + /// Assigns a range to the deque. + //************************************************************************* + template<typename TIterator> + typename etl::enable_if<is_iterator<TIterator>::value, void>::type + assign(TIterator range_begin, TIterator range_end) + { + initialise(); + + while (range_begin != range_end) + { + push_back(*range_begin++); + } + } + + //************************************************************************* + /// Assigns 'n' copies of a value to the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full is 'n' is too large. + ///\param n The number of copies to assign. + ///\param value The value to add.< + //************************************************************************* + void assign(size_type n, const value_type& value) + { + ETL_ASSERT(n <= CAPACITY, ETL_ERROR(deque_full)); + + initialise(); + + _begin.index = 0; + _end.index = 0; + + while (n > 0) + { + create_element_back(value); + --n; + } + } + + //************************************************************************* + /// Gets a reference to the item at the index. + /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the index is out of range. + ///\return A reference to the item at the index. + //************************************************************************* + reference at(size_t index) + { + ETL_ASSERT(index < current_size, ETL_ERROR(deque_out_of_bounds)); + + iterator result(_begin); + result += index; + + return *result; + } + + //************************************************************************* + /// Gets a const reference to the item at the index. + /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the index is out of range. + ///\return A const reference to the item at the index. + //************************************************************************* + const_reference at(size_t index) const + { + ETL_ASSERT(index < current_size, ETL_ERROR(deque_out_of_bounds)); + + iterator result(_begin); + result += index; + + return *result; + } + + //************************************************************************* + /// Gets a reference to the item at the index. + ///\return A reference to the item at the index. + //************************************************************************* + reference operator [](size_t index) + { + iterator result(_begin); + result += index; + + return *result; + } + + //************************************************************************* + /// Gets a const reference to the item at the index. + ///\return A const reference to the item at the index. + //************************************************************************* + const_reference operator [](size_t index) const + { + iterator result(_begin); + result += index; + + return *result; + } + + //************************************************************************* + /// Gets a reference to the item at the front of the deque. + ///\return A reference to the item at the front of the deque. + //************************************************************************* + reference front() + { + return *_begin; + } + + //************************************************************************* + /// Gets a const reference to the item at the front of the deque. + ///\return A const reference to the item at the front of the deque. + //************************************************************************* + const_reference front() const + { + return *_begin; + } + + //************************************************************************* + /// Gets a reference to the item at the back of the deque. + ///\return A reference to the item at the back of the deque. + //************************************************************************* + reference back() + { + return *(_end - 1); + } + + //************************************************************************* + /// Gets a const reference to the item at the back of the deque. + ///\return A const reference to the item at the back of the deque. + //************************************************************************* + const_reference back() const + { + return *(_end - 1); + } + + //************************************************************************* + /// Gets an iterator to the beginning of the deque. + //************************************************************************* + iterator begin() + { + return _begin; + } + + //************************************************************************* + /// Gets a const iterator to the beginning of the deque. + //************************************************************************* + const_iterator begin() const + { + return _begin; + } + + //************************************************************************* + /// Gets a const iterator to the beginning of the deque. + //************************************************************************* + const_iterator cbegin() const + { + return _begin; + } + + //************************************************************************* + /// Gets an iterator to the end of the deque. + //************************************************************************* + iterator end() + { + return iterator(_end); + } + + //************************************************************************* + /// Gets a const iterator to the end of the deque. + //************************************************************************* + const_iterator end() const + { + return iterator(_end); + } + + //************************************************************************* + /// Gets a const iterator to the end of the deque. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(_end); + } + + //************************************************************************* + /// Gets a reverse iterator to the end of the deque. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + //************************************************************************* + /// Gets a const reverse iterator to the end of the deque. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + //************************************************************************* + /// Gets a const reverse iterator to the end of the deque. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + //************************************************************************* + /// Gets a reverse iterator to the beginning of the deque. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + //************************************************************************* + /// Gets a const reverse iterator to the beginning of the deque. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + //************************************************************************* + /// Gets a const reverse iterator to the beginning of the deque. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + //************************************************************************* + /// Clears the deque. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + /// Inserts data into the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. + ///\param insert_position>The insert position. + ///\param value>The value to insert. + //************************************************************************* + iterator insert(const_iterator insert_position, const value_type& value) + { + iterator position(insert_position.index, *this, p_buffer); + + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); + + if (insert_position == begin()) + { + create_element_front(value); + position = _begin; + } + else if (insert_position == end()) + { + create_element_back(value); + position = _end - 1; + } + else + { + // Are we closer to the front? + if (std::distance(_begin, position) < std::distance(position, _end - 1)) + { + // Construct the _begin. + create_element_front(*_begin); + + // Move the values. + std::copy(_begin + 1, position, _begin); + + // Write the new value. + *--position = value; + } + else + { + // Construct the _end. + create_element_back(*(_end - 1)); + + // Move the values. + std::copy_backward(position, _end - 2, _end - 1); + + // Write the new value. + *position = value; + } + } + + return position; + } + + //************************************************************************* + /// Emplaces data into the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. + ///\param insert_position>The insert position. + //************************************************************************* + template <typename T1> + iterator emplace(const_iterator insert_position, const T1& value1) + { + iterator position(insert_position.index, *this, p_buffer); + + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); + + void* p; + + if (insert_position == begin()) + { + --_begin; + p = etl::addressof(*_begin); + ++current_size; + ++construct_count; + position = _begin; + } + else if (insert_position == end()) + { + p = etl::addressof(*_end); + ++_end; + ++current_size; + ++construct_count; + position = _end - 1; + } + else + { + // Are we closer to the front? + if (std::distance(_begin, position) < std::distance(position, _end - 1)) + { + // Construct the _begin. + create_element_front(*_begin); + + // Move the values. + std::copy(_begin + 1, position, _begin); + + // Write the new value. + --position; + (*position).~T(); + p = etl::addressof(*position); + } + else + { + // Construct the _end. + create_element_back(*(_end - 1)); + + // Move the values. + std::copy_backward(position, _end - 2, _end - 1); + + // Write the new value. + (*position).~T(); + p = etl::addressof(*position); + } + } + + ::new (p) T(value1); + + return position; + } + + //************************************************************************* + /// Emplaces data into the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. + ///\param insert_position>The insert position. + //************************************************************************* + template <typename T1, typename T2> + iterator emplace(const_iterator insert_position, const T1& value1, const T2& value2) + { + iterator position(insert_position.index, *this, p_buffer); + + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); + + void* p; + + if (insert_position == begin()) + { + --_begin; + p = etl::addressof(*_begin); + ++current_size; + ++construct_count; + position = _begin; + } + else if (insert_position == end()) + { + p = etl::addressof(*_end); + ++_end; + ++current_size; + ++construct_count; + position = _end - 1; + } + else + { + // Are we closer to the front? + if (std::distance(_begin, position) < std::distance(position, _end - 1)) + { + // Construct the _begin. + create_element_front(*_begin); + + // Move the values. + std::copy(_begin + 1, position, _begin); + + // Write the new value. + --position; + (*position).~T(); + p = etl::addressof(*position); + } + else + { + // Construct the _end. + create_element_back(*(_end - 1)); + + // Move the values. + std::copy_backward(position, _end - 2, _end - 1); + + // Write the new value. + (*position).~T(); + p = etl::addressof(*position); + } + } + + ::new (p) T(value1, value2); + + return position; + } + + //************************************************************************* + /// Emplaces data into the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. + ///\param insert_position>The insert position. + //************************************************************************* + template <typename T1, typename T2, typename T3> + iterator emplace(const_iterator insert_position, const T1& value1, const T2& value2, const T3& value3) + { + iterator position(insert_position.index, *this, p_buffer); + + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); + + void* p; + + if (insert_position == begin()) + { + --_begin; + p = etl::addressof(*_begin); + ++current_size; + ++construct_count; + position = _begin; + } + else if (insert_position == end()) + { + p = etl::addressof(*_end); + ++_end; + ++current_size; + ++construct_count; + position = _end - 1; + } + else + { + // Are we closer to the front? + if (std::distance(_begin, position) < std::distance(position, _end - 1)) + { + // Construct the _begin. + create_element_front(*_begin); + + // Move the values. + std::copy(_begin + 1, position, _begin); + + // Write the new value. + --position; + (*position).~T(); + p = etl::addressof(*position); + } + else + { + // Construct the _end. + create_element_back(*(_end - 1)); + + // Move the values. + std::copy_backward(position, _end - 2, _end - 1); + + // Write the new value. + (*position).~T(); + p = etl::addressof(*position); + } + } + + ::new (p) T(value1, value2, value3); + + return position; + } + + //************************************************************************* + /// Emplaces data into the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. + ///\param insert_position>The insert position. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + iterator emplace(const_iterator insert_position, const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + iterator position(insert_position.index, *this, p_buffer); + + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); + + void* p; + + if (insert_position == begin()) + { + --_begin; + p = etl::addressof(*_begin); + ++current_size; + ++construct_count; + position = _begin; + } + else if (insert_position == end()) + { + p = etl::addressof(*_end); + ++_end; + ++current_size; + ++construct_count; + position = _end - 1; + } + else + { + // Are we closer to the front? + if (std::distance(_begin, position) < std::distance(position, _end - 1)) + { + // Construct the _begin. + create_element_front(*_begin); + + // Move the values. + std::copy(_begin + 1, position, _begin); + + // Write the new value. + --position; + (*position).~T(); + p = etl::addressof(*position); + } + else + { + // Construct the _end. + create_element_back(*(_end - 1)); + + // Move the values. + std::copy_backward(position, _end - 2, _end - 1); + + // Write the new value. + (*position).~T(); + p = etl::addressof(*position); + } + } + + ::new (p) T(value1, value2, value3, value4); + + return position; + } + + //************************************************************************* + /// Inserts 'n' copies of a value into the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. + ///\param insert_position The insert position. + ///\param n The number of values to insert. + ///\param value The value to insert. + //************************************************************************* + iterator insert(const_iterator insert_position, size_type n, const value_type& value) + { + iterator position; + + ETL_ASSERT((current_size + n) <= CAPACITY, ETL_ERROR(deque_full)); + + if (insert_position == begin()) + { + for (size_t i = 0; i < n; ++i) + { + create_element_front(value); + } + + position = _begin; + } + else if (insert_position == end()) + { + for (size_t i = 0; i < n; ++i) + { + create_element_back(value); + } + + position = _end - n; + } + else + { + // Non-const insert iterator. + position = iterator(insert_position.index, *this, p_buffer); + + // Are we closer to the front? + if (distance(_begin, insert_position) <= difference_type(current_size / 2)) + { + size_t n_insert = n; + size_t n_move = std::distance(begin(), position); + size_t n_create_copy = std::min(n_insert, n_move); + size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0; + size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0; + size_t n_copy_old = n_move - n_create_copy; + + // Remember the original start. + iterator from = _begin + n_create_copy - 1; + iterator to; + + // Create new. + for (size_t i = 0; i < n_create_new; ++i) + { + create_element_front(value); + } + + // Create copy. + for (size_t i = 0; i < n_create_copy; ++i) + { + create_element_front(*from--); + } + + // Copy old. + from = position - n_copy_old; + to = _begin + n_create_copy; + etl::copy_n(from, n_copy_old, to); + + // Copy new. + to = position - n_create_copy; + std::fill_n(to, n_copy_new, value); + + position = _begin + n_move; + } + else + { + size_t n_insert = n; + size_t n_move = std::distance(position, end()); + size_t n_create_copy = std::min(n_insert, n_move); + size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0; + size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0; + size_t n_copy_old = n_move - n_create_copy; + + // Create new. + for (size_t i = 0; i < n_create_new; ++i) + { + create_element_back(value); + } + + // Create copy. + const_iterator from = position + n_copy_old; + + for (size_t i = 0; i < n_create_copy; ++i) + { + create_element_back(*from++); + } + + // Copy old. + std::copy_backward(position, position + n_copy_old, position + n_insert + n_copy_old); + + // Copy new. + std::fill_n(position, n_copy_new, value); + } + } + + return position; + } + + //************************************************************************* + /// Inserts a range into the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_empty if the deque is full. + ///\param insert_position>The insert position. + ///\param range_begin The beginning of the range to insert. + ///\param range_end The end of the range to insert. + //************************************************************************* + template<typename TIterator> + typename enable_if<is_iterator<TIterator>::value, iterator>::type + insert(const_iterator insert_position, TIterator range_begin, TIterator range_end) + { + iterator position; + + difference_type n = std::distance(range_begin, range_end); + + ETL_ASSERT((current_size + n) <= CAPACITY, ETL_ERROR(deque_full)); + + if (insert_position == begin()) + { + create_element_front(n, range_begin); + + position = _begin; + } + else if (insert_position == end()) + { + for (difference_type i = 0; i < n; ++i) + { + create_element_back(*range_begin++); + } + + position = _end - n; + } + else + { + // Non-const insert iterator. + position = iterator(insert_position.index, *this, p_buffer); + + // Are we closer to the front? + if (distance(_begin, insert_position) < difference_type(current_size / 2)) + { + size_t n_insert = n; + size_t n_move = std::distance(begin(), position); + size_t n_create_copy = std::min(n_insert, n_move); + size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0; + size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0; + size_t n_copy_old = n_move - n_create_copy; + + // Remember the original start. + iterator from; + iterator to; + + // Create new. + create_element_front(n_create_new, range_begin); + + // Create copy. + create_element_front(n_create_copy, _begin + n_create_new); + + // Copy old. + from = position - n_copy_old; + to = _begin + n_create_copy; + etl::copy_n(from, n_copy_old, to); + + // Copy new. + to = position - n_create_copy; + range_begin += n_create_new; + etl::copy_n(range_begin, n_copy_new, to); + + position = _begin + n_move; + } + else + { + size_t n_insert = n; + size_t n_move = std::distance(position, end()); + size_t n_create_copy = std::min(n_insert, n_move); + size_t n_create_new = (n_insert > n_create_copy) ? n_insert - n_create_copy : 0; + size_t n_copy_new = (n_insert > n_create_new) ? n_insert - n_create_new : 0; + size_t n_copy_old = n_move - n_create_copy; + + // Create new. + TIterator item = range_begin + (n - n_create_new); + for (size_t i = 0; i < n_create_new; ++i) + { + create_element_back(*item++); + } + + // Create copy. + const_iterator from = position + n_copy_old; + + for (size_t i = 0; i < n_create_copy; ++i) + { + create_element_back(*from++); + } + + // Copy old. + std::copy_backward(position, position + n_copy_old, position + n_insert + n_copy_old); + + // Copy new. + item = range_begin; + etl::copy_n(item, n_copy_new, position); + } + } + + return position; + } + + //************************************************************************* + /// Erase an item. + /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the position is out of range. + ///\param erase_position The position to erase. + //************************************************************************* + iterator erase(const_iterator erase_position) + { + iterator position(erase_position.index, *this, p_buffer); + + ETL_ASSERT(distance(position) <= difference_type(current_size), ETL_ERROR(deque_out_of_bounds)); + + if (position == _begin) + { + destroy_element_front(); + position = begin(); + } + else if (position == _end - 1) + { + destroy_element_back(); + position = end(); + } + else + { + // Are we closer to the front? + if (distance(_begin, position) < difference_type(current_size / 2)) + { + std::copy_backward(_begin, position, position + 1); + destroy_element_front(); + ++position; + } + else + { + std::copy(position + 1, _end, position); + destroy_element_back(); + } + } + + return position; + } + + //************************************************************************* + /// erase a range. + /// If asserts or exceptions are enabled, throws an etl::deque_out_of_bounds if the iterators are out of range. + ///\param range_begin The beginning of the range to erase. + ///\param range_end The end of the range to erase. + //************************************************************************* + iterator erase(const_iterator range_begin, const_iterator range_end) + { + iterator position(range_begin.index, *this, p_buffer); + + ETL_ASSERT((distance(range_begin) <= difference_type(current_size)) && (distance(range_end) <= difference_type(current_size)), ETL_ERROR(deque_out_of_bounds)); + + // How many to erase? + size_t length = std::distance(range_begin, range_end); + + // At the beginning? + if (position == _begin) + { + for (size_t i = 0; i < length; ++i) + { + destroy_element_front(); + } + + position = begin(); + } + // At the end? + else if (position == _end - length) + { + for (size_t i = 0; i < length; ++i) + { + destroy_element_back(); + } + + position = end(); + } + else + { + // Copy the smallest number of items. + // Are we closer to the front? + if (distance(_begin, position) < difference_type(current_size / 2)) + { + // Move the items. + std::copy_backward(_begin, position, position + length); + + for (size_t i = 0; i < length; ++i) + { + destroy_element_front(); + } + + position += length; + } + else + // Must be closer to the back. + { + // Move the items. + std::copy(position + length, _end, position); + + for (size_t i = 0; i < length; ++i) + { + destroy_element_back(); + } + } + } + + return position; + } + + //************************************************************************* + /// Adds an item to the back of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + ///\param item The item to push to the deque. + //************************************************************************* + void push_back(parameter_t item) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + create_element_back(item); + } + + //************************************************************************* + /// Adds one to the front of the deque and returns a reference to the new element. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + ///\return A reference to the item to assign to. + //************************************************************************* + reference push_back() + { + reference r = *_end; +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + create_element_back(); + + return r; + } + + //************************************************************************* + /// Emplaces an item to the back of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template <typename T1> + void emplace_back(const T1& value1) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + ::new (&(*_end)) T(value1); + ++_end; + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Emplaces an item to the back of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template <typename T1, typename T2> + void emplace_back(const T1& value1, const T2& value2) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + ::new (&(*_end)) T(value1, value2); + ++_end; + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Emplaces an item to the back of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template <typename T1, typename T2, typename T3> + void emplace_back(const T1& value1, const T2& value2, const T3& value3) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + ::new (&(*_end)) T(value1, value2, value3); + ++_end; + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Emplaces an item to the back of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + void emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + ::new (&(*_end)) T(value1, value2, value3, value4); + ++_end; + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Removes the oldest item from the deque. + //************************************************************************* + void pop_back() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(deque_empty)); +#endif + destroy_element_back(); + } + + //************************************************************************* + /// Adds an item to the front of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + ///\param item The item to push to the deque. + //************************************************************************* + void push_front(parameter_t item) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + create_element_front(item); + } + + //************************************************************************* + /// Adds one to the front of the deque and returns a reference to the new element. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + ///\return A reference to the item to assign to. + //************************************************************************* + reference push_front() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + create_element_front(); + + return *_begin; + } + + //************************************************************************* + /// Emplaces an item to the front of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template <typename T1> + void emplace_front(const T1& value1) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + --_begin; + ::new (&(*_begin)) T(value1); + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Emplaces an item to the front of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template <typename T1, typename T2> + void emplace_front(const T1& value1, const T2& value2) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + --_begin; + ::new (&(*_begin)) T(value1, value2); + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Emplaces an item to the front of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template <typename T1, typename T2, typename T3> + void emplace_front(const T1& value1, const T2& value2, const T3& value3) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + --_begin; + ::new (&(*_begin)) T(value1, value2, value3); + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Emplaces an item to the front of the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + void emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(deque_full)); +#endif + + --_begin; + ::new (&(*_begin)) T(value1, value2, value3, value4); + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Removes the oldest item from the deque. + //************************************************************************* + void pop_front() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(deque_empty)); +#endif + destroy_element_front(); + } + + //************************************************************************* + /// Resizes the deque. + /// If asserts or exceptions are enabled, throws an etl::deque_full is 'new_size' is too large. + ///\param new_size The new size of the deque. + ///\param value The value to assign if the new size is larger. Default = Default constructed value. + //************************************************************************* + void resize(size_t new_size, const value_type& value = value_type()) + { + ETL_ASSERT(new_size <= CAPACITY, ETL_ERROR(deque_out_of_bounds)); + + // Make it smaller? + if (new_size < current_size) + { + while (current_size > new_size) + { + destroy_element_back(); + } + } + // Make it larger? + else if (new_size > current_size) + { + size_t count = new_size - current_size; + + for (size_t i = 0; i < count; ++i) + { + create_element_back(value); + } + } + } + + //************************************************************************* + /// - operator for iterator + //************************************************************************* + friend difference_type operator -(const iterator& lhs, const iterator& rhs) + { + return distance(rhs, lhs); + } + + //************************************************************************* + /// - operator for const_iterator + //************************************************************************* + friend difference_type operator -(const const_iterator& lhs, const const_iterator& rhs) + { + return distance(rhs, lhs); + } + + //************************************************************************* + /// - operator for reverse_iterator + //************************************************************************* + friend difference_type operator -(const reverse_iterator& lhs, const reverse_iterator& rhs) + { + return distance(lhs.base(), rhs.base()); + } + + //************************************************************************* + /// - operator for const_reverse_iterator + //************************************************************************* + friend difference_type operator -(const const_reverse_iterator& lhs, const const_reverse_iterator& rhs) + { + return distance(lhs.base(), rhs.base()); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + ideque& operator =(const ideque& rhs) + { + if (&rhs != this) + { + assign(rhs.begin(), rhs.end()); + } + + return *this; + } + +#ifdef ETL_IDEQUE_REPAIR_ENABLE + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + virtual void repair() = 0; +#endif + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + ideque(pointer p_buffer_, size_t max_size_, size_t buffer_size_) + : deque_base(max_size_, buffer_size_), + p_buffer(p_buffer_) + { + } + + //********************************************************************* + /// Initialise the deque. + //********************************************************************* + void initialise() + { + while (current_size > 0) + { + destroy_element_back(); + } + + _begin = iterator(0, *this, p_buffer); + _end = iterator(0, *this, p_buffer); + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair(pointer p_buffer_) + { + p_buffer = p_buffer_; + + _begin = iterator(_begin.index, *this, p_buffer); + _end = iterator(_end.index, *this, p_buffer); + } + + iterator _begin; ///Iterator to the _begin item in the deque. + iterator _end; ///Iterator to the _end item in the deque. + pointer p_buffer; ///The buffer for the deque. + + private: + + //********************************************************************* + /// Create a new element with a default value at the front. + //********************************************************************* + void create_element_front() + { + --_begin; + ::new (&(*_begin)) T(); + ++current_size; + ++construct_count; + } + + //********************************************************************* + /// Create a new elements from a range at the front. + //********************************************************************* + template <typename TIterator> + void create_element_front(size_t n, TIterator from) + { + if (n == 0) + { + return; + } + + if (!empty()) + { + --_begin; + --n; + } + + if (n > 0) + { + _begin -= n; + } + + iterator item = _begin; + + do + { + ::new (&(*item++)) T(*from); + ++from; + ++current_size; + ++construct_count; + } while (n-- != 0); + } + + //********************************************************************* + /// Create a new element with a default value at the back. + //********************************************************************* + void create_element_back() + { + ::new (&(*_end)) T(); + ++_end; + ++current_size; + ++construct_count; + } + + //********************************************************************* + /// Create a new element with a default value at the front. + //********************************************************************* + void create_element_front(parameter_t value) + { + --_begin; + ::new (&(*_begin)) T(value); + ++current_size; + ++construct_count; + } + + //********************************************************************* + /// Create a new element with a value at the back + //********************************************************************* + void create_element_back(parameter_t value) + { + ::new (&(*_end)) T(value); + ++_end; + ++current_size; + ++construct_count; + } + + //********************************************************************* + /// Destroy an element at the front. + //********************************************************************* + void destroy_element_front() + { + (*_begin).~T(); + --current_size; + --construct_count; + ++_begin; + } + + //********************************************************************* + /// Destroy an element at the back. + //********************************************************************* + void destroy_element_back() + { + --_end; + (*_end).~T(); + --current_size; + --construct_count; + } + + //************************************************************************* + /// Measures the distance between two iterators. + //************************************************************************* + template <typename TIterator1, typename TIterator2> + static difference_type distance(const TIterator1& range_begin, const TIterator2& range_end) + { + difference_type distance1 = distance(range_begin); + difference_type distance2 = distance(range_end); + + return distance2 - distance1; + } + + //************************************************************************* + /// Measures the distance from the _begin iterator to the specified iterator. + //************************************************************************* + template <typename TIterator> + static difference_type distance(const TIterator& other) + { + const difference_type index = other.get_index(); + const difference_type reference_index = other.get_deque()._begin.index; + const size_t buffer_size = other.get_deque().BUFFER_SIZE; + + if (index < reference_index) + { + return buffer_size + index - reference_index; + } + else + { + return index - reference_index; + } + } + + // Disable copy construction. + ideque(const ideque&); + }; + + //*************************************************************************** + /// A fixed capacity double ended queue. + ///\note The deque allocates one more element than the specified maximum size. + ///\tparam T The type of items this deque holds. + ///\tparam MAX_SIZE_ The capacity of the deque + ///\ingroup deque + //*************************************************************************** + template <typename T, const size_t MAX_SIZE_> + class deque : public etl::ideque<T> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + private: + + static const size_t BUFFER_SIZE = MAX_SIZE + 1; + + public: + + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef typename std::iterator_traits<pointer>::difference_type difference_type; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + deque() + : etl::ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + { + etl::ideque<T>::initialise(); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~deque() + { + etl::ideque<T>::initialise(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + deque(const deque& other) + : etl::ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + { + if (this != &other) + { + etl::ideque<T>::assign(other.begin(), other.end()); + } + } + + //************************************************************************* + /// Assigns data to the deque. + //************************************************************************* + template <typename TIterator> + deque(TIterator begin_, TIterator end_) + : etl::ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + { + etl::ideque<T>::assign(begin_, end_); + } + + //************************************************************************* + /// Assigns data to the deque. + //************************************************************************* + explicit deque(size_t n, typename etl::ideque<T>::parameter_t value = value_type()) + : etl::ideque<T>(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + { + etl::ideque<T>::assign(n, value); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + deque& operator =(const deque& rhs) + { + if (&rhs != this) + { + etl::ideque<T>::assign(rhs.begin(), rhs.end()); + } + + return *this; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair() + { +#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED + ETL_ASSERT(std::is_trivially_copyable<T>::value, ETL_ERROR(etl::deque_incompatible_type)); +#endif + + etl::ideque<T>::repair(reinterpret_cast<T*>(&buffer[0])); + } + + private: + + /// The uninitialised buffer of T used in the deque. + typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[BUFFER_SIZE]; + }; +} + +//*************************************************************************** +/// Equal operator. +///\param lhs Reference to the _begin deque. +///\param rhs Reference to the second deque. +///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> +///\ingroup deque +//*************************************************************************** +template <typename T> +bool operator ==(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs) +{ + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +//*************************************************************************** +/// Not equal operator. +///\param lhs Reference to the _begin deque. +///\param rhs Reference to the second deque. +///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> +///\ingroup deque +//*************************************************************************** +template <typename T> +bool operator !=(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs) +{ + return !(lhs == rhs); +} + +//*************************************************************************** +/// Less than operator. +///\param lhs Reference to the _begin deque. +///\param rhs Reference to the second deque. +///\return <b>true</b> if the _begin deque is lexicographically less than the second, otherwise <b>false</b> +///\ingroup deque +//*************************************************************************** +template <typename T> +bool operator <(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); +} + +//*************************************************************************** +/// Less than or equal operator. +///\param lhs Reference to the _begin deque. +///\param rhs Reference to the second deque. +///\return <b>true</b> if the _begin deque is lexicographically less than or equal to the second, otherwise <b>false</b> +///\ingroup deque +//*************************************************************************** +template <typename T> +bool operator <=(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs) +{ + return !(lhs > rhs); +} + +//*************************************************************************** +/// Greater than operator. +///\param lhs Reference to the _begin deque. +///\param rhs Reference to the second deque. +///\return <b>true</b> if the _begin deque is lexicographically greater than the second, otherwise <b>false</b> +///\ingroup deque +//*************************************************************************** +template <typename T> +bool operator >(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs) +{ + return (rhs < lhs); +} + +//*************************************************************************** +/// Greater than or equal operator. +///\param "lhs Reference to the _begin deque. +///\param "rhs Reference to the second deque. +///\return <b>true</b> if the _begin deque is lexicographically greater than or equal to the second, otherwise <b>false</b> +///\ingroup deque +//*************************************************************************** +template <typename T> +bool operator >=(const etl::ideque<T>& lhs, const etl::ideque<T>& rhs) +{ + return !(lhs < rhs); +} + +#undef ETL_FILE + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doxygen.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,56 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +///\defgroup etl Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +///\defgroup containers Containers +///\ingroup etl + +///\defgroup utilities Utilities +/// A set of utility templates. +///\ingroup etl + +///\defgroup maths Maths +/// A set of mathematical templates. +///\ingroup etl + +///\defgroup patterns Patterns +/// A set of templated design patterns. +///\ingroup etl + +///\defgroup crc CRC +/// A set of CRC calculations +///\ingroup maths + +///\ingroup etl +namespace etl {} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ecl_user.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,49 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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 __ECL_USER__ +#define __ECL_USER__ + +#include <stdint.h> + +#if defined(_MSC_VER) + #include <Windows.h> + + #define ECL_TIMER_TIMER_SEMAPHORE uint32_t + #define ECL_TIMER_DISABLE_PROCESSING(x) InterlockedIncrement((volatile long*)&x) + #define ECL_TIMER_ENABLE_PROCESSING(x) InterlockedDecrement((volatile long*)&x) + #define ECL_TIMER_PROCESSING_ENABLED(x) (InterlockedAdd((volatile long*)&x, 0) == 0) +#else + #define ECL_TIMER_TIMER_SEMAPHORE uint32_t + #define ECL_TIMER_DISABLE_PROCESSING(x) __sync_fetch_and_add(&x, 1) + #define ECL_TIMER_ENABLE_PROCESSING(x) __sync_fetch_and_sub(&x, 1) + #define ECL_TIMER_PROCESSING_ENABLED(x) (__sync_fetch_and_add(&x, 0) == 0) +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/endianness.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,93 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_ENDIAN__ +#define __ETL_ENDIAN__ + +#include <stdint.h> + +#include "platform.h" +#include "enum_type.h" + +///\defgroup endian endian +/// Constants & utilities for endianess +///\ingroup utilities + +namespace etl +{ + //*************************************************************************** + /// Constants to denote endianness of operations. + ///\ingroup endian + //*************************************************************************** + struct endian + { + enum enum_type + { + little, + big, + native + }; + + ETL_DECLARE_ENUM_TYPE(endian, int) + ETL_ENUM_TYPE(little, "little") + ETL_ENUM_TYPE(big, "big") + ETL_ENUM_TYPE(native, "native") + ETL_END_ENUM_TYPE + }; + + //*************************************************************************** + /// Checks the endianness of the platform. + ///\ingroup endian + //*************************************************************************** + struct endianness + { + endianness() + : ETL_ENDIAN_TEST(0x0011223344556677) + { + } + + endian operator ()() const + { + return endian(*this); + } + + operator endian() const + { + return (*reinterpret_cast<const uint32_t*>(&ETL_ENDIAN_TEST) == 0x44556677) ? endian::little : endian::big; + } + + private: + + const uint64_t ETL_ENDIAN_TEST; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/enum_type.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,119 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_ENUM_TYPE__ +#define __ETL_ENUM_TYPE__ + +#include "platform.h" + +///\defgroup enum_type enum_type +/// Smart enumerations.<br> +/// A method of declaring enumerations that allow grouping within a structure. +/// Avoids the problem of clashing names that can occur with standard enumerations. +/// One way to think of the code is as a type with built-in constants and an optional conversion to a string.<br><br> +/// <b>Declaring the enumeration.</b> +///\code +/// struct CompassDirection +/// { +/// enum enum_type +/// { +/// North = 0, +/// South = 180, +/// East = 90, +/// West = 270 +/// }; +/// +/// ETL_DECLARE_ENUM_TYPE(CompassDirection, int) +/// ETL_ENUM_TYPE(North, "North") +/// ETL_ENUM_TYPE(South, "South") +/// ETL_ENUM_TYPE(East, "East") +/// ETL_ENUM_TYPE(West, "West") +/// ETL_END_ENUM_TYPE +/// }; +///\endcode +/// <b>Using the enumeration.</b> +///\code +/// CompassDirection direction; // Default construction. +/// +/// direction = CompassDirection::North; // Assignment from an enumeration constant; +/// +/// int value = direction; // Implicit conversion to 'int'. +/// +/// direction = CompassDirection(value); // Explicit conversion from 'int'. +/// +/// direction = CompassDirection(3); // Explicit conversion from an invalid value. This unfortunately cannot be avoided. Caveat emptor! +/// +/// direction = value; // Implicit conversion from 'int'. **** Compilation error **** +/// +/// std::cout << "Direction = " << direction.c_str(); // Prints "Direction = North" +///\endcode +/// If a conversion to a string is not required then the 'ETL_ENUM_TYPE' declaration may be omitted. +/// In that case the c_str() function will return a "?". This will also be the case for any +/// enumeration value that does not have an ETL_ENUM_TYPE entry. +///\ingroup utilities + +//***************************************************************************** +// The declaration of the member functions and the first section of the 'c_str' function. +//***************************************************************************** +#define ETL_DECLARE_ENUM_TYPE(TypeName, ValueType) \ + typedef ValueType value_type; \ + TypeName() {} \ + TypeName(const TypeName &other) : value(other.value) {} \ + TypeName(enum_type value_) : value(value_) {} \ + TypeName& operator=(const TypeName &other) {value = other.value; return *this;} \ + explicit TypeName(value_type value_) : value(static_cast<enum_type>(value_)) {} \ + operator value_type() const {return static_cast<value_type>(value);} \ + value_type get_value() const {return static_cast<value_type>(value);} \ + enum_type get_enum() const {return value;} \ + const char* c_str() const \ + { \ + switch (value) \ + { + +//***************************************************************************** +// A case in the 'c_str' function's switch statement. +//***************************************************************************** +#define ETL_ENUM_TYPE(value, name) \ + case value: \ + return name; \ + +//***************************************************************************** +// The final section of the 'c_str' function and the value declaration. +//***************************************************************************** +#define ETL_END_ENUM_TYPE \ + default: \ + return "?"; \ + } \ + } \ +private: \ + enum_type value; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/error_handler.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,61 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#include "platform.h" +#include "error_handler.h" +#include "nullptr.h" + +//***************************************************************************** +/// The error function callback pointer. +//***************************************************************************** +etl::ifunction<const etl::exception&>* etl::error_handler::p_ifunction = std::nullptr; + +//***************************************************************************** +/// Sets the error callback function. +///\param f A reference to an etl::function object that will handler errors. +//***************************************************************************** +void etl::error_handler::set_callback(ifunction<const etl::exception&>& f) +{ + p_ifunction = &f; +} + +//***************************************************************************** +/// Sends the exception error to the user's handler function. +///\param e The exception error. +//***************************************************************************** +void etl::error_handler::error(const etl::exception& e) +{ + if (p_ifunction != std::nullptr) + { + (*p_ifunction)(e); + } +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/error_handler.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,135 @@ + +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_ERROR_HANDLER__ +#define __ETL_ERROR_HANDLER__ + +///\defgroup error_handler error_handler +/// Error handler for when throwing exceptions is not required. +///\ingroup utilities + +#include <assert.h> + +#include "platform.h" +#include "exception.h" +#include "function.h" + +namespace etl +{ + //*************************************************************************** + /// Error handler for when throwing exceptions is not required. + ///\ingroup error_handler + //*************************************************************************** + class error_handler + { + public: + + //************************************************************************* + /// Callback class for free handler functions. + //************************************************************************* + struct free_function : public etl::function<void, const etl::exception&> + { + free_function(void (*p_function_)(const etl::exception&)) + : etl::function<void, const etl::exception&>(p_function_) + { + } + }; + + //************************************************************************* + /// Callback class for member handler functions. + //************************************************************************* + template <typename TObject> + struct member_function : public etl::function<TObject, const etl::exception&> + { + member_function(TObject& object_, void(TObject::*p_function_)(const etl::exception&)) + : etl::function<TObject, const etl::exception&>(object_, p_function_) + { + } + }; + + static void set_callback(ifunction<const etl::exception&>& f); + static void error(const etl::exception& e); + + private: + + static ifunction<const etl::exception&>* p_ifunction; + }; +} + +//*************************************************************************** +/// Asserts a condition. +/// Versions of the macro that return a constant value of 'true' will allow the compiler to optimise away +/// any 'if' statements that it is contained within. +/// If ETL_NO_CHECKS is defined then no runtime checks are executed at all. +/// If asserts or exceptions are enabled then the error is thrown if the assert fails. The return value is always 'true'. +/// If ETL_LOG_ERRORS is defined then the error is logged if the assert fails. The return value is the value of the boolean test. +/// Otherwise 'assert' is called. The return value is always 'true'. +///\ingroup error_handler +//*************************************************************************** +#if defined(ETL_NO_CHECKS) + #define ETL_ASSERT(b, e) // Does nothing. +#elif defined(ETL_THROW_EXCEPTIONS) + #if defined(ETL_LOG_ERRORS) + #define ETL_ASSERT(b, e) {if (!(b)) {etl::error_handler::error((e)); throw((e);)}} // If the condition fails, calls the error handler then throws an exception. + #else + #define ETL_ASSERT(b, e) {if (!(b)) {throw((e));}} // If the condition fails, throws an exception. + #endif +#else + #if defined(ETL_LOG_ERRORS) + #if defined(NDEBUG) + #define ETL_ASSERT(b, e) {if(!(b)) {etl::error_handler::error((e));}} // If the condition fails, calls the error handler + #else + #define ETL_ASSERT(b, e) {if(!(b)) {etl::error_handler::error((e));} assert((b));} // If the condition fails, calls the error handler then asserts. + #endif + #else + #if defined(NDEBUG) + #define ETL_ASSERT(b, e) // Does nothing. + #else + #define ETL_ASSERT(b, e) assert((b)) // If the condition fails, asserts. + #endif + #endif +#endif + +#if defined(ETL_VERBOSE_ERRORS) + #define ETL_ERROR(e) (e(__FILE__, __LINE__)) // Make an exception with the file name and line number. +#else + #define ETL_ERROR(e) (e("", __LINE__)) // Make an exception with the line number. +#endif + +#if defined(ETL_VERBOSE_ERRORS) + #define ETL_ERROR_TEXT(verbose_text, terse_text) (verbose_text) // Use the verbose text. +#else + #define ETL_ERROR_TEXT(verbose_text, terse_text) (terse_text) // Use the terse text. +#endif + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/etl_profile.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,47 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_PROFILE_H__ +#define __ETL_PROFILE_H__ + +#undef ETL_THROW_EXCEPTIONS +#undef ETL_CPP11_SUPPORTED +#define ETL_VERBOSE_ERRORS +#define ETL_CHECK_PUSH_POP +#undef ETL_ISTRING_REPAIR_ENABLE +#undef ETL_IVECTOR_REPAIR_ENABLE +#undef ETL_IDEQUE_REPAIR_ENABLE +#undef ETL_IN_UNIT_TEST +#undef CAPACITY + +#include "profiles/gcc_generic.h" + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/exception.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,118 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_EXCEPTION__ +#define __ETL_EXCEPTION__ + +#include "platform.h" + +///\defgroup exception exception +/// The base class for all ETL exceptions. +///\ingroup utilities + +namespace etl +{ + //*************************************************************************** + ///\ingroup exception + /// A low overhead exception base class. + //*************************************************************************** + class exception + { + public: + + typedef const char* string_type; + typedef int numeric_type; + +#if defined(ETL_VERBOSE_ERRORS) + //************************************************************************* + /// Constructor. + //************************************************************************* + exception(string_type reason_, string_type file_, numeric_type line_) + : reason_text(reason_), + file_text(file_), + line(line_) + { + } +#else + //************************************************************************* + /// Constructor. + //************************************************************************* + exception(string_type reason_, string_type file_, numeric_type line_) + : reason_text(reason_), + line(line_) + { + (void)file_; + } +#endif + + //*************************************************************************** + /// Gets the reason for the exception. + /// \return const char* to the reason. + //*************************************************************************** + string_type what() const + { + return reason_text; + } + + + //*************************************************************************** + /// Gets the file for the exception. + /// \return const char* to the file. + //*************************************************************************** + string_type file_name() const + { +#if defined(ETL_VERBOSE_ERRORS) + return file_text; +#else + return ""; +#endif + } + + //*************************************************************************** + /// Gets the line for the exception. + /// \return const char* to the line. + //*************************************************************************** + numeric_type line_number() const + { + return line; + } + + private: + + string_type reason_text; ///< The reason for the exception. +#if defined(ETL_VERBOSE_ERRORS) + string_type file_text; ///< The file for the exception. +#endif + numeric_type line; ///< The line for the exception. + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/factorial.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,66 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_FACTORIAL__ +#define __ETL_FACTORIAL__ + +#include <stddef.h> + +#include "platform.h" + +///\defgroup factorial factorial +/// fibonacci<N> : Calculates the Nth factorial value. +///\ingroup maths + +namespace etl +{ + //*************************************************************************** + ///\ingroup fibonacci + /// Defines <b>value</b> as the Nth factorial number. + ///\tparam N The number to find the factorial value of. + //*************************************************************************** + template <size_t N> + struct factorial + { + static const size_t value = N * factorial<N - 1>::value; + }; + + //*************************************************************************** + // Specialisation for N = 0 + //*************************************************************************** + template <> + struct factorial<0> + { + static const size_t value = 1; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/factory.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,469 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_FACTORY__ +#define __ETL_FACTORY__ + +#include <stdint.h> +#include <utility> + +#include "platform.h" +#include "error_handler.h" +#include "exception.h" +#include "largest.h" +#include "type_traits.h" +#include "alignment.h" +#include "static_assert.h" +#include "type_lookup.h" +#include <pool.h> + +#if defined(ETL_COMPILER_GCC) + #warning THIS CLASS IS DEPRECATED!USE VARIANT_POOL INSTEAD. +#elif defined(ETL_COMPILER_MICROSOFT) + #pragma message ("THIS CLASS IS DEPRECATED! USE VARIANT_POOL INSTEAD.") +#endif + +#undef ETL_FILE +#define ETL_FILE "40" + +namespace etl +{ + //*************************************************************************** + class factory_exception : public etl::exception + { + public: + + factory_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + class factory_cannot_create : public etl::factory_exception + { + public: + + factory_cannot_create(string_type file_name_, numeric_type line_number_) + : factory_exception(ETL_ERROR_TEXT("factory:cannot create", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + class factory_did_not_create : public etl::factory_exception + { + public: + + factory_did_not_create(string_type file_name_, numeric_type line_number_) + : factory_exception(ETL_ERROR_TEXT("factory:did not create", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + template <const size_t MAX_SIZE_, + typename T1, + typename T2 = etl::type_id_pair<etl::null_type, -2>, + typename T3 = etl::type_id_pair<etl::null_type, -3>, + typename T4 = etl::type_id_pair<etl::null_type, -4>, + typename T5 = etl::type_id_pair<etl::null_type, -5>, + typename T6 = etl::type_id_pair<etl::null_type, -6>, + typename T7 = etl::type_id_pair<etl::null_type, -7>, + typename T8 = etl::type_id_pair<etl::null_type, -8>, + typename T9 = etl::type_id_pair<etl::null_type, -9>, + typename T10 = etl::type_id_pair<etl::null_type, -10>, + typename T11 = etl::type_id_pair<etl::null_type, -11>, + typename T12 = etl::type_id_pair<etl::null_type, -12>, + typename T13 = etl::type_id_pair<etl::null_type, -13>, + typename T14 = etl::type_id_pair<etl::null_type, -14>, + typename T15 = etl::type_id_pair<etl::null_type, -15>, + typename T16 = etl::type_id_pair<etl::null_type, -16> > + class factory + { + private: + + typedef typename T1::type TT1; + typedef typename T2::type TT2; + typedef typename T3::type TT3; + typedef typename T4::type TT4; + typedef typename T5::type TT5; + typedef typename T6::type TT6; + typedef typename T7::type TT7; + typedef typename T8::type TT8; + typedef typename T9::type TT9; + typedef typename T10::type TT10; + typedef typename T11::type TT11; + typedef typename T12::type TT12; + typedef typename T13::type TT13; + typedef typename T14::type TT14; + typedef typename T15::type TT15; + typedef typename T16::type TT16; + + typedef etl::type_id_lookup<T1, T2, T3, T4, T5, T6, T7, T8, + T9, T10, T11, T12, T13, T14, T15, T16> lookup_t; + + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + factory() + { + } + +#if !ETL_CPP11_SUPPORTED + //************************************************************************* + /// Creates the object. Default constructor. + //************************************************************************* + template <typename T> + T* create_from_type() + { + STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object. One parameter constructor. + //************************************************************************* + template <typename T, typename TP1> + T* create_from_type(const TP1& p1) + { + STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(p1); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object. Two parameter constructor. + //************************************************************************* + template <typename T, typename TP1, typename TP2> + T* create_from_type(const TP1& p1, const TP2& p2) + { + STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(p1, p2); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object. Three parameter constructor. + //************************************************************************* + template <typename T, typename TP1, typename TP2, typename TP3> + T* create_from_type(const TP1& p1, const TP2& p2, const TP3& p3) + { + STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(p1, p2, p3); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object. Four parameter constructor. + //************************************************************************* + template <typename T, typename TP1, typename TP2, typename TP3, typename TP4> + T* create_from_type(const TP1& p1, const TP2& p2, const TP3& p3, const TP4& p4) + { + STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(p1, p2, p3, p4); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object from an index. Default constructor. + //************************************************************************* + template <size_t ID> + typename lookup_t::template type_from_id<ID>::type* create_from_id() + { + typedef typename lookup_t::template type_from_id<ID>::type type; + STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index"); + return create_from_type<type>(); + } + + //************************************************************************* + /// Creates the object from an index. One parameter constructor. + //************************************************************************* + template <size_t ID, typename TP1> + typename lookup_t::template type_from_id<ID>::type* create_from_id(const TP1& p1) + { + typedef typename lookup_t::template type_from_id<ID>::type type; + STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index"); + return create_from_type<type>(p1); + } + + //************************************************************************* + /// Creates the object from an index. Two parameter constructor. + //************************************************************************* + template <size_t ID, typename TP1, typename TP2> + typename lookup_t::template type_from_id<ID>::type* create_from_id(const TP1& p1, const TP2& p2) + { + typedef typename lookup_t::template type_from_id<ID>::type type; + STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index"); + return create_from_type<type>(p1, p2); + } + + //************************************************************************* + /// Creates the object from an index. Three parameter constructor. + //************************************************************************* + template <size_t ID, typename TP1, typename TP2, typename TP3> + typename lookup_t::template type_from_id<ID>::type* create_from_id(const TP1& p1, const TP2& p2, const TP3& p3) + { + typedef typename lookup_t::template type_from_id<ID>::type type; + STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index"); + return create_from_type<type>(p1, p2, p3); + } + + //************************************************************************* + /// Creates the object from an index. Three parameter constructor. + //************************************************************************* + template <size_t ID, typename TP1, typename TP2, typename TP3, typename TP4> + typename lookup_t::template type_from_id<ID>::type* create_from_id(const TP1& p1, const TP2& p2, const TP3& p3, const TP4& p4) + { + typedef typename lookup_t::template type_from_id<ID>::type type; + STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index"); + return create_from_type<type>(p1, p2, p3, p4); + } +#else + //************************************************************************* + /// Creates the object from a type. Variadic parameter constructor. + //************************************************************************* + template <typename T, typename... Args> + T* create_from_type(Args&&... args) + { + STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(std::forward<Args>(args)...); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object from an index. Variadic parameter constructor. + //************************************************************************* + template <size_t ID, typename... Args> + typename lookup_t::template type_from_id<ID>::type* create_from_id(Args&&... args) + { + typedef typename lookup_t::template type_from_id<ID>::type type; + STATIC_ASSERT((!etl::is_same<void, type>::value), "Invalid index"); + return create_from_type<type>(std::forward<Args>(args)...); + } +#endif + + //************************************************************************* + /// Destroys the object. + //************************************************************************* + template <typename T> + bool destroy(const T* const p) + { + STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value || + etl::is_base_of<T, TT1>::value || + etl::is_base_of<T, TT2>::value || + etl::is_base_of<T, TT3>::value || + etl::is_base_of<T, TT4>::value || + etl::is_base_of<T, TT5>::value || + etl::is_base_of<T, TT6>::value || + etl::is_base_of<T, TT7>::value || + etl::is_base_of<T, TT8>::value || + etl::is_base_of<T, TT9>::value || + etl::is_base_of<T, TT10>::value || + etl::is_base_of<T, TT11>::value || + etl::is_base_of<T, TT12>::value || + etl::is_base_of<T, TT13>::value || + etl::is_base_of<T, TT14>::value || + etl::is_base_of<T, TT15>::value || + etl::is_base_of<T, TT16>::value), "Invalid type"); + + p->~T(); + + void* vp = reinterpret_cast<char*>(const_cast<T*>(p)); + + if (pool.is_in_pool(vp)) + { + pool.release(vp); + return true; + } + else + { + ETL_ASSERT(false, ETL_ERROR(factory_did_not_create)); + return false; + } + } + + //************************************************************************* + /// Returns the maximum number of items in the factory. + //************************************************************************* + size_t max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns the number of free items in the factory. + //************************************************************************* + size_t available() const + { + return pool.available(); + } + + //************************************************************************* + /// Returns the number of allocated items in the factory. + //************************************************************************* + size_t size() const + { + return pool.size(); + } + + //************************************************************************* + /// Checks to see if there are no allocated items in the factory. + /// \return <b>true</b> if there are none allocated. + //************************************************************************* + bool empty() const + { + return pool.empty(); + } + + //************************************************************************* + /// Checks to see if there are no free items in the factory. + /// \return <b>true</b> if there are none free. + //************************************************************************* + bool full() const + { + return pool.full(); + } + + private: + + factory(const factory&); + factory& operator =(const factory&); + + // The pool. + etl::generic_pool<etl::largest<TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::size, + etl::largest<TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::alignment, + MAX_SIZE> pool; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fibonacci.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,75 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_FIBONACCI__ +#define __ETL_FIBONACCI__ + +#include <stddef.h> + +#include "platform.h" + +///\defgroup fibonacci fibonacci +/// fibonacci<N> : Calculates the Nth Fibonacci value. +///\ingroup maths + +namespace etl +{ + //*************************************************************************** + ///\ingroup fibonacci + /// Defines <b>value</b> as the Nth Fibbonacci number. + ///\tparam N The number to find the Fibbonacci value of. + //*************************************************************************** + template <size_t N> + struct fibonacci + { + static const size_t value = fibonacci<N - 1>::value + fibonacci<N - 2>::value; + }; + + //*************************************************************************** + // Specialisation for N = 1 + //*************************************************************************** + template <> + struct fibonacci<1> + { + static const size_t value = 1; + }; + + //*************************************************************************** + // Specialisation for N = 0 + //*************************************************************************** + template <> + struct fibonacci<0> + { + static const size_t value = 0; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fixed_iterator.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,271 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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_FIXED_ITERATOR__ +#define __ETL_FIXED_ITERATOR__ + +#include <iterator> + +#include "platform.h" + +///\defgroup iterator Iterator types + +namespace etl +{ + /// A fixed iterator class. + /// This iterator can be given an iterator value, which will not be allowed to be incremented or decremented. + /// This can be useful when using STL algorithms to interact with fixed memory locations such as registers. + ///\ingroup iterator + template <typename TIterator> + class fixed_iterator : std::iterator<typename std::iterator_traits<TIterator>::iterator_category, typename std::iterator_traits<TIterator>::value_type> + { + public: + + //*************************************************************************** + /// Default constructor. + //*************************************************************************** + fixed_iterator() + : it(TIterator()) + { + } + + //*************************************************************************** + /// Construct from iterator. + //*************************************************************************** + fixed_iterator(TIterator it_) + : it(it_) + { + } + + //*************************************************************************** + /// Increment (Does nothing). + //*************************************************************************** + fixed_iterator& operator ++() + { + return *this; + } + + //*************************************************************************** + /// Increment (Does nothing). + //*************************************************************************** + fixed_iterator operator ++(int) + { + return *this; + } + + //*************************************************************************** + /// Decrement (Does nothing). + //*************************************************************************** + fixed_iterator& operator --() + { + return *this; + } + + //*************************************************************************** + /// Decrement (Does nothing). + //*************************************************************************** + fixed_iterator operator --(int) + { + return *this; + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + typename std::iterator_traits<TIterator>::value_type operator *() + { + return *it; + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + const typename std::iterator_traits<TIterator>::value_type operator *() const + { + return *it; + } + + //*************************************************************************** + /// -> operator. + //*************************************************************************** + TIterator operator ->() + { + return it; + } + + //*************************************************************************** + /// -> operator. + //*************************************************************************** + const TIterator operator ->() const + { + return it; + } + + //*************************************************************************** + /// Conversion operator. + //*************************************************************************** + operator TIterator() const + { + return it; + } + + //*************************************************************************** + /// += operator. + //*************************************************************************** + fixed_iterator& operator +=(typename std::iterator_traits<TIterator>::difference_type /*offset*/) + { + return *this; + } + + //*************************************************************************** + /// -= operator. + //*************************************************************************** + fixed_iterator& operator -=(typename std::iterator_traits<TIterator>::difference_type /*offset*/) + { + return *this; + } + + //*************************************************************************** + /// Assignment from iterator. + //*************************************************************************** + fixed_iterator& operator =(TIterator new_it) + { + it = new_it; + return *this; + } + + //*************************************************************************** + /// Assignment from fixed_iterator. + //*************************************************************************** + fixed_iterator& operator =(fixed_iterator other) + { + it = other.it; + return *this; + } + + private: + + TIterator it; ///< The underlying iterator. + }; +} + +//***************************************************************************** +/// + difference operator. +//***************************************************************************** +template <typename TIterator> +etl::fixed_iterator<TIterator>& operator +(etl::fixed_iterator<TIterator>& lhs, + typename std::iterator_traits<TIterator>::difference_type /*rhs*/) +{ + return lhs; +} + +//***************************************************************************** +/// - difference operator. +//***************************************************************************** +template <typename TIterator> +etl::fixed_iterator<TIterator>& operator -(etl::fixed_iterator<TIterator>& lhs, + typename std::iterator_traits<TIterator>::difference_type /*rhs*/) +{ + return lhs; +} + +//***************************************************************************** +/// - fixed_iterator operator. +//***************************************************************************** +template <typename TIterator> +typename std::iterator_traits<TIterator>::difference_type operator -(etl::fixed_iterator<TIterator>& lhs, + etl::fixed_iterator<TIterator>& rhs) +{ + return TIterator(lhs) - TIterator(rhs); +} + +//***************************************************************************** +/// Equality operator. fixed_iterator == fixed_iterator. +//***************************************************************************** +template <typename TIterator> +bool operator ==(const etl::fixed_iterator<TIterator>& lhs, + const etl::fixed_iterator<TIterator>& rhs) +{ + return TIterator(lhs) == TIterator(rhs); +} + +//***************************************************************************** +/// Equality operator. fixed_iterator == iterator. +//***************************************************************************** +template <typename TIterator> +bool operator ==(const etl::fixed_iterator<TIterator>& lhs, + TIterator rhs) +{ + return TIterator(lhs) == rhs; +} + +//***************************************************************************** +/// Equality operator. iterator == fixed_iterator. +//***************************************************************************** +template <typename TIterator> +bool operator ==(TIterator lhs, + const etl::fixed_iterator<TIterator>& rhs) +{ + return lhs == TIterator(rhs); +} + + +//***************************************************************************** +/// Inequality operator. fixed_iterator == fixed_iterator. +//***************************************************************************** +template <typename TIterator> +bool operator !=(const etl::fixed_iterator<TIterator>& lhs, + const etl::fixed_iterator<TIterator>& rhs) +{ + return !(lhs == rhs); +} + +//***************************************************************************** +/// Inequality operator. fixed_iterator == iterator. +//***************************************************************************** +template <typename TIterator> +bool operator !=(const etl::fixed_iterator<TIterator>& lhs, + TIterator rhs) +{ + return !(lhs == rhs); +} + +//***************************************************************************** +/// Inequality operator. iterator == fixed_iterator. +//***************************************************************************** +template <typename TIterator> +bool operator !=(TIterator& lhs, + const etl::fixed_iterator<TIterator>& rhs) +{ + return !(lhs == rhs); +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flat_map.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,690 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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_FLAT_MAP__ +#define __ETL_FLAT_MAP__ + +#include "platform.h" +#include "reference_flat_map.h" +#include "pool.h" + +#undef ETL_FILE +#define ETL_FILE "2" + +//***************************************************************************** +///\defgroup flat_map flat_map +/// A flat_map with the capacity defined at compile time. +/// Has insertion of O(N) and flat_map of O(logN) +/// Duplicate entries are not allowed. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// The base class for specifically sized flat_maps. + /// Can be used as a reference type for all flat_maps containing a specific type. + ///\ingroup flat_map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> > + class iflat_map : private etl::ireference_flat_map<TKey, TMapped, TKeyCompare> + { + private: + + typedef etl::ireference_flat_map<TKey, TMapped, TKeyCompare> refmap_t; + typedef typename refmap_t::lookup_t lookup_t; + typedef etl::ipool storage_t; + + public: + + + typedef std::pair<const TKey, TMapped> value_type; + typedef TKey key_type; + typedef TMapped mapped_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + typedef typename refmap_t::iterator iterator; + typedef typename refmap_t::const_iterator const_iterator; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + protected: + + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + private: + + //********************************************************************* + /// How to compare elements and keys. + //********************************************************************* + class compare + { + public: + + bool operator ()(const value_type& element, key_type key) const + { + return key_compare()(element.first, key); + } + + bool operator ()(key_type key, const value_type& element) const + { + return key_compare()(key, element.first); + } + }; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the flat_map. + ///\return An iterator to the beginning of the flat_map. + //********************************************************************* + iterator begin() + { + return refmap_t::begin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the flat_map. + ///\return A const iterator to the beginning of the flat_map. + //********************************************************************* + const_iterator begin() const + { + return refmap_t::begin(); + } + + //********************************************************************* + /// Returns an iterator to the end of the flat_map. + ///\return An iterator to the end of the flat_map. + //********************************************************************* + iterator end() + { + return refmap_t::end(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the flat_map. + ///\return A const iterator to the end of the flat_map. + //********************************************************************* + const_iterator end() const + { + return refmap_t::end(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the flat_map. + ///\return A const iterator to the beginning of the flat_map. + //********************************************************************* + const_iterator cbegin() const + { + return refmap_t::cbegin(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the flat_map. + ///\return A const iterator to the end of the flat_map. + //********************************************************************* + const_iterator cend() const + { + return refmap_t::cend(); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the flat_map. + ///\return Iterator to the reverse beginning of the flat_map. + //********************************************************************* + reverse_iterator rbegin() + { + return refmap_t::rbegin(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the flat_map. + ///\return Const iterator to the reverse beginning of the flat_map. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return refmap_t::rbegin(); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the flat_map. + ///\return Reverse iterator to the end + 1 of the flat_map. + //********************************************************************* + reverse_iterator rend() + { + return refmap_t::rend(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the flat_map. + ///\return Const reverse iterator to the end + 1 of the flat_map. + //********************************************************************* + const_reverse_iterator rend() const + { + return refmap_t::rend(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the flat_map. + ///\return Const reverse iterator to the reverse beginning of the flat_map. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return refmap_t::crbegin(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the flat_map. + ///\return Const reverse iterator to the end + 1 of the flat_map. + //********************************************************************* + const_reverse_iterator crend() const + { + return refmap_t::crend(); + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& operator [](key_parameter_t key) + { + iterator i_element = lower_bound(key); + + // Doesn't already exist? + if (i_element == end()) + { + value_type* pvalue = storage.allocate<value_type>(); + ::new (pvalue) value_type(); + ++construct_count; + + std::pair<iterator, bool> result = refmap_t::insert_at(i_element, *pvalue); + i_element->second = result.first->second; + } + + return i_element->second; + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& at(key_parameter_t key) + { + return refmap_t::at(key); + } + + //********************************************************************* + /// Returns a const reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A const reference to the value at index 'key' + //********************************************************************* + const mapped_type& at(key_parameter_t key) const + { + return refmap_t::at(key); + } + + //********************************************************************* + /// Assigns values to the flat_map. + /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined, emits flat_map_full if the flat_map does not have enough free space. + /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined, emits flat_map_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_map_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the flat_map. + /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(const_reference value) + { + iterator i_element = lower_bound(value.first); + + std::pair<iterator, bool> result(i_element, false); + + // Doesn't already exist? + if ((i_element == end() || (i_element->first != value.first))) + { + ETL_ASSERT(!refmap_t::full(), ETL_ERROR(flat_map_full)); + + value_type* pvalue = storage.allocate<value_type>(); + ::new (pvalue) value_type(value); + ++construct_count; + result = refmap_t::insert_at(i_element, *pvalue); + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the flat_map. + /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, const_reference value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the flat_map. + /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(key_parameter_t key) + { + iterator i_element = find(key); + + if (i_element == end()) + { + return 0; + } + else + { + i_element->~value_type(); + storage.release(etl::addressof(*i_element)); + refmap_t::erase(i_element); + --construct_count; + return 1; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + i_element->~value_type(); + storage.release(etl::addressof(*i_element)); + refmap_t::erase(i_element); + --construct_count; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + iterator itr = first; + + while (itr != last) + { + itr->~value_type(); + storage.release(etl::addressof(*itr)); + ++itr; + --construct_count; + } + + refmap_t::erase(first, last); + } + + //************************************************************************* + /// Clears the flat_map. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_parameter_t key) + { + return refmap_t::find(key); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + return refmap_t::find(key); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_parameter_t key) const + { + return refmap_t::count(key); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(key_parameter_t key) + { + return refmap_t::lower_bound(key); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(key_parameter_t key) const + { + return refmap_t::lower_bound(key); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(key_parameter_t key) + { + return refmap_t::upper_bound(key); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(key_parameter_t key) const + { + return refmap_t::upper_bound(key); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + return refmap_t::equal_range(key); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + return refmap_t::equal_range(key); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iflat_map& operator = (const iflat_map& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Gets the current size of the flat_map. + ///\return The current size of the flat_map. + //************************************************************************* + size_type size() const + { + return refmap_t::size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the flat_map. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return refmap_t::empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the flat_map. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return refmap_t::full(); + } + + //************************************************************************* + /// Returns the capacity of the flat_map. + ///\return The capacity of the flat_map. + //************************************************************************* + size_type capacity() const + { + return refmap_t::capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the flat_map. + ///\return The maximum size of the flat_map. + //************************************************************************* + size_type max_size() const + { + return refmap_t::max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return refmap_t::available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iflat_map(lookup_t& lookup_, storage_t& storage_) + : refmap_t(lookup_), + storage(storage_) + { + } + + private: + + // Disable copy construction. + iflat_map(const iflat_map&); + + storage_t& storage; + + /// Internal debugging. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first flat_map. + ///\param rhs Reference to the second flat_map. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup flat_map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator ==(const etl::iflat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_map<TKey, TMapped, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first flat_map. + ///\param rhs Reference to the second flat_map. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup flat_map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator !=(const etl::iflat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_map<TKey, TMapped, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// A flat_map implementation that uses a fixed size buffer. + ///\tparam TKey The key type. + ///\tparam TValue The value type. + ///\tparam TCompare The type to compare keys. Default = std::less<TKey> + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup flat_map + //*************************************************************************** + template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> > + class flat_map : public etl::iflat_map<TKey, TValue, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + flat_map() + : etl::iflat_map<TKey, TValue, TCompare>(lookup, storage) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + flat_map(const flat_map& other) + : etl::iflat_map<TKey, TValue, TCompare>(lookup, storage) + { + etl::iflat_map<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + flat_map(TIterator first, TIterator last) + : etl::iflat_map<TKey, TValue, TCompare>(lookup, storage) + { + etl::iflat_map<TKey, TValue, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~flat_map() + { + etl::iflat_map<TKey, TValue, TCompare>::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + flat_map& operator = (const flat_map& rhs) + { + if (&rhs != this) + { + etl::iflat_map<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + typedef typename etl::iflat_map<TKey, TValue, TCompare>::value_type node_t; + + /// The pool of nodes. + etl::pool<node_t, MAX_SIZE> storage; + + /// The vector that stores pointers to the nodes. + etl::vector<node_t*, MAX_SIZE> lookup; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flat_multimap.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,641 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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_FLAT_MULTMAP__ +#define __ETL_FLAT_MULTMAP__ + +#include "platform.h" +#include "reference_flat_multimap.h" +#include "pool.h" + +#undef ETL_FILE +#define ETL_FILE "3" + +//***************************************************************************** +///\defgroup flat_multimap flat_multimap +/// A flat_multimapmap with the capacity defined at compile time. +/// Has insertion of O(N) and find of O(logN) +/// Duplicate entries and not allowed. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// The base class for specifically sized flat_multimaps. + /// Can be used as a reference type for all flat_multimaps containing a specific type. + ///\ingroup flat_multimap + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> > + class iflat_multimap : public etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare> + { + public: + + typedef std::pair<const TKey, TMapped> value_type; + + private: + + typedef etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare> refmap_t; + typedef typename refmap_t::lookup_t lookup_t; + typedef etl::ipool storage_t; + + public: + + typedef TKey key_type; + typedef TMapped mapped_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + typedef typename refmap_t::iterator iterator; + typedef typename refmap_t::const_iterator const_iterator; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + protected: + + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + private: + + //********************************************************************* + /// How to compare elements and keys. + //********************************************************************* + class compare + { + public: + + bool operator ()(const value_type& element, key_type key) const + { + return key_compare()(element.first, key); + } + + bool operator ()(key_type key, const value_type& element) const + { + return key_compare()(key, element.first); + } + }; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the flat_multimap. + ///\return An iterator to the beginning of the flat_multimap. + //********************************************************************* + iterator begin() + { + return refmap_t::begin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the flat_multimap. + ///\return A const iterator to the beginning of the flat_multimap. + //********************************************************************* + const_iterator begin() const + { + return refmap_t::begin(); + } + + //********************************************************************* + /// Returns an iterator to the end of the flat_multimap. + ///\return An iterator to the end of the flat_multimap. + //********************************************************************* + iterator end() + { + return refmap_t::end(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the flat_multimap. + ///\return A const iterator to the end of the flat_multimap. + //********************************************************************* + const_iterator end() const + { + return refmap_t::end(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the flat_multimap. + ///\return A const iterator to the beginning of the flat_multimap. + //********************************************************************* + const_iterator cbegin() const + { + return refmap_t::cbegin(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the flat_multimap. + ///\return A const iterator to the end of the flat_multimap. + //********************************************************************* + const_iterator cend() const + { + return refmap_t::cend(); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the flat_multimap. + ///\return Iterator to the reverse beginning of the flat_multimap. + //********************************************************************* + reverse_iterator rbegin() + { + return refmap_t::rbegin(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the flat_multimap. + ///\return Const iterator to the reverse beginning of the flat_multimap. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return refmap_t::rbegin(); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the flat_multimap. + ///\return Reverse iterator to the end + 1 of the flat_multimap. + //********************************************************************* + reverse_iterator rend() + { + return refmap_t::rend(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the flat_multimap. + ///\return Const reverse iterator to the end + 1 of the flat_multimap. + //********************************************************************* + const_reverse_iterator rend() const + { + refmap_t::rend(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the flat_multimap. + ///\return Const reverse iterator to the reverse beginning of the flat_multimap. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return refmap_t::crbegin(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the flat_multimap. + ///\return Const reverse iterator to the end + 1 of the flat_multimap. + //********************************************************************* + const_reverse_iterator crend() const + { + return refmap_t::crend(); + } + + //********************************************************************* + /// Assigns values to the flat_multimap. + /// If asserts or exceptions are enabled, emits flat_multimap_full if the flat_multimap does not have enough free space. + /// If asserts or exceptions are enabled, emits flat_multimap_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_multimap_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the flat_multimap. + /// If asserts or exceptions are enabled, emits flat_multimap_full if the flat_multimap is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(const value_type& value) + { + ETL_ASSERT(!refmap_t::full(), ETL_ERROR(flat_multimap_full)); + + std::pair<iterator, bool> result(end(), false); + + iterator i_element = lower_bound(value.first); + + value_type* pvalue = storage.allocate<value_type>(); + ::new (pvalue) value_type(value); + ++construct_count; + result = refmap_t::insert_at(i_element, *pvalue); + + return result; + } + + //********************************************************************* + /// Inserts a value to the flast_multi. + /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, const value_type& value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the flat_multimap. + /// If asserts or exceptions are enabled, emits flat_multimap_full if the flat_multimap does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(key_parameter_t key) + { + std::pair<iterator, iterator> range = equal_range(key); + + if (range.first == end()) + { + return 0; + } + else + { + size_t d = std::distance(range.first, range.second); + erase(range.first, range.second); + return d; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + i_element->~value_type(); + storage.release(etl::addressof(*i_element)); + refmap_t::erase(i_element); + --construct_count; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + iterator itr = first; + + while (itr != last) + { + itr->~value_type(); + storage.release(etl::addressof(*itr)); + ++itr; + --construct_count; + } + + refmap_t::erase(first, last); + } + + //************************************************************************* + /// Clears the flat_multimap. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_parameter_t key) + { + return refmap_t::find(key); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + return refmap_t::find(key); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_parameter_t key) const + { + return refmap_t::count(key);; + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(key_parameter_t key) + { + return refmap_t::lower_bound(key); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(key_parameter_t key) const + { + return refmap_t::lower_bound(key); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(key_parameter_t key) + { + return refmap_t::upper_bound(key); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(key_parameter_t key) const + { + return refmap_t::upper_bound(key); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + return refmap_t::equal_range(key); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + return refmap_t::equal_range(key); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iflat_multimap& operator = (const iflat_multimap& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Gets the current size of the flat_multiset. + ///\return The current size of the flat_multiset. + //************************************************************************* + size_type size() const + { + return refmap_t::size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the flat_multiset. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return refmap_t::empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the flat_multiset. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return refmap_t::full(); + } + + //************************************************************************* + /// Returns the capacity of the flat_multiset. + ///\return The capacity of the flat_multiset. + //************************************************************************* + size_type capacity() const + { + return refmap_t::capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the flat_multiset. + ///\return The maximum size of the flat_multiset. + //************************************************************************* + size_type max_size() const + { + return refmap_t::max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return refmap_t::available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iflat_multimap(lookup_t& lookup_, storage_t& storage_) + : refmap_t(lookup_), + storage(storage_) + { + } + + private: + + // Disable copy construction. + iflat_multimap(const iflat_multimap&); + + storage_t& storage; + + /// Internal debugging. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first flat_multimap. + ///\param rhs Reference to the second flat_multimap. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup flat_multimap + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator ==(const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first flat_multimap. + ///\param rhs Reference to the second flat_multimap. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup flat_multimap + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator !=(const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iflat_multimap<TKey, TMapped, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// A flat_multimap implementation that uses a fixed size buffer. + ///\tparam TKey The key type. + ///\tparam TValue The value type. + ///\tparam TCompare The type to compare keys. Default = std::less<TKey> + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup flat_multimap + //*************************************************************************** + template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> > + class flat_multimap : public etl::iflat_multimap<TKey, TValue, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + flat_multimap() + : etl::iflat_multimap<TKey, TValue, TCompare>(lookup, storage) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + flat_multimap(const flat_multimap& other) + : etl::iflat_multimap<TKey, TValue, TCompare>(lookup, storage) + { + etl::iflat_multimap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + flat_multimap(TIterator first, TIterator last) + : etl::iflat_multimap<TKey, TValue, TCompare>(lookup, storage) + { + etl::iflat_multimap<TKey, TValue, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~flat_multimap() + { + etl::iflat_multimap<TKey, TValue, TCompare>::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + flat_multimap& operator = (const flat_multimap& rhs) + { + if (&rhs != this) + { + etl::iflat_multimap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + typedef typename etl::iflat_multimap<TKey, TValue, TCompare>::value_type node_t; + + // The pool of nodes. + etl::pool<node_t, MAX_SIZE> storage; + + // The vector that stores pointers to the nodes. + etl::vector<node_t*, MAX_SIZE> lookup; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flat_multiset.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,618 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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_FLAT_MULTISET__ +#define __ETL_FLAT_MULTISET__ + +#include "platform.h" +#include "reference_flat_multiset.h" +#include "pool.h" + +#undef ETL_FILE +#define ETL_FILE "4" + +//***************************************************************************** +///\defgroup flat_multiset flat_multiset +/// A flat_multiset with the capacity defined at compile time. +/// Has insertion of O(N) and flat_multiset of O(logN) +/// Duplicate entries and not allowed. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// The base class for specifically sized flat_multisets. + /// Can be used as a reference type for all flat_multisets containing a specific type. + ///\ingroup flat_multiset + //*************************************************************************** + template <typename T, typename TKeyCompare = std::less<T> > + class iflat_multiset : private etl::ireference_flat_multiset<T, TKeyCompare> + { + private: + + typedef etl::ireference_flat_multiset<T, TKeyCompare> refset_t; + typedef typename refset_t::lookup_t lookup_t; + typedef etl::ipool storage_t; + + public: + + typedef T key_type; + typedef T value_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + typedef typename refset_t::iterator iterator; + typedef typename refset_t::const_iterator const_iterator; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + protected: + + typedef typename etl::parameter_type<T>::type parameter_t; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the flat_multiset. + ///\return An iterator to the beginning of the flat_multiset. + //********************************************************************* + iterator begin() + { + return refset_t::begin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the flat_multiset. + ///\return A const iterator to the beginning of the flat_multiset. + //********************************************************************* + const_iterator begin() const + { + return refset_t::begin(); + } + + //********************************************************************* + /// Returns an iterator to the end of the flat_multiset. + ///\return An iterator to the end of the flat_multiset. + //********************************************************************* + iterator end() + { + return refset_t::end(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the flat_multiset. + ///\return A const iterator to the end of the flat_multiset. + //********************************************************************* + const_iterator end() const + { + return refset_t::end(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the flat_multiset. + ///\return A const iterator to the beginning of the flat_multiset. + //********************************************************************* + const_iterator cbegin() const + { + return refset_t::cbegin(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the flat_multiset. + ///\return A const iterator to the end of the flat_multiset. + //********************************************************************* + const_iterator cend() const + { + return refset_t::cend(); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the flat_multiset. + ///\return Iterator to the reverse beginning of the flat_multiset. + //********************************************************************* + reverse_iterator rbegin() + { + return refset_t::rbegin(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the flat_multiset. + ///\return Const iterator to the reverse beginning of the flat_multiset. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return refset_t::rbegin(); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the flat_multiset. + ///\return Reverse iterator to the end + 1 of the flat_multiset. + //********************************************************************* + reverse_iterator rend() + { + return refset_t::rend(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the flat_multiset. + ///\return Const reverse iterator to the end + 1 of the flat_multiset. + //********************************************************************* + const_reverse_iterator rend() const + { + return refset_t::rend(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the flat_multiset. + ///\return Const reverse iterator to the reverse beginning of the flat_multiset. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return refset_t::crbegin(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the flat_multiset. + ///\return Const reverse iterator to the end + 1 of the flat_multiset. + //********************************************************************* + const_reverse_iterator crend() const + { + return refset_t::crend(); + } + + //********************************************************************* + /// Assigns values to the flat_multiset. + /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset does not have enough free space. + /// If asserts or exceptions are enabled, emits flat_multiset_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_multiset_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the flat_multiset. + /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(parameter_t value) + { + std::pair<iterator, bool> result(end(), false); + + ETL_ASSERT(!full(), ETL_ERROR(flat_multiset_full)); + + iterator i_element = std::lower_bound(begin(), end(), value, TKeyCompare()); + + ETL_ASSERT(!full(), ETL_ERROR(flat_multiset_full)); + + value_type* pvalue = storage.allocate<value_type>(); + ::new (pvalue) value_type(value); + ++construct_count; + result = refset_t::insert_at(i_element, *pvalue); + + return result; + } + + //********************************************************************* + /// Inserts a value to the flat_multiset. + /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, parameter_t value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the flat_multiset. + /// If asserts or exceptions are enabled, emits flat_multiset_full if the flat_multiset does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(parameter_t key) + { + std::pair<iterator, iterator> range = equal_range(key); + + if (range.first == end()) + { + return 0; + } + else + { + size_t d = std::distance(range.first, range.second); + erase(range.first, range.second); + return d; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + i_element->~value_type(); + storage.release(etl::addressof(*i_element)); + refset_t::erase(i_element); + --construct_count; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + iterator itr = first; + + while (itr != last) + { + itr->~value_type(); + storage.release(etl::addressof(*itr)); + ++itr; + --construct_count; + } + + refset_t::erase(first, last); + } + + //************************************************************************* + /// Clears the flat_multiset. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(parameter_t key) + { + return refset_t::find(key); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(parameter_t key) const + { + return refset_t::find(key); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(parameter_t key) const + { + return refset_t::count(key); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(parameter_t key) + { + return refset_t::lower_bound(key); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(parameter_t key) const + { + return refset_t::lower_bound(key); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(parameter_t key) + { + return refset_t::upper_bound(key); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(parameter_t key) const + { + return refset_t::upper_bound(key); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<iterator, iterator> equal_range(parameter_t key) + { + return refset_t::equal_range(key); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const + { + return refset_t::equal_range(key); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iflat_multiset& operator = (const iflat_multiset& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Gets the current size of the flat_multiset. + ///\return The current size of the flat_multiset. + //************************************************************************* + size_type size() const + { + return refset_t::size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the flat_multiset. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return refset_t::empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the flat_multiset. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return refset_t::full(); + } + + //************************************************************************* + /// Returns the capacity of the flat_multiset. + ///\return The capacity of the flat_multiset. + //************************************************************************* + size_type capacity() const + { + return refset_t::capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the flat_multiset. + ///\return The maximum size of the flat_multiset. + //************************************************************************* + size_type max_size() const + { + return refset_t::max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return refset_t::available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iflat_multiset(lookup_t& lookup_, storage_t& storage_) + : refset_t(lookup_), + storage(storage_) + { + } + + private: + + // Disable copy construction. + iflat_multiset(const iflat_multiset&); + + storage_t& storage; + + /// Internal debugging. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first flat_multiset. + ///\param rhs Reference to the second flat_multiset. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup flat_multiset + //*************************************************************************** + template <typename T, typename TKeyCompare> + bool operator ==(const etl::iflat_multiset<T, TKeyCompare>& lhs, const etl::iflat_multiset<T, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first flat_multiset. + ///\param rhs Reference to the second flat_multiset. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup flat_multiset + //*************************************************************************** + template <typename T, typename TKeyCompare> + bool operator !=(const etl::iflat_multiset<T, TKeyCompare>& lhs, const etl::iflat_multiset<T, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// A flat_multiset implementation that uses a fixed size buffer. + ///\tparam T The value type. + ///\tparam TCompare The type to compare keys. Default = std::less<T> + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup flat_multiset + //*************************************************************************** + template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> > + class flat_multiset : public etl::iflat_multiset<T, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + flat_multiset() + : etl::iflat_multiset<T, TCompare>(lookup, storage) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + flat_multiset(const flat_multiset& other) + : iflat_multiset<T, TCompare>(lookup, storage) + { + etl::iflat_multiset<T, TCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + flat_multiset(TIterator first, TIterator last) + : iflat_multiset<T, TCompare>(lookup, storage) + { + etl::iflat_multiset<T, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~flat_multiset() + { + etl::iflat_multiset<T, TCompare>::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + flat_multiset& operator = (const flat_multiset& rhs) + { + if (&rhs != this) + { + etl::iflat_multiset<T, TCompare>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + typedef typename etl::iflat_multiset<T, TCompare>::value_type node_t; + + // The pool of nodes. + etl::pool<node_t, MAX_SIZE> storage; + + // The vector that stores pointers to the nodes. + etl::vector<node_t*, MAX_SIZE> lookup; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flat_set.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,622 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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_FLAT_SET__ +#define __ETL_FLAT_SET__ + +#include "platform.h" +#include "reference_flat_set.h" +#include "pool.h" + +#undef ETL_FILE +#define ETL_FILE "5" + +//***************************************************************************** +///\defgroup flat_set flat_set +/// A flat_set with the capacity defined at compile time. +/// Has insertion of O(N) and flat_set of O(logN) +/// Duplicate entries and not allowed. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// The base class for specifically sized flat_sets. + /// Can be used as a reference type for all flat_sets containing a specific type. + ///\ingroup flat_set + //*************************************************************************** + template <typename T, typename TKeyCompare = std::less<T> > + class iflat_set : private etl::ireference_flat_set<T, TKeyCompare> + { + private: + + typedef etl::ireference_flat_set<T, TKeyCompare> refset_t; + typedef typename refset_t::lookup_t lookup_t; + typedef etl::ipool storage_t; + + public: + + typedef T key_type; + typedef T value_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + typedef typename refset_t::iterator iterator; + typedef typename refset_t::const_iterator const_iterator; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + protected: + + typedef typename etl::parameter_type<T>::type parameter_t; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the flat_set. + ///\return An iterator to the beginning of the flat_set. + //********************************************************************* + iterator begin() + { + return refset_t::begin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the flat_set. + ///\return A const iterator to the beginning of the flat_set. + //********************************************************************* + const_iterator begin() const + { + return refset_t::begin(); + } + + //********************************************************************* + /// Returns an iterator to the end of the flat_set. + ///\return An iterator to the end of the flat_set. + //********************************************************************* + iterator end() + { + return refset_t::end(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the flat_set. + ///\return A const iterator to the end of the flat_set. + //********************************************************************* + const_iterator end() const + { + return refset_t::end(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the flat_set. + ///\return A const iterator to the beginning of the flat_set. + //********************************************************************* + const_iterator cbegin() const + { + return refset_t::cbegin(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the flat_set. + ///\return A const iterator to the end of the flat_set. + //********************************************************************* + const_iterator cend() const + { + return refset_t::cend(); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the flat_set. + ///\return Iterator to the reverse beginning of the flat_set. + //********************************************************************* + reverse_iterator rbegin() + { + return refset_t::rbegin(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the flat_set. + ///\return Const iterator to the reverse beginning of the flat_set. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return refset_t::rbegin(); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the flat_set. + ///\return Reverse iterator to the end + 1 of the flat_set. + //********************************************************************* + reverse_iterator rend() + { + return refset_t::rend(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the flat_set. + ///\return Const reverse iterator to the end + 1 of the flat_set. + //********************************************************************* + const_reverse_iterator rend() const + { + return refset_t::rend(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the flat_set. + ///\return Const reverse iterator to the reverse beginning of the flat_set. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return refset_t::crbegin(); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the flat_set. + ///\return Const reverse iterator to the end + 1 of the flat_set. + //********************************************************************* + const_reverse_iterator crend() const + { + return refset_t::crend(); + } + + //********************************************************************* + /// Assigns values to the flat_set. + /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set does not have enough free space. + /// If asserts or exceptions are enabled, emits flat_set_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_set_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the flat_set. + /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(parameter_t value) + { + iterator i_element = lower_bound(value); + + std::pair<iterator, bool> result(i_element, false); + + // Doesn't already exist? + if ((i_element == end() || (*i_element != value))) + { + ETL_ASSERT(!refset_t::full(), ETL_ERROR(flat_set_full)); + + value_type* pvalue = storage.allocate<value_type>(); + ::new (pvalue) value_type(value); + ++construct_count; + result = refset_t::insert_at(i_element, *pvalue); + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the flat_set. + /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, parameter_t value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the flat_set. + /// If asserts or exceptions are enabled, emits flat_set_full if the flat_set does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(parameter_t key) + { + iterator i_element = find(key); + + if (i_element == end()) + { + return 0; + } + else + { + i_element->~value_type(); + storage.release(etl::addressof(*i_element)); + refset_t::erase(i_element); + --construct_count; + return 1; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + i_element->~value_type(); + storage.release(etl::addressof(*i_element)); + refset_t::erase(i_element); + --construct_count; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + iterator itr = first; + + while (itr != last) + { + itr->~value_type(); + storage.release(etl::addressof(*itr)); + ++itr; + --construct_count; + } + + refset_t::erase(first, last); + } + + //************************************************************************* + /// Clears the flat_set. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(parameter_t key) + { + return refset_t::find(key); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(parameter_t key) const + { + return refset_t::find(key); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(parameter_t key) const + { + return refset_t::count(key); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(parameter_t key) + { + return refset_t::lower_bound(key); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(parameter_t key) const + { + return refset_t::lower_bound(key); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(parameter_t key) + { + return refset_t::upper_bound(key); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(parameter_t key) const + { + return refset_t::upper_bound(key); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<iterator, iterator> equal_range(parameter_t key) + { + return refset_t::equal_range(key); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const + { + return refset_t::upper_bound(key); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iflat_set& operator = (const iflat_set& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Gets the current size of the flat_set. + ///\return The current size of the flat_set. + //************************************************************************* + size_type size() const + { + return refset_t::size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the flat_set. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return refset_t::empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the flat_set. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return refset_t::full(); + } + + //************************************************************************* + /// Returns the capacity of the flat_set. + ///\return The capacity of the flat_set. + //************************************************************************* + size_type capacity() const + { + return refset_t::capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the flat_set. + ///\return The maximum size of the flat_set. + //************************************************************************* + size_type max_size() const + { + return refset_t::max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return refset_t::available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iflat_set(lookup_t& lookup_, storage_t& storage_) + : refset_t(lookup_), + storage(storage_) + { + } + + private: + + // Disable copy construction. + iflat_set(const iflat_set&); + + storage_t& storage; + + /// Internal debugging. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first flat_set. + ///\param rhs Reference to the second flat_set. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup flat_set + //*************************************************************************** + template <typename T, typename TKeyCompare> + bool operator ==(const etl::iflat_set<T, TKeyCompare>& lhs, const etl::iflat_set<T, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first flat_set. + ///\param rhs Reference to the second flat_set. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup flat_set + //*************************************************************************** + template <typename T, typename TKeyCompare> + bool operator !=(const etl::iflat_set<T, TKeyCompare>& lhs, const etl::iflat_set<T, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// A flat_set implementation that uses a fixed size buffer. + ///\tparam T The value type. + ///\tparam TCompare The type to compare keys. Default = std::less<T> + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup flat_set + //*************************************************************************** + template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> > + class flat_set : public etl::iflat_set<T, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + flat_set() + : etl::iflat_set<T, TCompare>(lookup, storage) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + flat_set(const flat_set& other) + : etl::iflat_set<T, TCompare>(lookup, storage) + { + etl::iflat_set<T, TCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + flat_set(TIterator first, TIterator last) + : etl::iflat_set<T, TCompare>(lookup, storage) + { + etl::iflat_set<T, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~flat_set() + { + etl::iflat_set<T, TCompare>::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + flat_set& operator = (const flat_set& rhs) + { + if (&rhs != this) + { + etl::iflat_set<T, TCompare>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + typedef typename etl::iflat_set<T, TCompare>::value_type node_t; + + // The pool of nodes. + etl::pool<node_t, MAX_SIZE> storage; + + // The vector that stores pointers to the nodes. + etl::vector<node_t*, MAX_SIZE> lookup; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fnv_1.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,286 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_FNV_1__ +#define __ETL_FNV_1__ + +#include <stdint.h> + +#include "platform.h" +#include "static_assert.h" +#include "type_traits.h" +#include "ihash.h" +#include "frame_check_sequence.h" + + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup fnv_1 FNV-1 & FNV-1a 32 & 64 bit hash calculations +///\ingroup maths + +namespace etl +{ + //*************************************************************************** + /// fnv_1 policy. + /// Calculates FNV1. + //*************************************************************************** + struct fnv_1_policy_64 + { + typedef uint64_t value_type; + + inline uint64_t initial() const + { + return OFFSET_BASIS; + } + + inline uint64_t add(uint64_t hash, uint8_t value) const + { + hash *= PRIME; + hash ^= value; + return hash; + } + + inline uint64_t final(uint64_t hash) const + { + return hash; + } + + static const uint64_t OFFSET_BASIS = 0xCBF29CE484222325; + static const uint64_t PRIME = 0x00000100000001b3; + }; + + //*************************************************************************** + /// Calculates the fnv_1_64 hash. + ///\ingroup fnv_1_64 + //*************************************************************************** + class fnv_1_64 : public etl::frame_check_sequence<fnv_1_policy_64> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + fnv_1_64() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + fnv_1_64(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; + + //*************************************************************************** + /// fnv_1a policy. + /// Calculates FNV1A. + //*************************************************************************** + struct fnv_1a_policy_64 + { + typedef uint64_t value_type; + + inline uint64_t initial() const + { + return OFFSET_BASIS; + } + + inline uint64_t add(uint64_t hash, uint8_t value) const + { + hash ^= value; + hash *= PRIME; + return hash; + } + + inline uint64_t final(uint64_t hash) const + { + return hash; + } + + static const uint64_t OFFSET_BASIS = 0xCBF29CE484222325; + static const uint64_t PRIME = 0x00000100000001b3; + }; + + //*************************************************************************** + /// Calculates the fnv_1a_64 hash. + ///\ingroup fnv_1a_64 + //*************************************************************************** + class fnv_1a_64 : public etl::frame_check_sequence<fnv_1a_policy_64> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + fnv_1a_64() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + fnv_1a_64(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; + + //*************************************************************************** + /// fnv_1 policy. + /// Calculates FNV1. + //*************************************************************************** + struct fnv_1_policy_32 + { + typedef uint32_t value_type; + + inline uint32_t initial() const + { + return OFFSET_BASIS; + } + + inline uint32_t add(uint32_t hash, uint8_t value) const + { + hash *= PRIME; + hash ^= value; + return hash; + } + + inline uint32_t final(uint32_t hash) const + { + return hash; + } + + static const uint32_t OFFSET_BASIS = 0x811C9DC5; + static const uint32_t PRIME = 0x01000193; + }; + + //*************************************************************************** + /// Calculates the fnv_1_32 hash. + ///\ingroup fnv_1_32 + //*************************************************************************** + class fnv_1_32 : public etl::frame_check_sequence<fnv_1_policy_32> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + fnv_1_32() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + fnv_1_32(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; + + //*************************************************************************** + /// fnv_1a policy. + /// Calculates FNV1A. + //*************************************************************************** + struct fnv_1a_policy_32 + { + typedef uint32_t value_type; + + inline uint32_t initial() const + { + return OFFSET_BASIS; + } + + inline uint32_t add(uint32_t hash, uint8_t value) const + { + hash ^= value; + hash *= PRIME; + return hash; + } + + inline uint32_t final(uint32_t hash) const + { + return hash; + } + + static const uint32_t OFFSET_BASIS = 0x811C9DC5; + static const uint32_t PRIME = 0x01000193; + }; + + //*************************************************************************** + /// Calculates the fnv_1a_32 hash. + ///\ingroup fnv_1a_32 + //*************************************************************************** + class fnv_1a_32 : public etl::frame_check_sequence<fnv_1a_policy_32> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + fnv_1a_32() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + fnv_1a_32(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/forward_list.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1494 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_FORWARD_LIST__ +#define __ETL_FORWARD_LIST__ + +#include <iterator> +#include <algorithm> +#include <functional> +#include <stddef.h> + +#include "platform.h" +#include "pool.h" +#include "container.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "nullptr.h" +#include "type_traits.h" +#include "parameter_type.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#undef ETL_FILE +#define ETL_FILE "6" + +//***************************************************************************** +///\defgroup forward_list forward_list +/// A linked forward_list with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the forward_list. + ///\ingroup forward_list + //*************************************************************************** + class forward_list_exception : public etl::exception + { + public: + + forward_list_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the forward_list. + ///\ingroup forward_list + //*************************************************************************** + class forward_list_full : public etl::forward_list_exception + { + public: + + forward_list_full(string_type file_name_, numeric_type line_number_) + : etl::forward_list_exception(ETL_ERROR_TEXT("forward_list:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Empty exception for the forward_list. + ///\ingroup forward_list + //*************************************************************************** + class forward_list_empty : public etl::forward_list_exception + { + public: + + forward_list_empty(string_type file_name_, numeric_type line_number_) + : etl::forward_list_exception(ETL_ERROR_TEXT("forward_list:empty", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the forward_list. + ///\ingroup forward_list + //*************************************************************************** + class forward_list_iterator : public etl::forward_list_exception + { + public: + + forward_list_iterator(string_type file_name_, numeric_type line_number_) + : etl::forward_list_exception(ETL_ERROR_TEXT("forward_list:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for all forward_lists. + ///\ingroup forward_list + //*************************************************************************** + class forward_list_base + { + protected: + + //************************************************************************* + /// The node element in the forward_list. + //************************************************************************* + struct node_t + { + node_t() + : next(std::nullptr) + { + } + + node_t* next; + }; + + public: + + typedef size_t size_type; ///< The type used for determining the size of forward_list. + + //************************************************************************* + /// Gets the size of the forward_list. + //************************************************************************* + size_type size() const + { + return p_node_pool->size(); + } + + //************************************************************************* + /// Gets the maximum possible size of the forward_list. + //************************************************************************* + size_type max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Checks to see if the forward_list is empty. + //************************************************************************* + bool empty() const + { + return p_node_pool->empty(); + } + + //************************************************************************* + /// Checks to see if the forward_list is full. + //************************************************************************* + bool full() const + { + return p_node_pool->full(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return p_node_pool->available(); + } + + //************************************************************************* + /// Reverses the forward_list. + //************************************************************************* + void reverse() + { + if (is_trivial_list()) + { + return; + } + + node_t* p_last = &start_node; + node_t* p_current = p_last->next; + node_t* p_next = p_current->next; + + p_current->next = std::nullptr; + + while (p_next != std::nullptr) + { + p_last = p_current; + p_current = p_next; + p_next = p_current->next; + + p_current->next = p_last; + } + + join(&start_node, p_current); + } + + protected: + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + forward_list_base(etl::ipool& node_pool_, size_type max_size_) + : p_node_pool(&node_pool_), + MAX_SIZE(max_size_) + { + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + node_t& get_head() + { + return *start_node.next; + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + const node_t& get_head() const + { + return *start_node.next; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + inline void insert_node_after(node_t& position, node_t& node) + { + // Connect to the forward_list. + join(&node, position.next); + join(&position, &node); + } + + //************************************************************************* + /// Is the forward_list a trivial length? + //************************************************************************* + bool is_trivial_list() const + { + return (size() < 2); + } + + //************************************************************************* + /// Join two nodes. + //************************************************************************* + void join(node_t* left, node_t* right) + { + left->next = right; + } + + node_t start_node; ///< The node that acts as the forward_list start. + etl::ipool* p_node_pool; ///< The pool of data nodes used in the list. + const size_type MAX_SIZE; ///< The maximum size of the forward_list. + etl::debug_count construct_count; ///< Internal debugging. + }; + + //*************************************************************************** + /// A templated base for all etl::forward_list types. + ///\ingroup forward_list + //*************************************************************************** + template <typename T> + class iforward_list : public etl::forward_list_base + { + public: + + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + + protected: + + typedef typename etl::parameter_type<T>::type parameter_t; + + //************************************************************************* + /// The data node element in the forward_list. + //************************************************************************* + struct data_node_t : public node_t + { + explicit data_node_t(parameter_t value_) + : value(value_) + {} + + T value; + }; + + public: + + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator<std::forward_iterator_tag, T> + { + public: + + friend class iforward_list; + + iterator() + : p_node(std::nullptr) + { + } + + iterator(node_t& node) + : p_node(&node) + { + } + + iterator(const iterator& other) + : p_node(other.p_node) + { + } + + iterator& operator ++() + { + p_node = p_node->next; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_node = p_node->next; + return temp; + } + + iterator operator =(const iterator& other) + { + p_node = other.p_node; + return *this; + } + + reference operator *() + { + return iforward_list::data_cast(p_node)->value; + } + + const_reference operator *() const + { + return iforward_list::data_cast(p_node)->value; + } + + pointer operator &() + { + return &(iforward_list::data_cast(p_node)->value); + } + + const_pointer operator &() const + { + return &(iforward_list::data_cast(p_node)->value); + } + + pointer operator ->() + { + return &(iforward_list::data_cast(p_node)->value); + } + + const_pointer operator ->() const + { + return &(iforward_list::data_cast(p_node)->value); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_node == rhs.p_node; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + node_t* p_node; + }; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator<std::forward_iterator_tag, const T> + { + public: + + friend class iforward_list; + + const_iterator() + : p_node(std::nullptr) + { + } + + const_iterator(node_t& node) + : p_node(&node) + { + } + + const_iterator(const node_t& node) + : p_node(&node) + { + } + + const_iterator(const typename iforward_list::iterator& other) + : p_node(other.p_node) + { + } + + const_iterator(const const_iterator& other) + : p_node(other.p_node) + { + } + + const_iterator& operator ++() + { + p_node = p_node->next; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_node = p_node->next; + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return iforward_list::data_cast(p_node)->value; + } + + const_pointer operator &() const + { + return &(iforward_list::data_cast(p_node)->value); + } + + const_pointer operator ->() const + { + return &(iforward_list::data_cast(p_node)->value); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_node == rhs.p_node; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + const node_t* p_node; + }; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //************************************************************************* + /// Gets the beginning of the forward_list. + //************************************************************************* + iterator begin() + { + return iterator(data_cast(get_head())); + } + + //************************************************************************* + /// Gets the beginning of the forward_list. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(data_cast(get_head())); + } + + //************************************************************************* + /// Gets before the beginning of the forward_list. + //************************************************************************* + iterator before_begin() + { + return iterator(static_cast<data_node_t&>(start_node)); + } + + //************************************************************************* + /// Gets before the beginning of the forward_list. + //************************************************************************* + const_iterator before_begin() const + { + return const_iterator(static_cast<const data_node_t&>(start_node)); + } + + //************************************************************************* + /// Gets the beginning of the forward_list. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(get_head()); + } + + //************************************************************************* + /// Gets the end of the forward_list. + //************************************************************************* + iterator end() + { + return iterator(); + } + + //************************************************************************* + /// Gets the end of the forward_list. + //************************************************************************* + const_iterator end() const + { + return const_iterator(); + } + + //************************************************************************* + /// Gets the end of the forward_list. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(); + } + + //************************************************************************* + /// Clears the forward_list. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + /// Gets a reference to the first element. + //************************************************************************* + reference front() + { + return data_cast(get_head()).value; + } + + //************************************************************************* + /// Gets a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return data_cast(get_head()).value; + } + + //************************************************************************* + /// Assigns a range of values to the forward_list. + /// If asserts or exceptions are enabled throws etl::forward_list_full if the forward_list does not have enough free space. + /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined throws forward_list_iterator if the iterators are reversed. + //************************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d >= 0, ETL_ERROR(forward_list_iterator)); +#endif + + initialise(); + + node_t* p_last_node = &start_node; + + // Add all of the elements. + while (first != last) + { + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); + + data_node_t& data_node = allocate_data_node(*first++); + join(p_last_node, &data_node); + data_node.next = std::nullptr; + p_last_node = &data_node; + } + } + + //************************************************************************* + /// Assigns 'n' copies of a value to the forward_list. + //************************************************************************* + void assign(size_t n, parameter_t value) + { + ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(forward_list_full)); + + initialise(); + + node_t* p_last_node = &start_node; + + // Add all of the elements. + while (size() < n) + { + data_node_t& data_node = allocate_data_node(value); + join(p_last_node, &data_node); + data_node.next = std::nullptr; + p_last_node = &data_node; + } + } + + //************************************************************************* + /// Adds a node to the front of the forward_list so a new value can be assigned to front(). + //************************************************************************* + void push_front() + { + push_front(T()); + } + + //************************************************************************* + /// Pushes a value to the front of the forward_list. + //************************************************************************* + void push_front(parameter_t value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); +#endif + + data_node_t& data_node = allocate_data_node(value); + insert_node_after(start_node, data_node); + } + + //************************************************************************* + /// Emplaces a value to the front of the list.. + //************************************************************************* + template <typename T1> + void emplace_front(const T1& value1) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1); + ++construct_count; + insert_node_after(start_node, *p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the front of the list.. + //************************************************************************* + template <typename T1, typename T2> + void emplace_front(const T1& value1, const T2& value2) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2); + ++construct_count; + insert_node_after(start_node, *p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the front of the list.. + //************************************************************************* + template <typename T1, typename T2, typename T3> + void emplace_front(const T1& value1, const T2& value2, const T3& value3) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3); + ++construct_count; + insert_node_after(start_node, *p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the front of the list.. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + void emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3, value4); + ++construct_count; + insert_node_after(start_node, *p_data_node); + } + + //************************************************************************* + /// Removes a value from the front of the forward_list. + //************************************************************************* + void pop_front() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(forward_list_empty)); +#endif + remove_node_after(start_node); + } + + //************************************************************************* + /// Resizes the forward_list. + //************************************************************************* + void resize(size_t n) + { + resize(n, T()); + } + + //************************************************************************* + /// Resizes the forward_list. + /// If asserts or exceptions are enabled, will throw an etl::forward_list_full + /// if <b>n</b> is larger than the maximum size. + //************************************************************************* + void resize(size_t n, T value) + { + ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(forward_list_full)); + + size_t i = 0; + iterator i_node = begin(); + iterator i_last_node; + + // Find where we're currently at. + while ((i < n) && (i_node != end())) + { + ++i; + i_last_node = i_node; + ++i_node; + } + + if (i_node != end()) + { + // Reduce. + erase_after(i_last_node, end()); + } + else if (i_node == end()) + { + // Increase. + while (i < n) + { + i_last_node = insert_after(i_last_node, value); + ++i; + } + } + } + + //************************************************************************* + /// Inserts a value to the forward_list after the specified position. + //************************************************************************* + iterator insert_after(iterator position, parameter_t value) + { + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); + + data_node_t& data_node = allocate_data_node(value); + insert_node_after(*position.p_node, data_node); + + return iterator(data_node); + } + + //************************************************************************* + /// Emplaces a value to the forward_list after the specified position. + //************************************************************************* + template <typename T1> + iterator emplace_after(iterator position, const T1& value1) + { + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); + + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1); + ++construct_count; + insert_node_after(*position.p_node, *p_data_node); + + return iterator(*p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the forward_list after the specified position. + //************************************************************************* + template <typename T1, typename T2> + iterator emplace_after(iterator position, const T1& value1, const T2& value2) + { + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); + + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2); + ++construct_count; + insert_node_after(*position.p_node, *p_data_node); + + return iterator(*p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the forward_list after the specified position. + //************************************************************************* + template <typename T1, typename T2, typename T3> + iterator emplace_after(iterator position, const T1& value1, const T2& value2, const T3& value3) + { + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); + + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3); + ++construct_count; + insert_node_after(*position.p_node, *p_data_node); + + return iterator(*p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the forward_list after the specified position. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + iterator emplace_after(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); + + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3, value4); + ++construct_count; + insert_node_after(*position.p_node, *p_data_node); + + return iterator(*p_data_node); + } + + //************************************************************************* + /// Inserts 'n' copies of a value to the forward_list after the specified position. + //************************************************************************* + void insert_after(iterator position, size_t n, parameter_t value) + { + ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); + + for (size_t i = 0; !full() && (i < n); ++i) + { + // Set up the next free node. + data_node_t& data_node = allocate_data_node(value); + insert_node_after(*position.p_node, data_node); + } + } + + //************************************************************************* + /// Inserts a range of values to the forward_list after the specified position. + //************************************************************************* + template <typename TIterator> + void insert_after(iterator position, TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT((d + size()) <= MAX_SIZE, ETL_ERROR(forward_list_full)); +#endif + + while (first != last) + { + // Set up the next free node. + data_node_t& data_node = allocate_data_node(*first++); + insert_node_after(*position.p_node, data_node); + ++position; + } + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase_after(iterator position) + { + iterator next(position); + if (next != end()) + { + ++next; + if (next != end()) + { + ++next; + remove_node_after(*position.p_node); + } + } + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase_after(iterator first, iterator last) + { + if (first != end() && (first != last)) + { + node_t* p_first = first.p_node; + node_t* p_last = last.p_node; + node_t* p_next = p_first->next; + + // Join the ends. + join(p_first, p_last); + + p_first = p_next; + + // Erase the ones in between. + while (p_first != p_last) + { + p_next = p_first->next; // Remember the next node. + destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the pool object. + p_first = p_next; // Move to the next node. + } + + if (p_next == std::nullptr) + { + return end(); + } + else + { + return iterator(*p_last); + } + } + else + { + return end(); + } + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + void move_after(const_iterator from_before, const_iterator to_before) + { + if (from_before == to_before) // Can't move to after yourself! + { + return; + } + + node_t* p_from_before = const_cast<node_t*>(from_before.p_node); // We're not changing the value, just it's position. + node_t* p_to_before = const_cast<node_t*>(to_before.p_node); // We're not changing the value, just it's position. + + node_t* p_from = p_from_before->next; + + // Disconnect from the list. + join(p_from_before, p_from->next); + + // Attach it to the new position. + join(p_from, p_to_before->next); + join(p_to_before, p_from); + } + + //************************************************************************* + /// Moves a range from one position to another within the list. + /// Moves a range at position 'first_before'/'last' to the position before 'to_before'. + //************************************************************************* + void move_after(const_iterator first_before, const_iterator last, const_iterator to_before) + { + if ((first_before == to_before) || (last == to_before)) + { + return; // Can't more to before yourself! + } + +#if defined(ETL_DEBUG) + // Check that we are not doing an illegal move! + for (const_iterator item = first_before; item != last; ++item) + { + ETL_ASSERT(item != to_before, ETL_ERROR(forward_list_iterator)); + } +#endif + + node_t* p_first_before = const_cast<node_t*>(first_before.p_node); // We're not changing the value, just it's position. + node_t* p_last = const_cast<node_t*>(last.p_node); // We're not changing the value, just it's position. + node_t* p_to_before = const_cast<node_t*>(to_before.p_node); // We're not changing the value, just it's position. + node_t* p_first = p_first_before->next; + node_t* p_final = p_first_before; + + // Find the last node that will be moved. + while (p_final->next != p_last) + { + p_final = p_final->next; + } + + // Disconnect from the list. + join(p_first_before, p_final->next); + + // Attach it to the new position. + join(p_final, p_to_before->next); + join(p_to_before, p_first); + } + + //************************************************************************* + /// Removes all but the first element from every consecutive group of equal + /// elements in the container. + //************************************************************************* + void unique() + { + unique(std::equal_to<T>()); + } + + //************************************************************************* + /// Removes all but the one element from every consecutive group of equal + /// elements in the container. + //************************************************************************* + template <typename TIsEqual> + void unique(TIsEqual isEqual) + { + if (empty()) + { + return; + } + + node_t* last = &get_head(); + node_t* current = last->next; + + while (current != std::nullptr) + { + // Is this value the same as the last? + if (isEqual(data_cast(current)->value, data_cast(last)->value)) + { + remove_node_after(*last); + } + else + { + // Move on one. + last = current; + } + + current = last->next; + } + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + /// Uses 'less-than operator as the predicate. + //************************************************************************* + void sort() + { + sort(std::less<T>()); + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + /// Uses a supplied predicate function or functor. + /// This is not my algorithm. I got it off the web somewhere. + //************************************************************************* + template <typename TCompare> + void sort(TCompare compare) + { + iterator p_left; + iterator p_right; + iterator p_node; + iterator p_head; + iterator p_tail; + int list_size = 1; + int number_of_merges; + int left_size; + int right_size; + + if (is_trivial_list()) + { + return; + } + + while (true) + { + p_left = begin(); + p_head = before_begin(); + p_tail = before_begin(); + + number_of_merges = 0; // Count the number of merges we do in this pass. + + while (p_left != end()) + { + ++number_of_merges; // There exists a merge to be done. + p_right = p_left; + left_size = 0; + + // Step 'list_size' places along from left + for (int i = 0; i < list_size; ++i) + { + ++left_size; + + ++p_right; + + if (p_right == end()) + { + break; + } + } + + // If right hasn't fallen off end, we have two lists to merge. + right_size = list_size; + + // Now we have two lists. Merge them. + while (left_size > 0 || (right_size > 0 && p_right != end())) + { + // Decide whether the next node of merge comes from left or right. + if (left_size == 0) + { + // Left is empty. The node must come from right. + p_node = p_right; + ++p_right; + --right_size; + } + else if (right_size == 0 || p_right == end()) + { + // Right is empty. The node must come from left. + p_node = p_left; + ++p_left; + --left_size; + } + else if (!compare(*p_right, *p_left)) + { + // First node of left is lower or same. The node must come from left. + p_node = p_left; + ++p_left; + --left_size; + } + else + { + // First node of right is lower. The node must come from right. + p_node = p_right; + ++p_right; + --right_size; + } + + // Add the next node to the merged head. + if (p_head == before_begin()) + { + join(p_head.p_node, p_node.p_node); + p_head = p_node; + p_tail = p_node; + } + else + { + join(p_tail.p_node, p_node.p_node); + p_tail = p_node; + } + + p_tail.p_node->next = std::nullptr; + } + + // Now left has stepped `list_size' places along, and right has too. + p_left = p_right; + } + + // If we have done only one merge, we're finished. + if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case + { + return; + } + + // Otherwise repeat, merging lists twice the size + list_size *= 2; + } + } + + //************************************************************************* + // Removes the values specified. + //************************************************************************* + void remove(parameter_t value) + { + iterator i_item = begin(); + iterator i_last_item = before_begin(); + + while (i_item != end()) + { + if (*i_item == value) + { + i_item = erase_after(i_last_item); + } + else + { + ++i_item; + ++i_last_item; + } + } + } + + //************************************************************************* + /// Removes according to a predicate. + //************************************************************************* + template <typename TPredicate> + void remove_if(TPredicate predicate) + { + iterator i_item = begin(); + iterator i_last_item = before_begin(); + + while (i_item != end()) + { + if (predicate(*i_item)) + { + i_item = erase_after(i_last_item); + } + else + { + ++i_item; + ++i_last_item; + } + } + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iforward_list& operator = (const iforward_list& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + iforward_list(etl::ipool& node_pool, size_t max_size_) + : forward_list_base(node_pool, max_size_) + { + } + + //************************************************************************* + /// Initialise the forward_list. + //************************************************************************* + void initialise() + { + if (!empty()) + { + node_t* p_first = start_node.next; + node_t* p_next; + + // Erase the ones in between. + while (p_first != std::nullptr) + { + p_next = p_first->next; // Remember the next node. + destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the pool object. + p_first = p_next; // Move to the next node. + } + } + + start_node.next = std::nullptr; + } + + private: + + //************************************************************************* + /// Downcast a node_t* to a data_node_t* + //************************************************************************* + static data_node_t* data_cast(node_t* p_node) + { + return static_cast<data_node_t*>(p_node); + } + + //************************************************************************* + /// Downcast a node_t& to a data_node_t& + //************************************************************************* + static data_node_t& data_cast(node_t& node) + { + return static_cast<data_node_t&>(node); + } + + //************************************************************************* + /// Downcast a const node_t* to a const data_node_t* + //************************************************************************* + static const data_node_t* data_cast(const node_t* p_node) + { + return static_cast<const data_node_t*>(p_node); + } + + //************************************************************************* + /// Downcast a const node_t& to a const data_node_t& + //************************************************************************* + static const data_node_t& data_cast(const node_t& node) + { + return static_cast<const data_node_t&>(node); + } + + //************************************************************************* + /// Remove a node. + //************************************************************************* + void remove_node_after(node_t& node) + { + // The node to erase. + node_t* p_node = node.next; + + if (p_node != std::nullptr) + { + // Disconnect the node from the forward_list. + join(&node, p_node->next); + + // Destroy the pool object. + destroy_data_node(static_cast<data_node_t&>(*p_node)); + } + } + + //************************************************************************* + /// Allocate a data_node_t. + //************************************************************************* + data_node_t& allocate_data_node(parameter_t value) + { + data_node_t* p_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_node->value)) T(value); + ++construct_count; + + return *p_node; + } + + //************************************************************************* + /// Destroy a data_node_t. + //************************************************************************* + void destroy_data_node(data_node_t& node) + { + node.value.~T(); + p_node_pool->release(&node); + --construct_count; + } + + // Disable copy construction. + iforward_list(const iforward_list&); + }; + + //************************************************************************* + /// A templated forward_list implementation that uses a fixed size pool. + ///\note 'merge' and 'splice_after' and are not supported. + //************************************************************************* + template <typename T, const size_t MAX_SIZE_> + class forward_list : public etl::iforward_list<T> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + public: + + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + forward_list() + : etl::iforward_list<T>(node_pool, MAX_SIZE) + { + etl::iforward_list<T>::initialise(); + } + + //************************************************************************* + /// Construct from size and value. + //************************************************************************* + explicit forward_list(size_t initial_size, typename etl::iforward_list<T>::parameter_t value = T()) + : etl::iforward_list<T>(node_pool, MAX_SIZE) + { + etl::iforward_list<T>::assign(initial_size, value); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + forward_list(const forward_list& other) + : etl::iforward_list<T>(node_pool, MAX_SIZE) + { + etl::iforward_list<T>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Construct from range. + //************************************************************************* + template <typename TIterator> + forward_list(TIterator first, TIterator last) + : etl::iforward_list<T>(node_pool, MAX_SIZE) + { + etl::iforward_list<T>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~forward_list() + { + etl::iforward_list<T>::initialise(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + forward_list& operator = (const forward_list& rhs) + { + if (&rhs != this) + { + etl::iforward_list<T>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of nodes used in the list. + etl::pool<typename etl::iforward_list<T>::data_node_t, MAX_SIZE> node_pool; + }; +} + +//************************************************************************* +/// Equal operator. +///\param lhs Reference to the first forward_list. +///\param rhs Reference to the second forward_list. +///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator ==(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) +{ + return (lhs.size() == rhs.size()) && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +//************************************************************************* +/// Not equal operator. +///\param lhs Reference to the first forward_list. +///\param rhs Reference to the second forward_list. +///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator !=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) +{ + return !(lhs == rhs); +} + +//************************************************************************* +/// Less than operator. +///\param lhs Reference to the first forward_list. +///\param rhs Reference to the second forward_list. +///\return <b>true</b> if the first forward_list is lexicographically less than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator <(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); +} + +//************************************************************************* +/// Greater than operator. +///\param lhs Reference to the first forward_list. +///\param rhs Reference to the second forward_list. +///\return <b>true</b> if the first forward_list is lexicographically greater than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator >(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) +{ + return (rhs < lhs); +} + +//************************************************************************* +/// Less than or equal operator. +///\param lhs Reference to the first forward_list. +///\param rhs Reference to the second forward_list. +///\return <b>true</b> if the first forward_list is lexicographically less than or equal +/// to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator <=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) +{ + return !(lhs > rhs); +} + +//************************************************************************* +/// Greater than or equal operator. +///\param lhs Reference to the first forward_list. +///\param rhs Reference to the second forward_list. +///\return <b>true</b> if the first forward_list is lexicographically greater than or +/// equal to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator >=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) +{ + return !(lhs < rhs); +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frame_check_sequence.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,137 @@ + +///\file + +/****************************************************************************** +The MIT License(MIT) +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com +Copyright(c) 2014 jwellbelove +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_FRAME_CHECK_SEQUENCE__ +#define __ETL_FRAME_CHECK_SEQUENCE__ + +#include <stdint.h> + +#include "platform.h" +#include "static_assert.h" +#include "type_traits.h" +#include "binary.h" + +STATIC_ASSERT(ETL_8BIT_SUPPORT, "This file does not currently support targets with no 8bit type"); + +///\defgroup frame_check_sequence Frame check sequence calculation +///\ingroup maths + +namespace etl +{ + //*************************************************************************** + /// Calculates a frame check sequence according to the specified policy. + ///\tparam TPolicy The type used to enact the policy. + ///\ingroup frame_check_sequence + //*************************************************************************** + template <typename TPolicy> + class frame_check_sequence + { + public: + + typedef TPolicy policy_type; + typedef typename policy_type::value_type value_type; + + STATIC_ASSERT(etl::is_unsigned<value_type>::value, "Signed frame check type not supported"); + + //************************************************************************* + /// Default constructor. + //************************************************************************* + frame_check_sequence() + { + reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + frame_check_sequence(TIterator begin, const TIterator end) + { + STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported"); + + reset(); + add(begin, end); + } + + //************************************************************************* + /// Resets the FCS to the initial state. + //************************************************************************* + void reset() + { + frame_check = policy.initial(); + } + + //************************************************************************* + /// Adds a range. + /// \param begin + /// \param end + //************************************************************************* + template<typename TIterator> + void add(TIterator begin, const TIterator end) + { + STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported"); + + while (begin != end) + { + frame_check = policy.add(frame_check, *begin++); + } + } + + //************************************************************************* + /// \param value The uint8_t to add to the FCS. + //************************************************************************* + void add(uint8_t value_) + { + frame_check = policy.add(frame_check, value_); + } + + //************************************************************************* + /// Gets the FCS value. + //************************************************************************* + value_type value() + { + return policy.final(frame_check); + } + + //************************************************************************* + /// Conversion operator to value_type. + //************************************************************************* + operator value_type () + { + return policy.final(frame_check); + } + + private: + + value_type frame_check; + policy_type policy; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fsm.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1216 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -ofsm.h -DHandlers=<n> fsm_generator.h +// Where <n> is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 events... +// python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_FSM__ +#define __ETL_FSM__ + +#include <stdint.h> + +#include "platform.h" +#include "array.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "user_type.h" +#include "message_router.h" +#include "integral_limits.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "34" + +#ifdef ETL_COMPILER_MICROSOFT +#undef max +#endif + +namespace etl +{ + class fsm; + + /// Allow alternative type for state id. +#if !defined(ETL_FSM_STATE_ID_TYPE) + typedef uint_least8_t fsm_state_id_t; +#else + typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t; +#endif + + // For internal FSM use. + typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t; + + //*************************************************************************** + /// Base exception class for FSM. + //*************************************************************************** + class fsm_exception : public etl::exception + { + public: + + fsm_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception for null state pointer. + //*************************************************************************** + class fsm_null_state_exception : public etl::fsm_exception + { + public: + + fsm_null_state_exception(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception for invalid state id. + //*************************************************************************** + class fsm_state_id_exception : public etl::fsm_exception + { + public: + + fsm_state_id_exception(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception for incompatible state list. + //*************************************************************************** + class fsm_state_list_exception : public etl::fsm_exception + { + public: + + fsm_state_list_exception(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Interface class for FSM states. + //*************************************************************************** + class ifsm_state + { + public: + + /// Allows ifsm_state functions to be private. + friend class etl::fsm; + + //******************************************* + /// Gets the id for this state. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + return state_id; + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ifsm_state(etl::fsm_state_id_t state_id_) + : state_id(state_id_), + p_context(std::nullptr) + { + } + + //******************************************* + inline etl::fsm& get_fsm_context() const + { + return *p_context; + } + + private: + + virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0; + + virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing. + virtual void on_exit_state() {} // By default, do nothing. + + //******************************************* + void set_fsm_context(etl::fsm& context) + { + p_context = &context; + } + + // The state id. + const etl::fsm_state_id_t state_id; + + // A pointer to the FSM context. + etl::fsm* p_context; + + // Disabled. + ifsm_state(const ifsm_state&); + ifsm_state& operator =(const ifsm_state&); + }; + + //*************************************************************************** + /// The FSM class. + //*************************************************************************** + class fsm : public etl::imessage_router + { + public: + + //******************************************* + /// Constructor. + //******************************************* + fsm(etl::message_router_id_t id) + : imessage_router(id), + p_state(std::nullptr) + { + } + + //******************************************* + /// Set the states for the FSM + //******************************************* + template <typename TSize> + void set_states(etl::ifsm_state** p_states, TSize size) + { + state_list = p_states; + number_of_states = etl::fsm_state_id_t(size); + + ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception)); + + for (etl::fsm_state_id_t i = 0; i < size; ++i) + { + ETL_ASSERT((state_list[i] != std::nullptr), ETL_ERROR(etl::fsm_null_state_exception)); + state_list[i]->set_fsm_context(*this); + } + } + + //******************************************* + /// Starts the FSM. + /// Can only be called once. + /// Subsequent calls will do nothing. + //******************************************* + void start() + { + // Can only be started once. + if (p_state == std::nullptr) + { + p_state = state_list[0]; + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + + p_state->on_enter_state(); + } + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, message); + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t next_state_id = p_state->process_event(source, message); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + etl::ifsm_state* p_next_state = state_list[next_state_id]; + + // Have we changed state? + if (p_next_state != p_state) + { + do + { + p_state->on_exit_state(); + p_state = p_next_state; + + next_state_id = p_state->on_enter_state(); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + p_next_state = state_list[next_state_id]; + + } while (p_next_state != p_state); // Have we changed state again? + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this FSM accept the message id? + /// Yes, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t id) const + { + return true; + } + + //******************************************* + /// Gets the current state id. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return p_state->get_state_id(); + } + + //******************************************* + /// Gets a reference to the current state interface. + //******************************************* + ifsm_state& get_state() + { + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Gets a const reference to the current state interface. + //******************************************* + const ifsm_state& get_state() const + { + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Checks if the FSM has been started. + //******************************************* + bool is_started() const + { + return p_state != std::nullptr; + } + + //******************************************* + /// Reset the FSM to pre-started state. + //******************************************* + void reset() + { + p_state = std::nullptr; + } + + private: + + etl::ifsm_state* p_state; ///< A pointer to the current state. + etl::ifsm_state** state_list; ///< The list of added states. + etl::fsm_state_id_t number_of_states; ///< The number of states. + }; + + //*************************************************************************** + // The definition for all 16 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void> + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break; + case T14::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T14&>(message)); break; + case T15::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T15&>(message)); break; + case T16::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T16&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 15 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13, typename T14, typename T15> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break; + case T14::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T14&>(message)); break; + case T15::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T15&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 14 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13, typename T14> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break; + case T14::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T14&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 13 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + case T13::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T13&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 12 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + case T12::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T12&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 11 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + case T11::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T11&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 10 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + case T10::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T10&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 9 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + case T9::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T9&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 8 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + case T8::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T8&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 7 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + case T7::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T7&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 6 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + case T6::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T6&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 5 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4, + typename T5> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + case T5::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T5&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 4 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3, typename T4> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + case T4::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T4&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 3 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2, typename T3> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + case T3::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T3&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 2 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1, typename T2> + class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + case T2::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T2&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 1 message type. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, + typename T1> + class fsm_state<TContext, TDerived, STATE_ID_, T1, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + protected: + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.message_id; + + switch (event_id) + { + case T1::ID: new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T1&>(message)); break; + default: new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_> + class fsm_state<TContext, TDerived, STATE_ID_, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast<TContext&>(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + return static_cast<TDerived*>(this)->on_event_unknown(source, message); + } + }; +} + +#undef ETL_FILE + +#ifdef ETL_COMPILER_MICROSOFT +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fsm_generator.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,539 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -ofsm.h -DHandlers=<n> fsm_generator.h +// Where <n> is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 events... +// python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_FSM__ +#define __ETL_FSM__ + +#include <stdint.h> + +#include "platform.h" +#include "array.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "user_type.h" +#include "message_router.h" +#include "integral_limits.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "34" + +#ifdef ETL_COMPILER_MICROSOFT +#undef max +#endif + +namespace etl +{ + class fsm; + + /// Allow alternative type for state id. +#if !defined(ETL_FSM_STATE_ID_TYPE) + typedef uint_least8_t fsm_state_id_t; +#else + typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t; +#endif + + // For internal FSM use. + typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t; + + //*************************************************************************** + /// Base exception class for FSM. + //*************************************************************************** + class fsm_exception : public etl::exception + { + public: + + fsm_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception for null state pointer. + //*************************************************************************** + class fsm_null_state_exception : public etl::fsm_exception + { + public: + + fsm_null_state_exception(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception for invalid state id. + //*************************************************************************** + class fsm_state_id_exception : public etl::fsm_exception + { + public: + + fsm_state_id_exception(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception for incompatible state list. + //*************************************************************************** + class fsm_state_list_exception : public etl::fsm_exception + { + public: + + fsm_state_list_exception(string_type file_name_, numeric_type line_number_) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Interface class for FSM states. + //*************************************************************************** + class ifsm_state + { + public: + + /// Allows ifsm_state functions to be private. + friend class etl::fsm; + + //******************************************* + /// Gets the id for this state. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + return state_id; + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ifsm_state(etl::fsm_state_id_t state_id_) + : state_id(state_id_), + p_context(std::nullptr) + { + } + + //******************************************* + inline etl::fsm& get_fsm_context() const + { + return *p_context; + } + + private: + + virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0; + + virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing. + virtual void on_exit_state() {} // By default, do nothing. + + //******************************************* + void set_fsm_context(etl::fsm& context) + { + p_context = &context; + } + + // The state id. + const etl::fsm_state_id_t state_id; + + // A pointer to the FSM context. + etl::fsm* p_context; + + // Disabled. + ifsm_state(const ifsm_state&); + ifsm_state& operator =(const ifsm_state&); + }; + + //*************************************************************************** + /// The FSM class. + //*************************************************************************** + class fsm : public etl::imessage_router + { + public: + + //******************************************* + /// Constructor. + //******************************************* + fsm(etl::message_router_id_t id) + : imessage_router(id), + p_state(std::nullptr) + { + } + + //******************************************* + /// Set the states for the FSM + //******************************************* + template <typename TSize> + void set_states(etl::ifsm_state** p_states, TSize size) + { + state_list = p_states; + number_of_states = etl::fsm_state_id_t(size); + + ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception)); + + for (etl::fsm_state_id_t i = 0; i < size; ++i) + { + ETL_ASSERT((state_list[i] != std::nullptr), ETL_ERROR(etl::fsm_null_state_exception)); + state_list[i]->set_fsm_context(*this); + } + } + + //******************************************* + /// Starts the FSM. + /// Can only be called once. + /// Subsequent calls will do nothing. + //******************************************* + void start() + { + // Can only be started once. + if (p_state == std::nullptr) + { + p_state = state_list[0]; + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + + p_state->on_enter_state(); + } + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, message); + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t next_state_id = p_state->process_event(source, message); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + etl::ifsm_state* p_next_state = state_list[next_state_id]; + + // Have we changed state? + if (p_next_state != p_state) + { + do + { + p_state->on_exit_state(); + p_state = p_next_state; + + next_state_id = p_state->on_enter_state(); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + p_next_state = state_list[next_state_id]; + + } while (p_next_state != p_state); // Have we changed state again? + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this FSM accept the message id? + /// Yes, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t id) const + { + return true; + } + + //******************************************* + /// Gets the current state id. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return p_state->get_state_id(); + } + + //******************************************* + /// Gets a reference to the current state interface. + //******************************************* + ifsm_state& get_state() + { + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Gets a const reference to the current state interface. + //******************************************* + const ifsm_state& get_state() const + { + ETL_ASSERT(p_state != std::nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Checks if the FSM has been started. + //******************************************* + bool is_started() const + { + return p_state != std::nullptr; + } + + //******************************************* + /// Reset the FSM to pre-started state. + //******************************************* + void reset() + { + p_state = std::nullptr; + } + + private: + + etl::ifsm_state* p_state; ///< A pointer to the current state. + etl::ifsm_state** state_list; ///< The list of added states. + etl::fsm_state_id_t number_of_states; ///< The number of states. + }; + + /*[[[cog + import cog + ################################################ + # The first definition for all of the events. + ################################################ + cog.outl("//***************************************************************************") + cog.outl("// The definition for all %s message types." % Handlers) + cog.outl("//***************************************************************************") + cog.outl("template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, ") + cog.out(" ") + for n in range(1, int(Handlers)): + cog.out("typename T%s = void, " % n) + if n % 4 == 0: + cog.outl("") + cog.out(" ") + cog.outl("typename T%s = void>" % Handlers) + cog.outl("class fsm_state : public ifsm_state") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" STATE_ID = STATE_ID_") + cog.outl(" };") + cog.outl("") + cog.outl(" fsm_state()") + cog.outl(" : ifsm_state(STATE_ID)") + cog.outl(" {") + cog.outl(" }") + cog.outl("") + cog.outl("protected:") + cog.outl("") + cog.outl(" inline TContext& get_fsm_context() const") + cog.outl(" {") + cog.outl(" return static_cast<TContext&>(ifsm_state::get_fsm_context());") + cog.outl(" }") + cog.outl("") + cog.outl("private:") + cog.outl("") + cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") + cog.outl(" {") + cog.outl(" etl::fsm_state_id_t new_state_id;") + cog.outl(" etl::message_id_t event_id = message.message_id;") + cog.outl("") + cog.outl(" switch (event_id)") + cog.outl(" {") + for n in range(1, int(Handlers) + 1): + cog.out(" case T%d::ID:" % n) + cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T%d&>(message));" % n) + cog.outl(" break;") + cog.out(" default:") + cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message);") + cog.outl(" break;") + cog.outl(" }") + cog.outl("") + cog.outl(" return new_state_id;") + cog.outl(" }") + cog.outl("};") + + #################################### + # All of the other specialisations. + #################################### + for n in range(int(Handlers) - 1, 0, -1): + cog.outl("") + cog.outl("//***************************************************************************") + if n == 1: + cog.outl("// Specialisation for %d message type." % n) + else: + cog.outl("// Specialisation for %d message types." % n) + cog.outl("//***************************************************************************") + cog.outl("template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_, ") + cog.out(" ") + for t in range(1, n): + cog.out("typename T%d, " % t) + if t % 4 == 0: + cog.outl("") + cog.out(" ") + cog.outl("typename T%d>" % n) + cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ") + for t in range(1, n + 1): + cog.out("T%d, " % t) + if t % 16 == 0: + cog.outl("") + cog.out(" ") + for t in range(n + 1, int(Handlers)): + cog.out("void, ") + if t % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("void> : public ifsm_state") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" STATE_ID = STATE_ID_") + cog.outl(" };") + cog.outl("") + cog.outl(" fsm_state()") + cog.outl(" : ifsm_state(STATE_ID)") + cog.outl(" {") + cog.outl(" }") + cog.outl("") + cog.outl("protected:") + cog.outl("") + cog.outl(" inline TContext& get_fsm_context() const") + cog.outl(" {") + cog.outl(" return static_cast<TContext&>(ifsm_state::get_fsm_context());") + cog.outl(" }") + cog.outl("") + cog.outl("private:") + cog.outl("") + cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") + cog.outl(" {") + cog.outl(" etl::fsm_state_id_t new_state_id;") + cog.outl(" etl::message_id_t event_id = message.message_id;") + cog.outl("") + cog.outl(" switch (event_id)") + cog.outl(" {") + for n in range(1, n + 1): + cog.out(" case T%d::ID:" % n) + cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event(source, static_cast<const T%d&>(message));" % n) + cog.outl(" break;") + cog.out(" default:") + cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event_unknown(source, message);") + cog.outl(" break;") + cog.outl(" }") + cog.outl("") + cog.outl(" return new_state_id;") + cog.outl(" }") + cog.outl("};") + #################################### + # Specialisation for zero messages. + #################################### + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for 0 message types.") + cog.outl("//***************************************************************************") + cog.outl("template <typename TContext, typename TDerived, const etl::fsm_state_id_t STATE_ID_>") + cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ") + for t in range(1, int(Handlers)): + cog.out("void, ") + if t % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("void> : public ifsm_state") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" STATE_ID = STATE_ID_") + cog.outl(" };") + cog.outl("") + cog.outl(" fsm_state()") + cog.outl(" : ifsm_state(STATE_ID)") + cog.outl(" {") + cog.outl(" }") + cog.outl("") + cog.outl(" inline TContext& get_fsm_context() const") + cog.outl(" {") + cog.outl(" return static_cast<TContext&>(ifsm_state::get_fsm_context());") + cog.outl(" }") + cog.outl("private:") + cog.outl("") + cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") + cog.outl(" {") + cog.outl(" return static_cast<TDerived*>(this)->on_event_unknown(source, message);") + cog.outl(" }") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#undef ETL_FILE + +#ifdef ETL_COMPILER_MICROSOFT +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/function.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,417 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_FUNCTION__ +#define __ETL_FUNCTION__ + +#include "platform.h" + +//***************************************************************************** +///\defgroup function function +/// A set of wrapper templates to allow a member or static function to be called +/// without the caller having to know the specific details of the callee. +/// This template class may be used to link interrupt vectors to specific member +/// functions of a handler class. +///\ingroup utilities +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + ///\ingroup function + /// The base interface template for function template specialisations. + ///\tparam TParameter The parameter type expected by the function. + //*************************************************************************** + template <typename TParameter> + class ifunction + { + public: + + typedef TParameter parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// The function operator that will be overridden. + //************************************************************************* + virtual void operator ()(TParameter) = 0; + }; + + //*************************************************************************** + ///\ingroup function + /// The base interface template for functions taking <b>void</b> parameters. + //*************************************************************************** + template <> + class ifunction<void> + { + public: + + typedef void parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// The function operator that will be overridden. + //************************************************************************* + virtual void operator ()() = 0; + }; + + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes an object type and parameter type. + ///\tparam TObject The object type that contains the member function. + ///\tparam TParameter The parameter type accepted by the member function. + //*************************************************************************** + template <typename TObject, typename TParameter> + class function : public ifunction<TParameter> + { + public: + + typedef TObject object_type; ///< The type of object. + typedef TParameter parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// Constructor. + ///\param object Reference to the object + ///\param p_function Pointer to the member function + //************************************************************************* + function(TObject& object_, void(TObject::* p_function_)(TParameter)) + : p_object(&object_), + p_function(p_function_) + { + } + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()(TParameter data) + { + // Call the object's member function with the data. + (p_object->*p_function)(data); + } + + private: + + TObject* p_object; ///< Pointer to the object that contains the function. + void (TObject::* p_function)(TParameter); ///< Pointer to the member function. + }; + + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes a parameter type. + ///\tparam TObject The object type that contains the member function. + //*************************************************************************** + template <typename TObject> + class function<TObject, void> : public ifunction<void> + { + public: + + //************************************************************************* + /// Constructor. + ///\param object Reference to the object + ///\param p_function Pointer to the member function + //************************************************************************* + function(TObject& object_, void(TObject::* p_function_)(void)) + : p_object(&object_), + p_function(p_function_) + { + } + + //************************************************************************* + /// The function operator that calls the destination function. + //************************************************************************* + virtual void operator ()() + { + // Call the object's member function. + (p_object->*p_function)(); + } + + private: + + TObject* p_object; ///< Pointer to the object that contains the function. + void (TObject::* p_function)(); ///< Pointer to the member function. + }; + + //*************************************************************************** + ///\ingroup function + /// Specialisation for static or global functions that takes a parameter. + //*************************************************************************** + template <typename TParameter> + class function<void, TParameter> : public ifunction<TParameter> + { + public: + + //************************************************************************* + /// Constructor. + ///\param p_function Pointer to the function + //************************************************************************* + function(void(*p_function_)(TParameter)) + : p_function(p_function_) + { + } + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()(TParameter data) + { + // Call the function with the data. + (*p_function)(data); + } + + private: + + void (*p_function)(TParameter); ///< Pointer to the function. + }; + + //*************************************************************************** + ///\ingroup function + /// Specialisation static functions taking void parameter. + //*************************************************************************** + template <> + class function<void, void> : public ifunction<void> + { + public: + + //************************************************************************* + /// Constructor. + ///\param p_function Pointer to the function. + //************************************************************************* + function(void(*p_function_)(void)) + : p_function(p_function_) + { + } + + //************************************************************************* + /// The function operator that calls the destination function. + //************************************************************************* + virtual void operator ()() + { + // Call the function. + (*p_function)(); + } + + private: + + void (*p_function)(); ///< Pointer to the function. + }; + + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes an object type and parameter type. + ///\tparam TObject The object type that contains the member function. + ///\tparam TParameter The parameter type accepted by the member function. + //*************************************************************************** + template <typename TObject, typename TParameter, void (TObject::*Function)(TParameter)> + class function_mp : public ifunction<TParameter> + { + public: + + typedef TObject object_type; ///< The type of object. + typedef TParameter parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// Constructor. + ///\param object Reference to the object + //************************************************************************* + function_mp(TObject& object_) + : p_object(&object_) + { + } + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()(TParameter data) + { + // Call the object's member function with the data. + (p_object->*Function)(data); + } + + private: + + TObject* p_object; ///< Pointer to the object that contains the function. + }; + + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes an object type and parameter type. + ///\tparam TObject The object type that contains the member function. + ///\tparam TParameter The parameter type accepted by the member function. + //*************************************************************************** + template <typename TObject, void (TObject::*Function)(void)> + class function_mv : public ifunction<void> + { + public: + + typedef TObject object_type; ///< The type of object. + typedef void parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// Constructor. + ///\param object Reference to the object + //************************************************************************* + function_mv(TObject& object_) + : p_object(&object_) + { + } + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()() + { + // Call the object's member function. + (p_object->*Function)(); + } + + private: + + TObject* p_object; ///< Pointer to the object that contains the function. + }; + + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes an object type and parameter type. + ///\tparam TObject The object type that contains the member function. + ///\tparam TParameter The parameter type accepted by the member function. + //*************************************************************************** + template <typename TObject, typename TParameter, TObject& Instance, void (TObject::*Function)(TParameter)> + class function_imp : public ifunction<TParameter> + { + public: + + typedef TObject object_type; ///< The type of object. + typedef TParameter parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()(TParameter data) + { + // Call the object's member function with the data. + (Instance.*Function)(data); + } + }; + + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes an object type and parameter type. + ///\tparam TObject The object type that contains the member function. + ///\tparam TParameter The parameter type accepted by the member function. + //*************************************************************************** + template <typename TObject, TObject& Instance, void (TObject::*Function)(void)> + class function_imv : public ifunction<void> + { + public: + + typedef TObject object_type; ///< The type of object. + typedef void parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()() + { + // Call the object's member function. + (Instance.*Function)(); + } + }; + + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes a parameter type. + ///\tparam TParameter The parameter type accepted by the member function. + //*************************************************************************** + template <typename TParameter, void (*Function)(TParameter)> + class function_fp : public ifunction<TParameter> + { + public: + + typedef TParameter parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// Constructor. + ///\param object Reference to the object + ///\param p_function Pointer to the member function + //************************************************************************* + function_fp() + { + } + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()(TParameter data) + { + // Call the object's member function with the data. + (*Function)(data); + } + }; + + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes a parameter type. + ///\tparam TParameter The parameter type accepted by the member function. + //*************************************************************************** + template <void(*Function)(void)> + class function_fv : public ifunction<void> + { + public: + + typedef void parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// Constructor. + ///\param object Reference to the object + ///\param p_function Pointer to the member function + //************************************************************************* + function_fv() + { + } + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()() + { + // Call the function. + (*Function)(); + } + }; + +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/functional.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,112 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_FUNCTIONAL__ +#define __ETL_FUNCTIONAL__ + +#include "platform.h" + +///\defgroup functional functional +///\ingroup utilities + +///\defgroup reference_wrapper reference_wrapper +///\ingroup functional + +namespace etl +{ + //*************************************************************************** + /// A definition of reference_wrapper for those that don't have C++ 0x11 support. + ///\ingroup reference + //*************************************************************************** + template <typename T> + class reference_wrapper + { + public: + + typedef T type; + + explicit reference_wrapper(T& t_) + : t(&t_) + { + } + + operator T& () const + { + return *t; + } + + reference_wrapper<T>& operator = (T value) + { + *t = value; + return *this; + } + + T& get() const + { + return *t; + } + + private: + + T* t; + }; + + //*************************************************************************** + template <typename T> + reference_wrapper<T> ref(T& t) + { + return reference_wrapper<T>(t); + } + + //*************************************************************************** + template <typename T> + reference_wrapper<T> ref(reference_wrapper<T> t) + { + return reference_wrapper<T>(t.get()); + } + + //*************************************************************************** + template <typename T> + reference_wrapper<const T> cref(const T& t) + { + return reference_wrapper<const T>(t); + } + + //*************************************************************************** + template <typename T> + reference_wrapper<const T> cref(reference_wrapper<T> t) + { + return reference_wrapper<const T>(t.get()); + } +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hash.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,438 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_HASH__ +#define __ETL_HASH__ + +#include <stdint.h> +#include <stdlib.h> + +#include "platform.h" + +// The default hash calculation. +#include "fnv_1.h" +#include "type_traits.h" +#include "static_assert.h" + +///\defgroup hash Standard hash calculations +///\ingroup maths + +namespace etl +{ + namespace __private_hash__ + { + //************************************************************************* + /// Hash to use when size_t is 16 bits. + /// T is always expected to be size_t. + //************************************************************************* + template <typename T> + typename enable_if<sizeof(T) == sizeof(uint16_t), size_t>::type + generic_hash(const uint8_t* begin, const uint8_t* end) + { + uint32_t h = fnv_1a_32(begin, end); + + return static_cast<size_t>(h ^ (h >> 16)); + } + + //************************************************************************* + /// Hash to use when size_t is 32 bits. + /// T is always expected to be size_t. + //************************************************************************* + template <typename T> + typename enable_if<sizeof(T) == sizeof(uint32_t), size_t>::type + generic_hash(const uint8_t* begin, const uint8_t* end) + { + return fnv_1a_32(begin, end); + } + + //************************************************************************* + /// Hash to use when size_t is 64 bits. + /// T is always expected to be size_t. + //************************************************************************* + template <typename T> + typename enable_if<sizeof(T) == sizeof(uint64_t), size_t>::type + generic_hash(const uint8_t* begin, const uint8_t* end) + { + return fnv_1a_64(begin, end); + } + } + + //*************************************************************************** + /// Generic declaration for etl::hash + ///\ingroup hash + //*************************************************************************** + template <typename T> struct hash; + + //*************************************************************************** + /// Specialisation for bool. + ///\ingroup hash + //*************************************************************************** + template <> + struct hash <bool> + { + STATIC_ASSERT(sizeof(size_t) >= sizeof(bool), "size_t smaller than type"); + + size_t operator ()(bool v) const + { + return static_cast<size_t>(v); + } + }; + + //*************************************************************************** + /// Specialisation for char. + ///\ingroup hash + //*************************************************************************** + template <> + struct hash<char> + { + STATIC_ASSERT(sizeof(size_t) >= sizeof(char), "size_t smaller than type"); + + size_t operator ()(char v) const + { + return static_cast<size_t>(v); + } + }; + + //*************************************************************************** + /// Specialisation for signed char. + ///\ingroup hash + //*************************************************************************** + template<> struct + hash<signed char> + { + STATIC_ASSERT(sizeof(size_t) >= sizeof(signed char), "size_t smaller than type"); + + size_t operator ()(signed char v) const + { + return static_cast<size_t>(v); + } + }; + + //*************************************************************************** + /// Specialisation for unsigned char. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<unsigned char> + { + STATIC_ASSERT(sizeof(size_t) >= sizeof(unsigned char), "size_t smaller than type"); + + size_t operator ()(unsigned char v) const + { + return static_cast<size_t>(v); + } + }; + + //*************************************************************************** + /// Specialisation for wchar_t. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<wchar_t> + { + STATIC_ASSERT(sizeof(size_t) >= sizeof(wchar_t), "size_t smaller than type"); + + size_t operator ()(wchar_t v) const + { + return static_cast<size_t>(v); + } + }; + + //*************************************************************************** + /// Specialisation for short. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<short> + { + STATIC_ASSERT(sizeof(size_t) >= sizeof(short), "size_t smaller than type"); + + size_t operator ()(short v) const + { + return static_cast<size_t>(v); + } + }; + + //*************************************************************************** + /// Specialisation for unsigned short. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<unsigned short> + { + STATIC_ASSERT(sizeof(size_t) >= sizeof(unsigned short), "size_t smaller than type"); + + size_t operator ()(unsigned short v) const + { + return static_cast<size_t>(v); + } + }; + + //*************************************************************************** + /// Specialisation for int. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<int> + { + STATIC_ASSERT(sizeof(size_t) >= sizeof(int), "size_t smaller than type"); + + size_t operator ()(int v) const + { + return static_cast<size_t>(v); + } + }; + + //*************************************************************************** + /// Specialisation for unsigned int. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<unsigned int> + { + STATIC_ASSERT(sizeof(size_t) >= sizeof(unsigned int), "size_t smaller than type"); + + size_t operator ()(unsigned int v) const + { + return static_cast<size_t>(v); + } + }; + + //*************************************************************************** + /// Specialisation for long. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<long> + { + size_t operator ()(long v) const + { + // If it's the same size as a size_t. + if (sizeof(size_t) >= sizeof(v)) + { + return static_cast<size_t>(v); + } + else + { + uint8_t* p = reinterpret_cast<uint8_t*>(&v); + return __private_hash__::generic_hash<size_t>(p, p + sizeof(v)); + } + } + }; + + //*************************************************************************** + /// Specialisation for long long. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<long long> + { + size_t operator ()(long long v) const + { + // If it's the same size as a size_t. + if (sizeof(size_t) >= sizeof(v)) + { + return static_cast<size_t>(v); + } + else + { + uint8_t* p = reinterpret_cast<uint8_t*>(&v); + return __private_hash__::generic_hash<size_t>(p, p + sizeof(v)); + } + } + }; + + //*************************************************************************** + /// Specialisation for unsigned long. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<unsigned long> + { + size_t operator ()(unsigned long v) const + { + // If it's the same size as a size_t. + if (sizeof(size_t) >= sizeof(v)) + { + return static_cast<size_t>(v); + } + else + { + uint8_t* p = reinterpret_cast<uint8_t*>(&v); + return __private_hash__::generic_hash<size_t>(p, p + sizeof(v)); + } + } + }; + + //*************************************************************************** + /// Specialisation for unsigned long long. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<unsigned long long> + { + size_t operator ()(unsigned long long v) const + { + // If it's the same size as a size_t. + if (sizeof(size_t) >= sizeof(v)) + { + return static_cast<size_t>(v); + } + else + { + uint8_t* p = reinterpret_cast<uint8_t*>(&v); + return __private_hash__::generic_hash<size_t>(p, p + sizeof(v)); + } + } + }; + + //*************************************************************************** + /// Specialisation for float. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<float> + { + size_t operator ()(float v) const + { + // If it's the same size as a size_t. + if (sizeof(size_t) == sizeof(v)) + { + union + { + size_t s; + float v; + } u; + + u.v = v; + + return u.s; + } + else + { + uint8_t* p = reinterpret_cast<uint8_t*>(&v); + return __private_hash__::generic_hash<size_t>(p, p + sizeof(v)); + } + } + }; + + //*************************************************************************** + /// Specialisation for double. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<double> + { + size_t operator ()(double v) const + { + // If it's the same size as a size_t. + if (sizeof(size_t) == sizeof(v)) + { + union + { + size_t s; + double v; + } u; + + u.v = v; + + return u.s; + } + else + { + uint8_t* p = reinterpret_cast<uint8_t*>(&v); + return __private_hash__::generic_hash<size_t>(p, p + sizeof(v)); + } + } + }; + + //*************************************************************************** + /// Specialisation for long double. + ///\ingroup hash + //*************************************************************************** + template<> + struct hash<long double> + { + size_t operator ()(long double v) const + { + // If it's the same size as a size_t. + if (sizeof(size_t) == sizeof(v)) + { + union + { + size_t s; + long double v; + } u; + + u.v = v; + + return u.s; + } + else + { + uint8_t* p = reinterpret_cast<uint8_t*>(&v); + return __private_hash__::generic_hash<size_t>(p, p + sizeof(v)); + } + } + }; + + //*************************************************************************** + /// Specialisation for pointers. + ///\ingroup hash + //*************************************************************************** + template <typename T> + struct hash<T*> + { + size_t operator ()(const T* v) const + { + // If it's the same size as a size_t. + if (sizeof(size_t) == sizeof(T*)) + { + union + { + size_t s; + const T* v; + } u; + + u.v = v; + + return u.s; + } + else + { + uint8_t* p = reinterpret_cast<uint8_t*>(&v); + return __private_hash__::generic_hash<size_t>(p, p + sizeof(v)); + } + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/icache.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,117 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove, rlindeman + +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. +******************************************************************************/ + +//***************************************************************************** +#error This header is in development. Do not use. +//***************************************************************************** + +#ifndef __ETL_ICACHE__ +#define __ETL_ICACHE__ + +#include "platform.h" +#include "function.h" +#include "nullptr.h" + +#include <utility> + +namespace etl +{ + ///************************************************************************** + /// The base class for all caches. + ///************************************************************************** + template <typename TKey, typename TValue> + class icache + { + public: + + ///************************************************************************ + /// Constructor. + /// By default, 'write_through' is set to true. + ///************************************************************************ + icache() + : write_through(true), + p_read_store(std::nullptr), + p_write_store(std::nullptr) + { + } + + ///************************************************************************ + /// Destructor. + /// Flushes the cache if necessary. + ///************************************************************************ + virtual ~icache() + { + if (!write_through) + { + flush(); + } + } + + ///************************************************************************ + /// Sets the function that reads from the store. + ///************************************************************************ + void set_read_function(etl::ifunction<key_value_t&>* p_read) + { + p_read_store = p_read; + } + + ///************************************************************************ + /// Sets the function that writes to the store. + ///************************************************************************ + void set_write_function(etl::ifunction<const key_value_t&>* p_write) + { + p_write_store = p_write; + } + + ///************************************************************************ + /// Sets the 'write through'' flag. + ///************************************************************************ + void set_write_through(bool write_through_) + { + write_through = write_through_; + } + + virtual const T& read(const TKey& key) const = 0; ///< Reads from the cache. May read from the store using p_read_store. + virtual void write(const TKey& key, const TValue& value) = 0; ///< Writes to the cache. May write to the store using p_write_store. + virtual void flush() = 0; ///< The overridden function should write all changed values to the store. + + protected: + + typedef std::pair<TKey, TValue> key_value_t; + + bool write_through; ///< If true, the cache should write changed items back to the store immediately. If false then a flush() or destruct will be required. + + etl::ifunction<key_value_t&>* p_read_store; ///< A pointer to the function that will read a value from the store into the cache. + etl::ifunction<const key_value_t&>* p_write_store; ///< A pointer to the function that will write a value from the cache into the store. + } +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ihash.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,82 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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_IHASH__ +#define __ETL_IHASH__ + +#include <stdint.h> +#include <utility> + +#include "platform.h" +#include "exception.h" +#include "error_handler.h" + +///\defgroup ihash Common data for all hash type classes. +///\ingroup hash + +#undef ETL_FILE +#define ETL_FILE "19" + +namespace etl +{ + //*************************************************************************** + ///\ingroup hash + /// Exception base for hashes. + //*************************************************************************** + class hash_exception : public exception + { + public: + + hash_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + {} + }; + + //*************************************************************************** + ///\ingroup vector + /// Hash finalised exception. + //*************************************************************************** + class hash_finalised : public hash_exception + { + public: + + hash_finalised(string_type file_name_, numeric_type line_number_) + : hash_exception(ETL_ERROR_TEXT("ihash:finalised", ETL_FILE"A"), file_name_, line_number_) + {} + }; + + /// For the Americans + typedef hash_finalised hash_finalized; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/instance_count.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,86 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_INSTANCE_COUNT__ +#define __ETL_INSTANCE_COUNT__ + +#include "platform.h" + +///\defgroup instance_count instance count +///\ingroup utilities + +namespace etl +{ + //*************************************************************************** + /// Inherit from this to count instances of a type. + ///\ingroup reference + //*************************************************************************** + template <typename T> + class instance_count + { + public: + + //************************************************************************* + /// Construct and add 1. + //************************************************************************* + instance_count() + { + ++how_many; + } + + //************************************************************************* + /// Destruct and subtract 1. + //************************************************************************* + virtual ~instance_count() + { + --how_many; + } + + //************************************************************************* + /// Get how many instances we have. + //************************************************************************* + inline static size_t get_instance_count() + { + return how_many; + } + + private: + + /// The count for this type. + static size_t how_many; + }; + + /// Initialisation. + template <typename T> size_t instance_count<T>::how_many = 0; +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/integral_limits.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,222 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_INTEGRAL_LIMITS__ +#define __ETL_INTEGRAL_LIMITS__ + +#include <limits.h> +#include <stddef.h> + +#include "platform.h" +#include "type_traits.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#undef max +#endif + +//***************************************************************************** +///\defgroup integral_limits integral_limits +/// A set of templated compile time constants that mirror some of std::numeric_limits funtionality. +///\ingroup utilities +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <typename T> + struct integral_limits; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<void> + { + static const int min = 0; + static const int max = 0; + static const int bits = 0; + static const bool is_signed = false; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<signed char> + { + static const signed char min = SCHAR_MIN; + static const signed char max = SCHAR_MAX; + static const int bits = CHAR_BIT; + static const bool is_signed = etl::is_signed<signed char>::value; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<unsigned char> + { + static const unsigned char min = 0; + static const unsigned char max = UCHAR_MAX; + static const int bits = CHAR_BIT; + static const bool is_signed = etl::is_signed<unsigned char>::value; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<char> + { + static const char min = (etl::is_signed<char>::value) ? SCHAR_MIN : 0; + static const char max = (etl::is_signed<char>::value) ? SCHAR_MAX : char(UCHAR_MAX); + static const int bits = CHAR_BIT; + static const bool is_signed = etl::is_signed<char>::value; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<short> + { + static const short min = SHRT_MIN; + static const short max = SHRT_MAX; + static const int bits = CHAR_BIT * (sizeof(short) / sizeof(char)); + static const bool is_signed = etl::is_signed<short>::value; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<unsigned short> + { + static const unsigned short min = 0; + static const unsigned short max = USHRT_MAX; + static const int bits = CHAR_BIT * (sizeof(unsigned short) / sizeof(char)); + static const bool is_signed = etl::is_signed<unsigned short>::value; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<int> + { + static const int min = INT_MIN; + static const int max = INT_MAX; + static const int bits = CHAR_BIT * (sizeof(int) / sizeof(char)); + static const bool is_signed = etl::is_signed<int>::value; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<unsigned int> + { + static const unsigned int min = 0; + static const unsigned int max = UINT_MAX; + static const int bits = CHAR_BIT * (sizeof(unsigned int) / sizeof(char)); + static const bool is_signed = etl::is_signed<unsigned int>::value; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<long> + { + static const long min = LONG_MIN; + static const long max = LONG_MAX; + static const int bits = CHAR_BIT * (sizeof(long) / sizeof(char)); + static const bool is_signed = etl::is_signed<long>::value; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<unsigned long> + { + static const unsigned long min = 0; + static const unsigned long max = ULONG_MAX; + static const int bits = CHAR_BIT * (sizeof(unsigned long) / sizeof(char)); + static const bool is_signed = etl::is_signed<unsigned long>::value; + }; + +#ifndef LLONG_MAX +#define LLONG_MAX 9223372036854775807LL +#endif + +#ifndef LLONG_MIN +#define LLONG_MIN (-LLONG_MAX - 1LL) +#endif + +#ifndef ULLONG_MAX +#define ULLONG_MAX 18446744073709551615ULL +#endif + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<long long> + { + static const long long min = LLONG_MIN; + static const long long max = LLONG_MAX; + static const int bits = CHAR_BIT * (sizeof(long long) / sizeof(char)); + static const bool is_signed = etl::is_signed<long long>::value; + }; + + //*************************************************************************** + ///\ingroup integral_limits + //*************************************************************************** + template <> + struct integral_limits<unsigned long long> + { + static const unsigned long long min = 0; + static const unsigned long long max = ULLONG_MAX; + static const int bits = CHAR_BIT * (sizeof(unsigned long long) / sizeof(char)); + static const bool is_signed = etl::is_signed<unsigned long long>::value; + }; +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/intrusive_forward_list.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1049 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_INTRUSIVE_FORWARD_LIST__ +#define __ETL_INTRUSIVE_FORWARD_LIST__ + +#include "platform.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#include <iterator> +#include <algorithm> +#include <functional> +#include <stddef.h> + +#include "platform.h" +#include "nullptr.h" +#include "type_traits.h" +#include "exception.h" +#include "error_handler.h" +#include "intrusive_links.h" +#include "algorithm.h" + +#undef ETL_FILE +#define ETL_FILE "20" + +namespace etl +{ + //*************************************************************************** + /// Exception for the intrusive_forward_list. + ///\ingroup intrusive_forward_list + //*************************************************************************** + class intrusive_forward_list_exception : public exception + { + public: + + intrusive_forward_list_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Empty exception for the intrusive_forward_list. + ///\ingroup intrusive_forward_list + //*************************************************************************** + class intrusive_forward_list_empty : public intrusive_forward_list_exception + { + public: + + intrusive_forward_list_empty(string_type file_name_, numeric_type line_number_) + : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:empty", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the intrusive_forward_list. + ///\ingroup intrusive_forward_list + //*************************************************************************** + class intrusive_forward_list_iterator_exception : public intrusive_forward_list_exception + { + public: + + intrusive_forward_list_iterator_exception(string_type file_name_, numeric_type line_number_) + : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:iterator", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Index exception for the intrusive_forward_list. + ///\ingroup intrusive_forward_list + //*************************************************************************** + class intrusive_forward_list_index_exception : public intrusive_forward_list_exception + { + public: + + intrusive_forward_list_index_exception(string_type file_name_, numeric_type line_number_) + : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:bounds", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Unsorted exception for the intrusive_forward_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_forward_list_unsorted : public intrusive_forward_list_exception + { + public: + + intrusive_forward_list_unsorted(string_type file_name_, numeric_type line_number_) + : intrusive_forward_list_exception(ETL_ERROR_TEXT("intrusive_forward_list:unsorted", ETL_FILE"D"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Base for intrusive forward list. + ///\ingroup intrusive_forward_list + //*************************************************************************** + template <typename TLink> + class intrusive_forward_list_base + { + public: + + // Node typedef. + typedef TLink link_type; + + //************************************************************************* + /// Clears the intrusive_forward_list. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + /// Assigns a range of values to the intrusive_forward_list. + /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined throws forward_list_iterator if the iterators are reversed. + //************************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + intmax_t d = std::distance(first, last); + ETL_ASSERT(d >= 0, ETL_ERROR(intrusive_forward_list_iterator_exception)); +#endif + + initialise(); + + link_type* p_last_link = &start_link; + + // Add all of the elements. + while (first != last) + { + link_type& link = *first++; + etl::link_splice<link_type>(p_last_link, link); + p_last_link = &link; + ++current_size; + } + } + + //************************************************************************* + /// Pushes a value to the front of the intrusive_forward_list. + //************************************************************************* + void push_front(link_type& value) + { + insert_link_after(start_link, value); + } + + //************************************************************************* + /// Removes a value from the front of the intrusive_forward_list. + //************************************************************************* + void pop_front() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(intrusive_forward_list_empty)); +#endif + remove_link_after(start_link); + } + + //************************************************************************* + /// Reverses the intrusive_forward_list. + //************************************************************************* + void reverse() + { + if (is_trivial_list()) + { + return; + } + + link_type* first = std::nullptr; // To keep first link + link_type* second = start_link.etl_next; // To keep second link + link_type* track = start_link.etl_next; // Track the list + + while (track != NULL) + { + track = track->etl_next; // Track point to next link; + second->etl_next = first; // Second link point to first + first = second; // Move first link to next + second = track; // Move second link to next + } + + etl::link<link_type>(start_link, first); + } + + //************************************************************************* + /// Returns true if the list has no elements. + //************************************************************************* + bool empty() const + { + return start_link.etl_next == std::nullptr; + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + size_t size() const + { + return current_size; + } + + protected: + + link_type start_link; ///< The link that acts as the intrusive_forward_list start. + + size_t current_size; ///< Counts the number of elements in the list. + + //************************************************************************* + /// Is the intrusive_forward_list a trivial length? + //************************************************************************* + bool is_trivial_list() const + { + return (start_link.link_type::etl_next == std::nullptr) || (start_link.link_type::etl_next->etl_next == std::nullptr);; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link_after(link_type& position, link_type& link) + { + // Connect to the intrusive_forward_list. + etl::link_splice<link_type>(position, link); + ++current_size; + } + + //************************************************************************* + /// Remove a link. + //************************************************************************* + void remove_link_after(link_type& link) + { + link_type* p_next = link.etl_next; + + if (p_next != std::nullptr) + { + etl::unlink_after<link_type>(link); + --current_size; + } + } + + //************************************************************************* + /// Get the head link. + //************************************************************************* + link_type& get_head() + { + return *start_link.etl_next; + } + + //************************************************************************* + /// Get the head link. + //************************************************************************* + const link_type& get_head() const + { + return *start_link.etl_next; + } + + //************************************************************************* + /// Initialise the intrusive_forward_list. + //************************************************************************* + void initialise() + { + start_link.etl_next = std::nullptr; + current_size = 0; + } + }; + + //*************************************************************************** + /// An intrusive forward list. + ///\ingroup intrusive_forward_list + ///\note TLink must be a base of TValue. + //*************************************************************************** + template <typename TValue, typename TLink = etl::forward_link<0> > + class intrusive_forward_list : public etl::intrusive_forward_list_base<TLink> + { + public: + + // Node typedef. + typedef typename etl::intrusive_forward_list_base<TLink>::link_type link_type; + + // STL style typedefs. + typedef TValue value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + + typedef intrusive_forward_list<TValue, TLink> list_type; + + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator<std::forward_iterator_tag, value_type> + { + public: + + friend class intrusive_forward_list; + + iterator() + : p_value(std::nullptr) + { + } + + iterator(value_type& value) + : p_value(&value) + { + } + + iterator(const iterator& other) + : p_value(other.p_value) + { + } + + iterator& operator ++() + { + // Read the appropriate 'etl_next'. + p_value = static_cast<value_type*>(p_value->link_type::etl_next); + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + // Read the appropriate 'etl_next'. + p_value = static_cast<value_type*>(p_value->link_type::etl_next); + return temp; + } + + iterator operator =(const iterator& other) + { + p_value = other.p_value; + return *this; + } + + reference operator *() + { + return *p_value; + } + + const_reference operator *() const + { + return *p_value; + } + + pointer operator &() + { + return p_value; + } + + const_pointer operator &() const + { + return p_value; + } + + pointer operator ->() + { + return p_value; + } + + const_pointer operator ->() const + { + return p_value; + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_value == rhs.p_value; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + value_type* p_value; + }; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator<std::forward_iterator_tag, const value_type> + { + public: + + friend class intrusive_forward_list; + + const_iterator() + : p_value(std::nullptr) + { + } + + const_iterator(const value_type& value) + : p_value(&value) + { + } + + const_iterator(const typename intrusive_forward_list::iterator& other) + : p_value(other.p_value) + { + } + + const_iterator(const const_iterator& other) + : p_value(other.p_value) + { + } + + const_iterator& operator ++() + { + // Read the appropriate 'etl_next'. + p_value = static_cast<value_type*>(p_value->link_type::etl_next); + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + // Read the appropriate 'etl_next'. + p_value = static_cast<value_type*>(p_value->link_type::etl_next); + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_value = other.p_value; + return *this; + } + + const_reference operator *() const + { + return *p_value; + } + + const_pointer operator &() const + { + return p_value; + } + + const_pointer operator ->() const + { + return p_value; + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_value == rhs.p_value; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + const value_type* p_value; + }; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //************************************************************************* + /// Constructor. + //************************************************************************* + intrusive_forward_list() + { + this->initialise(); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~intrusive_forward_list() + { + this->clear(); + } + + //************************************************************************* + /// Constructor from range + //************************************************************************* + template <typename TIterator> + intrusive_forward_list(TIterator first, TIterator last) + { + this->assign(first, last); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_forward_list. + //************************************************************************* + iterator begin() + { + return iterator(static_cast<value_type&>(this->get_head())); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_forward_list. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(static_cast<const value_type&>(this->get_head())); + } + + //************************************************************************* + /// Gets before the beginning of the intrusive_forward_list. + //************************************************************************* + iterator before_begin() + { + return iterator(static_cast<value_type&>(this->start_link)); + } + + //************************************************************************* + /// Gets before the beginning of the intrusive_forward_list. + //************************************************************************* + const_iterator before_begin() const + { + return const_iterator(static_cast<const value_type&>(this->start_link)); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_forward_list. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(static_cast<const value_type&>(this->get_head())); + } + + //************************************************************************* + /// Gets the end of the intrusive_forward_list. + //************************************************************************* + iterator end() + { + return iterator(); + } + + //************************************************************************* + /// Gets the end of the intrusive_forward_list. + //************************************************************************* + const_iterator end() const + { + return const_iterator(); + } + + //************************************************************************* + /// Gets the end of the intrusive_forward_list. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(); + } + + //************************************************************************* + /// Gets a reference to the first element. + //************************************************************************* + reference front() + { + return static_cast<value_type&>(this->get_head()); + } + + //************************************************************************* + /// Gets a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return static_cast<const value_type&>(this->get_head());; + } + + //************************************************************************* + /// Inserts a value to the intrusive_forward_list after the specified position. + //************************************************************************* + iterator insert_after(iterator position, value_type& value) + { + this->insert_link_after(*position.p_value, value); + return iterator(value); + } + + //************************************************************************* + /// Inserts a range of values to the intrusive_forward_list after the specified position. + //************************************************************************* + template <typename TIterator> + void insert_after(iterator position, TIterator first, TIterator last) + { + while (first != last) + { + // Set up the next free link. + this->insert_link_after(*position.p_value, *first++); + ++position; + } + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase_after(iterator position) + { + iterator next(position); + if (next != end()) + { + ++next; + if (next != end()) + { + ++next; + this->remove_link_after(*position.p_value); + } + } + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase_after(iterator first, iterator last) + { + if (first != end() && (first != last)) + { + this->current_size -= std::distance(first, last) - 1; + + link_type* p_first = first.p_value; + link_type* p_last = last.p_value; + link_type* p_next = p_first->etl_next; + + // Join the ends. + etl::link<link_type>(p_first, p_last); + + if (p_next == std::nullptr) + { + return end(); + } + else + { + return last; + } + } + else + { + return last; + } + } + + //************************************************************************* + /// Removes all but the one element from every consecutive group of equal + /// elements in the container. + //************************************************************************* + template <typename TIsEqual> + void unique(TIsEqual isEqual) + { + if (this->empty()) + { + return; + } + + link_type* last = &this->get_head(); + link_type* current = last->etl_next; + + while (current != std::nullptr) + { + // Is this value the same as the last? + if (isEqual(*static_cast<value_type*>(current), *static_cast<value_type*>(last))) + { + this->remove_link_after(*last); + } + else + { + // Move on one. + last = current; + } + + current = last->etl_next; + } + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + //************************************************************************* + void sort() + { + sort(std::less<value_type>()); + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + /// Uses a supplied predicate function or functor. + /// This is not my algorithm. I got it off the web somewhere. + //************************************************************************* + template <typename TCompare> + void sort(TCompare compare) + { + iterator i_left; + iterator i_right; + iterator i_link; + iterator i_head; + iterator i_tail; + int list_size = 1; + int number_of_merges; + int left_size; + int right_size; + + if (this->is_trivial_list()) + { + return; + } + + while (true) + { + i_left = begin(); + i_head = before_begin(); + i_tail = before_begin(); + + number_of_merges = 0; // Count the number of merges we do in this pass. + + while (i_left != end()) + { + ++number_of_merges; // There exists a merge to be done. + i_right = i_left; + left_size = 0; + + // Step 'list_size' places along from left + for (int i = 0; i < list_size; ++i) + { + ++left_size; + + ++i_right; + + if (i_right == end()) + { + break; + } + } + + // If right hasn't fallen off end, we have two lists to merge. + right_size = list_size; + + // Now we have two lists. Merge them. + while (left_size > 0 || (right_size > 0 && i_right != end())) + { + // Decide whether the next link of merge comes from left or right. + if (left_size == 0) + { + // Left is empty. The link must come from right. + i_link = i_right; + ++i_right; + --right_size; + } + else if (right_size == 0 || i_right == end()) + { + // Right is empty. The link must come from left. + i_link = i_left; + ++i_left; + --left_size; + } + else if (!compare(*i_right, *i_left)) + { + // First link of left is lower or same. The link must come from left. + i_link = i_left; + ++i_left; + --left_size; + } + else + { + // First link of right is lower. The link must come from right. + i_link = i_right; + ++i_right; + --right_size; + } + + // Add the next link to the merged head. + if (i_head == before_begin()) + { + etl::link<link_type>(i_head.p_value, i_link.p_value); + i_head = i_link; + i_tail = i_link; + } + else + { + etl::link<link_type>(i_tail.p_value, i_link.p_value); + i_tail = i_link; + } + + i_tail.p_value->link_type::etl_next = std::nullptr; + } + + // Now left has stepped `list_size' places along, and right has too. + i_left = i_right; + } + + // If we have done only one merge, we're finished. + if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case + { + return; + } + + // Otherwise repeat, merging lists twice the size + list_size *= 2; + } + } + + //************************************************************************* + // Removes the values specified. + //************************************************************************* + void remove(const_reference value) + { + iterator i_item = begin(); + iterator i_last_item = before_begin(); + + while (i_item != end()) + { + if (*i_item == value) + { + i_item = erase_after(i_last_item); + } + else + { + ++i_item; + ++i_last_item; + } + } + } + + //************************************************************************* + /// Removes according to a predicate. + //************************************************************************* + template <typename TPredicate> + void remove_if(TPredicate predicate) + { + iterator i_item = begin(); + iterator i_last_item = before_begin(); + + while (i_item != end()) + { + if (predicate(*i_item)) + { + i_item = erase_after(i_last_item); + } + else + { + ++i_item; + ++i_last_item; + } + } + } + + //************************************************************************* + /// Splice another list into this one. + //************************************************************************* + void splice_after(iterator position, etl::intrusive_forward_list<TValue, TLink>& other) + { + // No point splicing to ourself! + if (&other != this) + { + if (!other.empty()) + { + link_type& first = other.get_head(); + + if (&other != this) + { + this->current_size += other.size(); + } + + link_type& before = *position.p_value; + link_type& after = *position.p_value->link_type::etl_next; + + etl::link<link_type>(before, first); + + link_type* last = &before; + while (last->link_type::etl_next != std::nullptr) + { + last = last->link_type::etl_next; + } + + etl::link<link_type>(last, after); + + other.initialise(); + } + } + } + + //************************************************************************* + /// Splice an element from another list into this one. + //************************************************************************* + void splice(iterator position, etl::intrusive_forward_list<TValue, TLink>& other, iterator isource) + { + link_type& before = *position.p_value; + + etl::unlink<link_type>(*isource.p_value); + etl::link_splice<link_type>(before, *isource.p_value); + + if (&other != this) + { + ++this->current_size; + --other.current_size; + } + } + + //************************************************************************* + /// Splice a range of elements from another list into this one. + //************************************************************************* + void splice_after(iterator position, etl::intrusive_forward_list<TValue, TLink>& other, iterator begin_, iterator end_) + { + if (!other.empty()) + { + if (&other != this) + { + size_t n = std::distance(begin_, end_) - 1; + this->current_size += n; + other.current_size -= n; + } + + link_type* first = begin_.p_value; + link_type* last = first; + + while (last->link_type::etl_next != end_.p_value) + { + last = last->link_type::etl_next; + } + + // Unlink from the source list. + link_type* first_next = first->link_type::etl_next; + etl::unlink_after(*first, *last); + + // Fix our links. + link_type* before = position.p_value; + + etl::link_splice<link_type>(*before, *first_next, *last); + } + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + void merge(list_type& other) + { + merge(other, std::less<value_type>()); + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + template <typename TCompare> + void merge(list_type& other, TCompare compare) + { + if (!other.empty()) + { +#if defined(ETL_DEBUG) + ETL_ASSERT(etl::is_sorted(other.begin(), other.end(), compare), ETL_ERROR(intrusive_forward_list_unsorted)); + ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(intrusive_forward_list_unsorted)); +#endif + + value_type* other_begin = static_cast<value_type*>(&other.get_head()); + value_type* other_terminal = std::nullptr; + + value_type* before = static_cast<value_type*>(&this->start_link); + value_type* before_next = get_next(before); + value_type* terminal = std::nullptr; + + while ((before->link_type::etl_next != terminal) && (other_begin != other_terminal)) + { + // Find the place to insert. + while ((before_next != terminal) && !(compare(*other_begin, *before_next))) + { + before = before_next; + before_next = get_next(before_next); + } + + // Insert. + if (before_next != terminal) + { + while ((other_begin != other_terminal) && (compare(*other_begin, *before_next))) + { + value_type* value = other_begin; + other_begin = get_next(other_begin); + etl::link_splice<link_type>(*before, *value); + before = get_next(before); + } + } + } + + // Any left over? + if (before_next == terminal) + { + while (other_begin != other_terminal) + { + value_type* value = other_begin; + other_begin = get_next(other_begin); + etl::link_splice<link_type>(*before, *value); + before = get_next(before); + } + } + + this->current_size += other.size(); + + other.initialise(); + } + } + + private: + + //************************************************************************* + /// Get the next value. + //************************************************************************* + value_type* get_next(link_type* link) const + { + return static_cast<value_type*>(link->etl_next); + } + + // Disabled. + intrusive_forward_list(const intrusive_forward_list& other); + intrusive_forward_list& operator = (const intrusive_forward_list& rhs); + }; +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/intrusive_links.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,795 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_INTRUSIVE_LINKS__ +#define __ETL_INTRUSIVE_LINKS__ + +#include <assert.h> +#include <utility> + +#include "platform.h" +#include "nullptr.h" +#include "type_traits.h" +#include "exception.h" +#include "error_handler.h" + +#undef ETL_FILE +#define ETL_FILE "22" + +//***************************************************************************** +// Note: +// The link functions work slightly differently to the STL 'insert' convention +// in that the second link parameter will be inserted after the first. +// i.e. +// If the list contains '1', '2', '3', '4' and "link_splice '2','5'" is invoked the +// resulting list will contain '1', '2', '5', '3', '4' +// This is to maintain consistency between forward and bidirectional links +// and also is intuitive. +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Link exception. + //*************************************************************************** + class link_exception : public etl::exception + { + public: + + link_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// not unlinked exception. + //*************************************************************************** + class not_unlinked_exception : public etl::link_exception + { + public: + + not_unlinked_exception(string_type file_name_, numeric_type line_number_) + : link_exception(ETL_ERROR_TEXT("link:still linked", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// A forward link. + //*************************************************************************** + template <const size_t ID_> + struct forward_link + { + enum + { + ID = ID_, + }; + + void clear() + { + etl_next = std::nullptr; + } + + bool is_linked() const + { + return etl_next != std::nullptr; + } + + forward_link* etl_next; + }; + + // Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link(TLink& lhs, TLink& rhs) + { + lhs.etl_next = &rhs; + } + + // Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link_splice(TLink& lhs, TLink& rhs) + { + rhs.etl_next = lhs.etl_next; + lhs.etl_next = &rhs; + } + + // Pointer, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link(TLink* lhs, TLink* rhs) + { + if (lhs != std::nullptr) + { + lhs->etl_next = rhs; + } + } + + // Pointer, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link_splice(TLink* lhs, TLink* rhs) + { + if (lhs != std::nullptr) + { + if (rhs != std::nullptr) + { + rhs->etl_next = lhs->etl_next; + } + + lhs->etl_next = rhs; + } + } + + // Reference, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link(TLink& lhs, TLink* rhs) + { + lhs.etl_next = rhs; + } + + // Reference, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link_splice(TLink& lhs, TLink* rhs) + { + if (rhs != std::nullptr) + { + rhs->etl_next = lhs.etl_next; + } + + lhs.etl_next = rhs; + } + + // Pointer, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link(TLink* lhs, TLink& rhs) + { + if (lhs != std::nullptr) + { + lhs->etl_next = &rhs; + } + } + + // Pointer, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link_splice(TLink* lhs, TLink& rhs) + { + if (lhs != std::nullptr) + { + rhs.etl_next = lhs->etl_next; + lhs->etl_next = &rhs; + } + } + + // Reference, Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link_splice(TLink& lhs, TLink& first, TLink& last) + { + last.etl_next = lhs.etl_next; + lhs.etl_next = &first; + } + + // Pointer, Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + link_splice(TLink* lhs, TLink& first, TLink& last) + { + if (lhs != std::nullptr) + { + last.etl_next = lhs->etl_next; + lhs->etl_next = &first; + } + else + { + last.etl_next = std::nullptr; + } + } + + // Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + unlink_after(TLink& node) + { + if (node.etl_next != std::nullptr) + { + TLink* unlinked_node = node.etl_next; + node.etl_next = unlinked_node->etl_next; + } + } + + // Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::forward_link<TLink::ID> >::value, void>::type + unlink_after(TLink& before, TLink& last) + { + before.etl_next = last.etl_next; + } + + //*************************************************************************** + /// A bidirectional link. + //*************************************************************************** + template <const size_t ID_> + struct bidirectional_link + { + enum + { + ID = ID_, + }; + + void clear() + { + etl_previous = std::nullptr; + etl_next = std::nullptr; + } + + bool is_linked() const + { + return (etl_previous != std::nullptr) || (etl_next != std::nullptr); + } + + void reverse() + { + std::swap(etl_previous, etl_next); + } + + bidirectional_link* etl_previous; + bidirectional_link* etl_next; + + void unlink() + { + // Connect the previous link with the next. + if (etl_previous != std::nullptr) + { + etl_previous->etl_next = etl_next; + } + + // Connect the next link with the previous. + if (etl_next != std::nullptr) + { + etl_next->etl_previous = etl_previous; + } + } + }; + + // Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link(TLink& lhs, TLink& rhs) + { + lhs.etl_next = &rhs; + rhs.etl_previous = &lhs; + } + + // Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link_splice(TLink& lhs, TLink& rhs) + { + rhs.etl_next = lhs.etl_next; + rhs.etl_previous = &lhs; + + if (lhs.etl_next != std::nullptr) + { + lhs.etl_next->etl_previous = &rhs; + } + + lhs.etl_next = &rhs; + } + + // Pointer, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link(TLink* lhs, TLink* rhs) + { + if (lhs != std::nullptr) + { + lhs->etl_next = rhs; + } + + if (rhs != std::nullptr) + { + rhs->etl_previous = lhs; + } + } + + // Pointer, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link_splice(TLink* lhs, TLink* rhs) + { + if (rhs != std::nullptr) + { + if (lhs != std::nullptr) + { + rhs->etl_next = lhs->etl_next; + } + + rhs->etl_previous = lhs; + } + + if (lhs != std::nullptr) + { + if (lhs->etl_next != std::nullptr) + { + lhs->etl_next->etl_previous = rhs; + } + + lhs->etl_next = rhs; + } + } + + // Reference, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link(TLink& lhs, TLink* rhs) + { + lhs.etl_next = rhs; + + if (rhs != std::nullptr) + { + rhs->etl_previous = &lhs; + } + } + + // Reference, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link_splice(TLink& lhs, TLink* rhs) + { + if (rhs != std::nullptr) + { + rhs->etl_next = lhs.etl_next; + rhs->etl_previous = &lhs; + } + + if (lhs.etl_next != std::nullptr) + { + lhs.etl_next->etl_previous = rhs; + } + + lhs.etl_next = rhs; + } + + // Pointer, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link(TLink* lhs, TLink& rhs) + { + if (lhs != std::nullptr) + { + lhs->etl_next = &rhs; + } + + rhs.etl_previous = lhs; + } + + // Pointer, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link_splice(TLink* lhs, TLink& rhs) + { + if (lhs != std::nullptr) + { + rhs.etl_next = lhs->etl_next; + } + + rhs.etl_previous = lhs; + + if (lhs != std::nullptr) + { + if (lhs->etl_next != std::nullptr) + { + lhs->etl_next->etl_previous = &rhs; + } + + lhs->etl_next = &rhs; + } + } + + // Reference, Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link_splice(TLink& lhs, TLink& first, TLink& last) + { + last.etl_next = lhs.etl_next; + first.etl_previous = &lhs; + + if (last.etl_next != std::nullptr) + { + last.etl_next->etl_previous = &last; + } + + lhs.etl_next = &first; + } + + // Pointer, Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + link_splice(TLink* lhs, TLink& first, TLink& last) + { + if (lhs != std::nullptr) + { + last.etl_next = lhs->etl_next; + } + else + { + last.etl_next = std::nullptr; + } + + first.etl_previous = lhs; + + if (last.etl_next != std::nullptr) + { + last.etl_next->etl_previous = &last; + } + + if (lhs != std::nullptr) + { + lhs->etl_next = &first; + } + } + + // Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + unlink(TLink& node) + { + node.unlink(); + } + + // Reference Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type + unlink(TLink& first, TLink& last) + { + if (&first == &last) + { + first.unlink(); + } + else + { + if (last.etl_next != std::nullptr) + { + last.etl_next->etl_previous = first.etl_previous; + } + + if (first.etl_previous != std::nullptr) + { + first.etl_previous->etl_next = last.etl_next; + } + } + } + + //*************************************************************************** + /// A binary tree link. + //*************************************************************************** + template <const size_t ID_> + struct tree_link + { + enum + { + ID = ID_, + }; + + void clear() + { + etl_parent = std::nullptr; + etl_left = std::nullptr; + etl_right = std::nullptr; + } + + bool is_linked() const + { + return (etl_parent != std::nullptr) || (etl_left != std::nullptr) || (etl_right != std::nullptr); + } + + tree_link* etl_parent; + tree_link* etl_left; + tree_link* etl_right; + }; + + // Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_left(TLink& parent, TLink& leaf) + { + parent.etl_left = &leaf; + leaf.etl_parent = &parent; + } + + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_right(TLink& parent, TLink& leaf) + { + parent.etl_right = &leaf; + leaf.etl_parent = &parent; + } + + // Pointer, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_left(TLink* parent, TLink* leaf) + { + if (parent != std::nullptr) + { + parent->etl_left = leaf; + } + + if (leaf != std::nullptr) + { + leaf->etl_parent = parent; + } + } + + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_right(TLink* parent, TLink* leaf) + { + if (parent != std::nullptr) + { + parent->etl_right = leaf; + } + + if (leaf != std::nullptr) + { + leaf->etl_parent = parent; + } + } + + // Reference, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_left(TLink& parent, TLink* leaf) + { + parent.etl_left = leaf; + + if (leaf != std::nullptr) + { + leaf->etl_parent = &parent; + } + } + + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_right(TLink& parent, TLink* leaf) + { + parent.etl_right = leaf; + + if (leaf != std::nullptr) + { + leaf->etl_parent = &parent; + } + } + + // Pointer, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_left(TLink* parent, TLink& leaf) + { + if (parent != std::nullptr) + { + parent->etl_left = &leaf; + } + + leaf.etl_parent = parent; + } + + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_right(TLink* parent, TLink& leaf) + { + if (parent != std::nullptr) + { + parent->etl_right = &leaf; + } + + leaf.etl_parent = parent; + } + + // Reference, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate_left(TLink& parent, TLink& leaf) + { + parent.etl_right = leaf.etl_left; + + if (parent.etl_right != std::nullptr) + { + parent.etl_right->etl_parent = &parent; + } + + leaf.etl_parent = parent.etl_parent; + parent.etl_parent = &leaf; + leaf.etl_left = &parent; + } + + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate_right(TLink& parent, TLink& leaf) + { + parent.etl_left = leaf.etl_right; + + if (parent.etl_left != std::nullptr) + { + parent.etl_left->etl_parent = &parent; + } + + leaf.etl_parent = parent.etl_parent; + parent.etl_parent = &leaf; + leaf.etl_right = &parent; + } + + // Pointer, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate_left(TLink* parent, TLink* leaf) + { + if ((parent != std::nullptr) && (leaf != std::nullptr)) + { + link_rotate_left(*parent, *leaf); + } + } + + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate_right(TLink* parent, TLink* leaf) + { + if ((parent != std::nullptr) && (leaf != std::nullptr)) + { + link_rotate_right(*parent, *leaf); + } + } + + // Reference, Pointer + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate_left(TLink& parent, TLink* leaf) + { + if (leaf != std::nullptr) + { + link_rotate_left(parent, *leaf); + } + } + + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate_right(TLink& parent, TLink* leaf) + { + if (leaf != std::nullptr) + { + link_rotate_right(parent, *leaf); + } + } + + // Pointer, Reference + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate_left(TLink* parent, TLink& leaf) + { + if (parent != std::nullptr) + { + link_rotate_left(*parent, leaf); + } + } + + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate_right(TLink* parent, TLink& leaf) + { + if (parent != std::nullptr) + { + link_rotate_right(*parent, leaf); + } + } + + // Reference, Reference + /// Automatically detects whether a left or right rotate is expected. + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate(TLink& parent, TLink& leaf) + { + if (parent.etl_left == &leaf) + { + etl::link_rotate_right(parent, leaf); + } + else + { + etl::link_rotate_left(parent, leaf); + } + } + + // Pointer, Pointer + /// Automatically detects whether a left or right rotate is expected. + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate(TLink* parent, TLink* leaf) + { + if ((parent != std::nullptr) && (leaf != std::nullptr)) + { + if (parent->etl_left == leaf) + { + etl::link_rotate_right(*parent, *leaf); + } + else + { + etl::link_rotate_left(*parent, *leaf); + } + } + } + + // Reference, Pointer + /// Automatically detects whether a left or right rotate is expected. + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate(TLink& parent, TLink* leaf) + { + if (leaf != std::nullptr) + { + if (parent.etl_left == leaf) + { + etl::link_rotate_right(parent, *leaf); + } + else + { + etl::link_rotate_left(parent, *leaf); + } + } + } + + // Pointer, Reference + /// Automatically detects whether a left or right rotate is expected. + template <typename TLink> + typename etl::enable_if<etl::is_same<TLink, etl::tree_link<TLink::ID> >::value, void>::type + link_rotate(TLink* parent, TLink& leaf) + { + if (parent != std::nullptr) + { + if (parent->etl_left == &leaf) + { + etl::link_rotate_right(*parent, leaf); + } + else + { + etl::link_rotate_left(*parent, leaf); + } + } + } +} + +#undef ETL_FILE +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/intrusive_list.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1081 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_INTRUSIVE_LIST__ +#define __ETL_INTRUSIVE_LIST__ + +#include "platform.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#include <iterator> +#include <algorithm> +#include <functional> +#include <stddef.h> + +#include "platform.h" +#include "nullptr.h" +#include "type_traits.h" +#include "exception.h" +#include "error_handler.h" +#include "intrusive_links.h" +#include "static_assert.h" +#include "algorithm.h" + +#undef ETL_FILE +#define ETL_FILE "21" + +namespace etl +{ + //*************************************************************************** + /// Exception for the intrusive_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_list_exception : public exception + { + public: + + intrusive_list_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Empty exception for the intrusive_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_list_empty : public intrusive_list_exception + { + public: + + intrusive_list_empty(string_type file_name_, numeric_type line_number_) + : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:empty", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the intrusive_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_list_iterator_exception : public intrusive_list_exception + { + public: + + intrusive_list_iterator_exception(string_type file_name_, numeric_type line_number_) + : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:iterator", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Unsorted exception for the intrusive_list. + ///\ingroup intrusive_list + //*************************************************************************** + class intrusive_list_unsorted : public intrusive_list_exception + { + public: + + intrusive_list_unsorted(string_type file_name_, numeric_type line_number_) + : intrusive_list_exception(ETL_ERROR_TEXT("intrusive_list:unsorted", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Base for intrusive list. + ///\ingroup intrusive_list + //*************************************************************************** + template <typename TLink> + class intrusive_list_base + { + public: + + // Node typedef. + typedef TLink link_type; + + //************************************************************************* + /// Assigns a range of values to the intrusive_list. + /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined emits a + /// intrusive_list_iterator_exception if the iterators are reversed. + //************************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + intmax_t d = std::distance(first, last); + ETL_ASSERT(d >= 0, ETL_ERROR(intrusive_list_iterator_exception)); +#endif + + initialise(); + + link_type* p_last_link = &terminal_link; + + // Add all of the elements. + while (first != last) + { + link_type& link = *first++; + etl::link_splice<link_type>(p_last_link, link); + p_last_link = &link; + ++current_size; + } + } + + //************************************************************************* + /// Pushes a value to the front of the intrusive_list. + //************************************************************************* + void push_front(link_type& value) + { + insert_link(terminal_link, value); + } + + //************************************************************************* + /// Removes a value from the front of the intrusive_list. + //************************************************************************* + void pop_front() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty)); +#endif + remove_link(get_head()); + } + + //************************************************************************* + /// Pushes a value to the back of the intrusive_list. + //************************************************************************* + void push_back(link_type& value) + { + insert_link(terminal_link.link_type::etl_previous, value); + } + + //************************************************************************* + /// Removes a value from the back of the intrusive_list. + //************************************************************************* + void pop_back() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(intrusive_list_empty)); +#endif + remove_link(get_tail()); + } + + //************************************************************************* + /// Clears the intrusive_list. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + /// Reverses the list. + //************************************************************************* + void reverse() + { + if (is_trivial_list()) + { + return; + } + + link_type* pnode = terminal_link.etl_next; + + while (pnode != &terminal_link) + { + pnode->reverse(); + pnode = pnode->etl_previous; // Now we've reversed it, we must go to the previous node. + } + + // Terminal node. + pnode->reverse(); + } + + //************************************************************************* + /// Returns true if the list has no elements. + //************************************************************************* + bool empty() const + { + return (terminal_link.link_type::etl_next == &terminal_link); + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + size_t size() const + { + return current_size; + } + + protected: + + /// The link that acts as the intrusive_list start & end. + link_type terminal_link; + + size_t current_size; ///< Counts the number of elements in the list. + + //************************************************************************* + /// Is the intrusive_list a trivial length? + //************************************************************************* + bool is_trivial_list() const + { + return (terminal_link.link_type::etl_next == &terminal_link) || (terminal_link.link_type::etl_next->etl_next == &terminal_link); + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type& previous, link_type& new_link) + { + // Connect to the intrusive_list. + etl::link_splice<link_type>(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type* previous, link_type& new_link) + { + // Connect to the intrusive_list. + etl::link_splice<link_type>(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type& previous, link_type* new_link) + { + // Connect to the intrusive_list. + etl::link_splice<link_type>(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Insert a link. + //************************************************************************* + void insert_link(link_type* previous, link_type* new_link) + { + // Connect to the intrusive_list. + etl::link_splice<link_type>(previous, new_link); + ++current_size; + } + + //************************************************************************* + /// Remove a link. + //************************************************************************* + void remove_link(link_type& link) + { + etl::unlink<link_type>(link); + --current_size; + } + + //************************************************************************* + /// Remove a link. + //************************************************************************* + void remove_link(link_type* link) + { + etl::unlink<link_type>(*link); + --current_size; + } + + //************************************************************************* + /// Get the head link. + //************************************************************************* + link_type* get_head() + { + return terminal_link.etl_next; + } + + //************************************************************************* + /// Get the head link. + //************************************************************************* + const link_type* get_head() const + { + return terminal_link.etl_next; + } + + //************************************************************************* + /// Get the tail link. + //************************************************************************* + link_type* get_tail() + { + return terminal_link.etl_previous; + } + + //************************************************************************* + /// Get the tail link. + //************************************************************************* + const link_type* get_tail() const + { + return terminal_link.etl_previous; + } + + //************************************************************************* + /// Initialise the intrusive_list. + //************************************************************************* + void initialise() + { + etl::link(terminal_link, terminal_link); + current_size = 0; + } + }; + + //*************************************************************************** + /// An intrusive list. + ///\ingroup intrusive_list + ///\note TLink must be a base of TValue. + //*************************************************************************** + template <typename TValue, typename TLink = etl::bidirectional_link<0> > + class intrusive_list : public etl::intrusive_list_base<TLink> + { + public: + + // Node typedef. + typedef typename etl::intrusive_list_base<TLink>::link_type link_type; + + typedef intrusive_list<TValue, TLink> list_type; + + // STL style typedefs. + typedef TValue value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type> + { + public: + + friend class intrusive_list; + + iterator() + : p_value(std::nullptr) + { + } + + iterator(value_type& value) + : p_value(&value) + { + } + + iterator(const iterator& other) + : p_value(other.p_value) + { + } + + iterator& operator ++() + { + // Read the appropriate 'etl_next'. + p_value = static_cast<value_type*>(p_value->link_type::etl_next); + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + // Read the appropriate 'etl_next'. + p_value = static_cast<value_type*>(p_value->link_type::etl_next); + return temp; + } + + iterator& operator --() + { + // Read the appropriate 'etl_previous'. + p_value = static_cast<value_type*>(p_value->link_type::etl_previous); + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + // Read the appropriate 'etl_previous'. + p_value = static_cast<value_type*>(p_value->link_type::etl_previous); + return temp; + } + + iterator operator =(const iterator& other) + { + p_value = other.p_value; + return *this; + } + + reference operator *() + { + return *p_value; + } + + const_reference operator *() const + { + return *p_value; + } + + pointer operator &() + { + return p_value; + } + + const_pointer operator &() const + { + return p_value; + } + + pointer operator ->() + { + return p_value; + } + + const_pointer operator ->() const + { + return p_value; + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_value == rhs.p_value; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + value_type* p_value; + }; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> + { + public: + + friend class intrusive_list; + + const_iterator() + : p_value(std::nullptr) + { + } + + const_iterator(const value_type& value) + : p_value(&value) + { + } + + const_iterator(const typename intrusive_list::iterator& other) + : p_value(other.p_value) + { + } + + const_iterator(const const_iterator& other) + : p_value(other.p_value) + { + } + + const_iterator& operator ++() + { + // Read the appropriate 'etl_next'. + p_value = static_cast<value_type*>(p_value->link_type::etl_next); + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + // Read the appropriate 'etl_next'. + p_value = static_cast<value_type*>(p_value->link_type::etl_next); + return temp; + } + + const_iterator& operator --() + { + // Read the appropriate 'etl_previous'. + p_value = static_cast<value_type*>(p_value->link_type::etl_previous); + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + // Read the appropriate 'etl_previous'. + p_value = static_cast<value_type*>(p_value->link_type::etl_previous); + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_value = other.p_value; + return *this; + } + + const_reference operator *() const + { + return *p_value; + } + + const_pointer operator &() const + { + return p_value; + } + + const_pointer operator ->() const + { + return p_value; + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_value == rhs.p_value; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + const value_type* p_value; + }; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //************************************************************************* + /// Constructor. + //************************************************************************* + intrusive_list() + { + this->initialise(); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~intrusive_list() + { + this->clear(); + } + + //************************************************************************* + /// Constructor from range + //************************************************************************* + template <typename TIterator> + intrusive_list(TIterator first, TIterator last) + { + this->assign(first, last); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_list. + //************************************************************************* + iterator begin() + { + return iterator(static_cast<value_type&>(*this->get_head())); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_list. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(static_cast<const value_type&>(*this->get_head())); + } + + //************************************************************************* + /// Gets the beginning of the intrusive_list. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(static_cast<const value_type&>(*this->get_head())); + } + + //************************************************************************* + /// Gets the end of the intrusive_list. + //************************************************************************* + iterator end() + { + return iterator(static_cast<value_type&>(this->terminal_link)); + } + + //************************************************************************* + /// Gets the end of the intrusive_list. + //************************************************************************* + const_iterator end() const + { + return const_iterator(static_cast<const value_type&>(this->terminal_link)); + } + + //************************************************************************* + /// Gets the end of the intrusive_list. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(static_cast<const value_type&>(this->terminal_link)); + } + + //************************************************************************* + /// Gets a reference to the first element. + //************************************************************************* + reference front() + { + return *static_cast<value_type*>(this->get_head()); + } + + //************************************************************************* + /// Gets a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return *static_cast<const value_type*>(this->get_head());; + } + + //************************************************************************* + /// Gets a reference to the last element. + //************************************************************************* + reference back() + { + return *static_cast<value_type*>(this->get_tail()); + } + + //************************************************************************* + /// Gets a const reference to the last element. + //************************************************************************* + const_reference back() const + { + return *static_cast<const value_type*>(this->get_tail());; + } + + //************************************************************************* + /// Inserts a value to the intrusive_list before the specified position. + //************************************************************************* + iterator insert(iterator position, value_type& value) + { + this->insert_link(position.p_value->link_type::etl_previous, value); + return iterator(value); + } + + //************************************************************************* + /// Inserts a range of values to the intrusive_list after the specified position. + //************************************************************************* + template <typename TIterator> + void insert(iterator position, TIterator first, TIterator last) + { + while (first != last) + { + // Set up the next free link. + this->insert_link(*position.p_value->link_type::etl_previous, *first++); + } + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase(iterator position) + { + iterator next(position); + ++next; + + this->remove_link(*position.p_value); + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + /// Clears the links after erasing if AUTO or CHECKED. + //************************************************************************* + iterator erase(iterator first, iterator last) + { + link_type* p_first = first.p_value; + link_type* p_last = last.p_value; + + // Join the ends. + etl::link<link_type>(p_first->etl_previous, p_last); + + this->current_size -= std::distance(first, last); + + if (p_last == &this->terminal_link) + { + return end(); + } + else + { + return iterator(*static_cast<value_type*>(p_last)); + } + } + + //************************************************************************* + /// Removes all but the one element from every consecutive group of equal + /// elements in the container. + //************************************************************************* + template <typename TIsEqual> + void unique(TIsEqual isEqual) + { + if (this->empty()) + { + return; + } + + iterator i_item = begin(); + ++i_item; + iterator i_previous = begin(); + + while (i_item != end()) + { + if (isEqual(*i_previous, *i_item)) + { + i_item = erase(i_item); + } + else + { + i_previous = i_item; + ++i_item; + } + } + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + //************************************************************************* + void sort() + { + sort(std::less<value_type>()); + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + /// Uses a supplied predicate function or functor. + /// This is not my algorithm. I got it off the web somewhere. + //************************************************************************* + template <typename TCompare> + void sort(TCompare compare) + { + iterator i_left; + iterator i_right; + iterator i_node; + iterator i_head; + iterator i_tail; + int list_size = 1; + int number_of_merges; + int left_size; + int right_size; + + if (this->is_trivial_list()) + { + return; + } + + while (true) + { + i_left = begin(); + i_head = end(); + i_tail = end(); + + number_of_merges = 0; // Count the number of merges we do in this pass. + + while (i_left != end()) + { + ++number_of_merges; // There exists a merge to be done. + i_right = i_left; + left_size = 0; + + // Step 'list_size' places along from left + for (int i = 0; i < list_size; ++i) + { + ++left_size; + ++i_right; + + if (i_right == end()) + { + break; + } + } + + // If right hasn't fallen off end, we have two lists to merge. + right_size = list_size; + + // Now we have two lists. Merge them. + while (left_size > 0 || (right_size > 0 && i_right != end())) + { + // Decide whether the next node of merge comes from left or right. + if (left_size == 0) + { + // Left is empty. The node must come from right. + i_node = i_right++; + --right_size; + } + else if (right_size == 0 || i_right == end()) + { + // Right is empty. The node must come from left. + i_node = i_left++; + --left_size; + } + else if (!compare(*i_right, *i_left)) + { + // First node of left is lower or same. The node must come from left. + i_node = i_left++; + --left_size; + } + else + { + // First node of right is lower. The node must come from right. + i_node = i_right; + ++i_right; + --right_size; + } + + // Add the next node to the merged head. + if (i_head == end()) + { + etl::link<link_type>(i_head.p_value, i_node.p_value); + i_head = i_node; + i_tail = i_node; + } + else + { + etl::link<link_type>(i_tail.p_value, i_node.p_value); + i_tail = i_node; + } + + etl::link<link_type>(i_tail.p_value, this->terminal_link); + } + + // Now left has stepped `list_size' places along, and right has too. + i_left = i_right; + } + + // If we have done only one merge, we're finished. + if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case + { + return; + } + + // Otherwise repeat, merging lists twice the size + list_size *= 2; + } + } + + //************************************************************************* + // Removes the values specified. + //************************************************************************* + void remove(const_reference value) + { + iterator i_item = begin(); + + while (i_item != end()) + { + if (*i_item == value) + { + i_item = erase(i_item); + } + else + { + ++i_item; + } + } + } + + //************************************************************************* + /// Removes according to a predicate. + //************************************************************************* + template <typename TPredicate> + void remove_if(TPredicate predicate) + { + iterator i_item = begin(); + + while (i_item != end()) + { + if (predicate(*i_item)) + { + i_item = erase(i_item); + } + else + { + ++i_item; + } + } + } + + //************************************************************************* + /// Splice another list into this one. + //************************************************************************* + void splice(iterator position, list_type& other) + { + // No point splicing to ourself! + if (&other != this) + { + if (!other.empty()) + { + link_type& first = *other.get_head(); + link_type& last = *other.get_tail(); + + if (&other != this) + { + this->current_size += other.size(); + } + + link_type& after = *position.p_value; + link_type& before = *after.etl_previous; + + etl::link<link_type>(before, first); + etl::link<link_type>(last, after); + + other.initialise(); + } + } + } + + //************************************************************************* + /// Splice an element from another list into this one. + //************************************************************************* + void splice(iterator position, list_type& other, iterator isource) + { + link_type& before = *position.p_value->link_type::etl_previous; + + etl::unlink<link_type>(*isource.p_value); + etl::link_splice<link_type>(before, *isource.p_value); + + if (&other != this) + { + ++this->current_size; + --other.current_size; + } + } + + //************************************************************************* + /// Splice a range of elements from another list into this one. + //************************************************************************* + void splice(iterator position, list_type& other, iterator begin_, iterator end_) + { + if (!other.empty()) + { + if (&other != this) + { + size_t n = std::distance(begin_, end_); + this->current_size += n; + other.current_size -= n; + } + + link_type& first = *begin_.p_value; + link_type& last = *end_.p_value->link_type::etl_previous; + + // Unlink from the source list. + etl::unlink(first, last); + + // Fix our links. + link_type& before = *position.p_value->link_type::etl_previous; + + etl::link_splice<link_type>(before, first, last); + } + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + void merge(list_type& other) + { + merge(other, std::less<value_type>()); + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + template <typename TCompare> + void merge(list_type& other, TCompare compare) + { + if (!other.empty()) + { +#if defined(ETL_DEBUG) + ETL_ASSERT(etl::is_sorted(other.begin(), other.end(), compare), ETL_ERROR(intrusive_list_unsorted)); + ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(intrusive_list_unsorted)); +#endif + + value_type* other_begin = static_cast<value_type*>(other.get_head()); + value_type* other_end = static_cast<value_type*>(&other.terminal_link); + + value_type* this_begin = static_cast<value_type*>(this->get_head()); + value_type* this_end = static_cast<value_type*>(&this->terminal_link); + + while ((this_begin != this_end) && (other_begin != other_end)) + { + // Find the place to insert. + while ((this_begin != this_end) && !(compare(*other_begin, *this_begin))) + { + this_begin = static_cast<value_type*>(this_begin->link_type::etl_next); + } + + // Insert. + if (this_begin != this_end) + { + while ((other_begin != other_end) && (compare(*other_begin, *this_begin))) + { + value_type* value = other_begin; + other_begin = static_cast<value_type*>(other_begin->link_type::etl_next); + etl::link_splice<link_type>(*this_begin->link_type::etl_previous, *value); + } + } + } + + // Any left over? + if ((this_begin == this_end) && (other_begin != other_end)) + { + etl::link_splice<link_type>(*this->get_tail(), *other_begin, *other_end->link_type::etl_previous); + } + + this->current_size += other.size(); + + other.initialise(); + } + } + + private: + + // Disabled. + intrusive_list(const intrusive_list& other); + intrusive_list& operator = (const intrusive_list& rhs); + }; +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/intrusive_queue.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,272 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_INTRUSIVE_QUEUE__ +#define __ETL_INTRUSIVE_QUEUE__ + +#include <stddef.h> + +#include "platform.h" +#include "type_traits.h" +#include "error_handler.h" +#include "intrusive_links.h" + +#define ETL_FILE "29" + +namespace etl +{ + //*************************************************************************** + /// Exception base for intrusive queue + ///\ingroup intrusive_queue + //*************************************************************************** + class intrusive_queue_exception : public etl::exception + { + public: + + intrusive_queue_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// intrusive_queue empty exception. + ///\ingroup intrusive_queue + //*************************************************************************** + class intrusive_queue_empty : public intrusive_queue_exception + { + public: + + intrusive_queue_empty(string_type file_name_, numeric_type line_number_) + : intrusive_queue_exception(ETL_ERROR_TEXT("intrusive_queue:empty", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup queue + /// Base for intrusive queue. Stores elements derived any type that supports an 'etl_next' pointer member. + /// \tparam TLink The link type that the value is derived from. + //*************************************************************************** + template <typename TLink> + class intrusive_queue_base + { + public: + + // Node typedef. + typedef TLink link_type; + + //************************************************************************* + /// Adds a value to the queue. + ///\param value The value to push to the queue. + //************************************************************************* + void push(link_type& value) + { + value.clear(); + + if (p_back != std::nullptr) + { + etl::link(p_back, value); + } + else + { + p_front = &value; + } + + p_back = &value; + + ++current_size; + } + + //************************************************************************* + /// Removes the oldest item from the queue. + /// Undefined behaviour if the queue is already empty. + //************************************************************************* + void pop() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(intrusive_queue_empty)); +#endif + link_type* p_next = p_front->etl_next; + + p_front = p_next; + + // Now empty? + if (p_front == std::nullptr) + { + p_back = std::nullptr; + } + + --current_size; + } + + //************************************************************************* + /// Removes the oldest item from the queue and pushes it to the destination. + /// Undefined behaviour if the queue is already empty. + /// NOTE: The destination must be an intrusize container that supports a push(TLink) member function. + //************************************************************************* + template <typename TContainer> + void pop_into(TContainer& destination) + { + link_type* p_link = p_front; + pop(); + destination.push(*p_link); + } + + //************************************************************************* + /// Clears the queue to the empty state. + //************************************************************************* + void clear() + { + while (!empty()) + { + pop(); + } + + current_size = 0; + } + + //************************************************************************* + /// Checks if the queue is in the empty state. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + size_t size() const + { + return current_size; + } + + protected: + + //************************************************************************* + /// Constructor + //************************************************************************* + intrusive_queue_base() + : p_front(std::nullptr), + p_back(std::nullptr), + current_size(0) + { + } + + link_type* p_front; ///< The current front of the queue. + link_type* p_back; ///< The current back of the queue. + + size_t current_size; ///< Counts the number of elements in the list. + }; + + //*************************************************************************** + ///\ingroup queue + /// An intrusive queue. Stores elements derived from any type that supports an 'etl_next' pointer member. + /// \warning This queue cannot be used for concurrent access from multiple threads. + /// \tparam TValue The type of value that the queue holds. + /// \tparam TLink The link type that the value is derived from. + //*************************************************************************** + template <typename TValue, typename TLink> + class intrusive_queue : public etl::intrusive_queue_base<TLink> + { + public: + + // Node typedef. + typedef typename etl::intrusive_queue_base<TLink> link_type; + + // STL style typedefs. + typedef TValue value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + + //************************************************************************* + /// Constructor + //************************************************************************* + intrusive_queue() + : intrusive_queue_base<TLink>() + { + } + + //************************************************************************* + /// Gets a reference to the value at the front of the queue. + /// Undefined behaviour if the queue is empty. + /// \return A reference to the value at the front of the queue. + //************************************************************************* + reference front() + { + return *static_cast<TValue*>(this->p_front); + } + + //************************************************************************* + /// Gets a reference to the value at the back of the queue. + /// Undefined behaviour if the queue is empty. + /// \return A reference to the value at the back of the queue. + //************************************************************************* + reference back() + { + return *static_cast<TValue*>(this->p_back); + } + + //************************************************************************* + /// Gets a const reference to the value at the front of the queue. + /// Undefined behaviour if the queue is empty. + /// \return A const reference to the value at the front of the queue. + //************************************************************************* + const_reference front() const + { + return *static_cast<const TValue*>(this->p_front); + } + + //************************************************************************* + /// Gets a reference to the value at the back of the queue. + /// Undefined behaviour if the queue is empty. + /// \return A reference to the value at the back of the queue. + //************************************************************************* + const_reference back() const + { + return *static_cast<const TValue*>(this->p_back); + } + + private: + + // Disable copy construction and assignment. + intrusive_queue(const intrusive_queue&); + intrusive_queue& operator = (const intrusive_queue& rhs); + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/intrusive_stack.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,257 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_INTRUSIVE_STACK__ +#define __ETL_INTRUSIVE_STACK__ + +#include <stddef.h> + +#include "platform.h" +#include "type_traits.h" +#include "error_handler.h" +#include "intrusive_links.h" + +#define ETL_FILE "28" + +namespace etl +{ + //*************************************************************************** + /// Exception base for intrusive stack + ///\ingroup intrusive_stack + //*************************************************************************** + class intrusive_stack_exception : public etl::exception + { + public: + + intrusive_stack_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// intrusive_stack empty exception. + ///\ingroup intrusive_stack + //*************************************************************************** + class intrusive_stack_empty : public intrusive_stack_exception + { + public: + + intrusive_stack_empty(string_type file_name_, numeric_type line_number_) + : intrusive_stack_exception(ETL_ERROR_TEXT("intrusive_stack:empty", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// Base for intrusive stack. Stores elements derived any type that supports an 'etl_next' pointer member. + /// \tparam TLink The link type that the value is derived from. + //*************************************************************************** + template <typename TLink> + class intrusive_stack_base + { + public: + + // Node typedef. + typedef TLink link_type; + + //************************************************************************* + /// Adds a value to the stack. + ///\param value The value to push to the stack. + //************************************************************************* + void push(link_type& value) + { + value.clear(); + + if (p_top != std::nullptr) + { + etl::link(value, p_top); + } + + p_top = &value; + + ++current_size; + } + + //************************************************************************* + /// Removes the oldest item from the top of the stack. + /// Undefined behaviour if the stack is already empty. + //************************************************************************* + void pop() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(intrusive_stack_empty)); +#endif + link_type* p_next = p_top->etl_next; + p_top = p_next; + --current_size; + } + + //************************************************************************* + /// Removes the oldest item from the queue and pushes it to the destination. + /// Undefined behaviour if the queue is already empty. + /// NOTE: The destination must be an intrusize container that supports a push(TLink) member function. + //************************************************************************* + template <typename TContainer> + void pop_into(TContainer& destination) + { + link_type* p_link = p_top; + pop(); + destination.push(*p_link); + } + + //************************************************************************* + /// Reverses the stack order. + //************************************************************************* + void reverse() + { + link_type* previous = std::nullptr; + link_type* current = p_top; + link_type* next; + + while (current != std::nullptr) + { + next = current->etl_next; + current->etl_next = previous; + previous = current; + current = next; + } + + p_top = previous; + } + + //************************************************************************* + /// Clears the stack to the empty state. + //************************************************************************* + void clear() + { + while (!empty()) + { + pop(); + } + + current_size = 0; + } + + //************************************************************************* + /// Checks if the stack is in the empty state. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + size_t size() const + { + return current_size; + } + + protected: + + //************************************************************************* + /// Constructor + //************************************************************************* + intrusive_stack_base() + : p_top(std::nullptr), + current_size(0) + { + } + + link_type* p_top; ///< The current top of the stack. + + size_t current_size; ///< Counts the number of elements in the list. + }; + + //*************************************************************************** + ///\ingroup stack + /// An intrusive stack. Stores elements derived from any type that supports an 'etl_next' pointer member. + /// \warning This stack cannot be used for concurrent access from multiple threads. + /// \tparam TValue The type of value that the stack holds. + /// \tparam TLink The link type that the value is derived from. + //*************************************************************************** + template <typename TValue, typename TLink> + class intrusive_stack : public etl::intrusive_stack_base<TLink> + { + public: + + // Node typedef. + typedef typename etl::intrusive_stack_base<TLink>::link_type link_type; + + // STL style typedefs. + typedef TValue value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + + //************************************************************************* + /// Constructor + //************************************************************************* + intrusive_stack() + : intrusive_stack_base<TLink>() + { + } + + //************************************************************************* + /// Gets a reference to the value at the top of the stack. + /// Undefined behaviour if the stack is empty. + /// \return A reference to the value at the top of the stack. + //************************************************************************* + reference top() + { + return *static_cast<TValue*>(this->p_top); + } + + //************************************************************************* + /// Gets a const reference to the value at the top of the stack.<br> + /// \return A const reference to the value at the top of the stack. + //************************************************************************* + const_reference top() const + { + return *static_cast<const TValue*>(this->p_top); + } + + private: + + // Disable copy construction and assignment. + intrusive_stack(const intrusive_stack&); + intrusive_stack& operator = (const intrusive_stack& rhs); + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/io_port.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,808 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_IO_PORT__ +#define __ETL_IO_PORT__ + +///\defgroup io_port io port +/// IO port access +///\ingroup utilities + +#include <stdint.h> +#include <iterator> + +#include "platform.h" +#include "nullptr.h" + +namespace etl +{ + //*************************************************************************** + /// Read write port. + //*************************************************************************** + template <typename T, uintptr_t ADDRESS = 0> + class io_port_rw : public std::iterator<std::forward_iterator_tag, T> + { + public: + + typedef volatile T* pointer; + typedef volatile const T* const_pointer; + typedef volatile T& reference; + typedef volatile const T& const_reference; + + /// Read. + operator T() const + { + return *reinterpret_cast<const_pointer>(ADDRESS); + } + + /// Read. + T read() const + { + return *reinterpret_cast<const_pointer>(ADDRESS); + } + + /// Write. + void write(T value_) + { + *reinterpret_cast<pointer>(ADDRESS) = value_; + } + + /// Write. + io_port_rw& operator =(T value_) + { + *reinterpret_cast<pointer>(ADDRESS) = value_; + return *this; + } + + /// Read / Write + reference operator *() + { + return *reinterpret_cast<pointer>(ADDRESS); + } + + /// Read + const_reference operator *() const + { + return *reinterpret_cast<const_pointer>(ADDRESS); + } + + /// Increment + io_port_rw& operator ++() + { + return *this; + } + + /// Increment + io_port_rw operator ++(int) + { + return *this; + } + + /// Get the IO port address. + pointer get_address() + { + return reinterpret_cast<pointer>(ADDRESS); + } + + /// Get the IO port address. + const_pointer get_address() const + { + return reinterpret_cast<const_pointer>(ADDRESS); + } + + private: + + /// Disabled. + io_port_rw& operator =(const io_port_rw&); + }; + + //*************************************************************************** + /// Read only port. + //*************************************************************************** + template <typename T, uintptr_t ADDRESS = 0> + class io_port_ro : public std::iterator<std::input_iterator_tag, T> + { + public: + + typedef volatile T* pointer; + typedef volatile const T* const_pointer; + typedef volatile T& reference; + typedef volatile const T& const_reference; + + /// Read. + operator T() const + { + return *reinterpret_cast<const_pointer>(ADDRESS); + } + + /// Read. + T read() const + { + return *reinterpret_cast<const_pointer>(ADDRESS); + } + + /// Read + const_reference operator *() const + { + return *reinterpret_cast<const_pointer>(ADDRESS); + } + + /// Increment + io_port_ro& operator ++() + { + return *this; + } + + /// Increment + io_port_ro operator ++(int) + { + return *this; + } + + /// Get the IO port address. + pointer get_address() + { + return reinterpret_cast<pointer>(ADDRESS); + } + + /// Get the IO port address. + const_pointer get_address() const + { + return reinterpret_cast<const_pointer>(ADDRESS); + } + + private: + + /// Write disabled. + void operator =(T value); + + /// Disabled. + io_port_ro& operator =(const io_port_ro&); + }; + + //*************************************************************************** + /// Write only port. + //*************************************************************************** + template <typename T, uintptr_t ADDRESS = 0> + class io_port_wo : public std::iterator<std::output_iterator_tag, T> + { + public: + + typedef volatile T* pointer; + typedef volatile const T* const_pointer; + typedef volatile T& reference; + typedef volatile const T& const_reference; + + /// Write. + void operator =(T value) + { + *reinterpret_cast<pointer>(ADDRESS) = value; + } + + /// Write. + void write(T value_) + { + *reinterpret_cast<pointer>(ADDRESS) = value_; + } + + /// Write + io_port_wo& operator *() + { + return *this; + } + + /// Increment + io_port_wo& operator ++() + { + return *this; + } + + /// Increment + io_port_wo operator ++(int) + { + return *this; + } + + /// Get the IO port address. + pointer get_address() + { + return reinterpret_cast<pointer>(ADDRESS); + } + + /// Get the IO port address. + const_pointer get_address() const + { + return reinterpret_cast<const_pointer>(ADDRESS); + } + + private: + + /// Read disabled. + operator T() const; + + /// Disabled. + io_port_wo& operator =(const io_port_wo&); + }; + + //*************************************************************************** + /// Write only port with shadow register. + //*************************************************************************** + template <typename T, uintptr_t ADDRESS = 0> + class io_port_wos : public std::iterator<std::forward_iterator_tag, T> + { + public: + + typedef volatile T* pointer; + typedef volatile const T* const_pointer; + typedef volatile T& reference; + typedef volatile const T& const_reference; + + /// Read. + operator T() const + { + return shadow_value; + } + + /// Read. + T read() const + { + return shadow_value; + } + + /// Write. + void write(T value_) + { + shadow_value = value_; + *reinterpret_cast<pointer>(ADDRESS) = shadow_value; + } + + /// Write. + io_port_wos& operator =(T value_) + { + shadow_value = value_; + *reinterpret_cast<pointer>(ADDRESS) = shadow_value; + return *this; + } + + /// Read / Write + io_port_wos& operator *() + { + return *this; + } + + /// Read + const_reference operator *() const + { + return shadow_value; + } + + /// Increment + io_port_wos& operator ++() + { + return *this; + } + + /// Increment + io_port_wos operator ++(int) + { + return *this; + } + + /// Get the IO port address. + pointer get_address() + { + return reinterpret_cast<pointer>(ADDRESS); + } + + private: + + /// Disabled. + io_port_wos& operator =(const io_port_wos&); + + T shadow_value; + }; + + //*************************************************************************** + /// Read write port. + /// Specialisation for dynamic addresses. + //*************************************************************************** + template <typename T> + class io_port_rw<T, 0> : public std::iterator<std::forward_iterator_tag, T> + { + public: + + typedef volatile T* pointer; + typedef volatile const T* const_pointer; + typedef volatile T& reference; + typedef volatile const T& const_reference; + + /// Default constructor. + io_port_rw() + : address(std::nullptr) + { + } + + /// Constructor. + io_port_rw(void* address_) + : address(reinterpret_cast<pointer>(address_)) + { + } + + /// Copy Constructor. + io_port_rw(const io_port_rw& other_) + : address(reinterpret_cast<pointer>(other_.address)) + { + } + + /// Assignment. + io_port_rw& operator =(const io_port_rw& other_) + { + address = other_.address; + return *this; + } + + /// Set the IO port address. + void set_address(void* address_) + { + address = reinterpret_cast<pointer>(address_); + } + + /// Get the IO port address. + pointer get_address() + { + return address; + } + + /// Get the IO port address. + const_pointer get_address() const + { + return address; + } + + /// Read. + operator T() const + { + return *address; + } + + /// Read. + T read() const + { + return *address; + } + + /// Write. + void write(T value_) + { + *address = value_; + } + + /// Write. + io_port_rw& operator =(T value_) + { + *address = value_; + return *this; + } + + /// Read / Write + reference operator *() + { + return *address; + } + + /// Read + const_reference operator *() const + { + return *address; + } + + /// Increment + io_port_rw& operator ++() + { + return *this; + } + + /// Increment + io_port_rw operator ++(int) + { + return *this; + } + + private: + + pointer address; + }; + + //*************************************************************************** + /// Read only port. + /// Specialisation for dynamic addresses. + //*************************************************************************** + template <typename T> + class io_port_ro<T, 0> : public std::iterator<std::input_iterator_tag, T> + { + public: + + typedef volatile T* pointer; + typedef volatile const T* const_pointer; + typedef volatile T& reference; + typedef volatile const T& const_reference; + + /// Default constructor. + io_port_ro() + : address(std::nullptr) + { + } + + /// Constructor. + io_port_ro(void* address_) + : address(reinterpret_cast<pointer>(address_)) + { + } + + /// Copy Constructor. + io_port_ro(const io_port_ro& other_) + : address(reinterpret_cast<pointer>(other_.address)) + { + } + + /// Assignment. + io_port_ro& operator =(const io_port_ro& other_) + { + address = other_.address; + return *this; + } + + /// Set the IO port address. + void set_address(void* address_) + { + address = reinterpret_cast<pointer>(address_); + } + + /// Get the IO port address. + const_pointer get_address() const + { + return address; + } + + /// Read. + operator T() const + { + return *address; + } + + /// Read. + T read() const + { + return *address; + } + + /// Read + const_reference operator *() const + { + return *address; + } + + /// Increment + io_port_ro& operator ++() + { + return *this; + } + + /// Increment + io_port_ro operator ++(int) + { + return *this; + } + + private: + + /// Write disabled. + void operator =(T value); + + pointer address; + }; + + //*************************************************************************** + /// Write only port. + /// Specialisation for dynamic addresses. + //*************************************************************************** + template <typename T> + class io_port_wo<T, 0> : public std::iterator<std::output_iterator_tag, T> + { + public: + + typedef volatile T* pointer; + typedef volatile const T* const_pointer; + typedef volatile T& reference; + typedef volatile const T& const_reference; + + /// Default constructor. + io_port_wo() + : address(std::nullptr) + { + } + + /// Constructor. + io_port_wo(void* address_) + : address(reinterpret_cast<pointer>(address_)) + { + } + + /// Copy Constructor. + io_port_wo(const io_port_wo& other_) + : address(reinterpret_cast<pointer>(other_.address)) + { + } + + /// Assignment. + io_port_wo& operator =(const io_port_wo& other_) + { + address = other_.address; + return *this; + } + + /// Set the IO port address. + void set_address(void* address_) + { + address = reinterpret_cast<pointer>(address_); + } + + /// Get the IO port address. + pointer get_address() + { + return address; + } + + /// Get the IO port address. + const_pointer get_address() const + { + return address; + } + + /// Write. + void write(T value_) + { + *address = value_; + } + + /// Write. + void operator =(T value) + { + *address = value; + } + + /// Write + io_port_wo& operator *() + { + return *this; + } + + /// Increment + io_port_wo& operator ++() + { + return *this; + } + + /// Write + io_port_wo operator ++(int) + { + return *this; + } + + private: + + /// Read disabled. + operator T() const; + + pointer address; + }; + + //*************************************************************************** + /// Write only port with shadow register. + /// Specialisation for dynamic addresses. + //*************************************************************************** + template <typename T> + class io_port_wos<T, 0> : public std::iterator<std::forward_iterator_tag, T> + { + public: + + typedef volatile T* pointer; + typedef volatile const T* const_pointer; + typedef volatile T& reference; + typedef volatile const T& const_reference; + + class iterator : public std::iterator<std::bidirectional_iterator_tag, T> + { + typedef io_port_wos<T, 0> iop_t; + + public: + + iterator(iop_t& iop) + : p_iop(&iop) + { + } + + iterator(const iterator& other) + : p_iop(other.p_iop) + { + } + + iterator& operator =(const iterator& other) + { + p_iop = other.p_iop; + return *this; + } + + iop_t& operator *() + { + return *p_iop; + } + + const iop_t& operator *() const + { + return *p_iop; + } + + iterator& operator ++() + { + return *this; + } + + iterator operator ++(int) + { + return *this; + } + + iterator& operator --() + { + return *this; + } + + iterator operator --(int) + { + return *this; + } + + private: + + iop_t* p_iop; + }; + + /// Default constructor. + io_port_wos() + : address(std::nullptr) + { + } + + /// Constructor. + io_port_wos(void* address_) + : address(reinterpret_cast<pointer>(address_)) + { + } + + /// Copy Constructor. + io_port_wos(const io_port_wos& other_) + : shadow_value(other_.shadow_value), + address(reinterpret_cast<pointer>(other_.address)) + { + } + + /// Assignment. + io_port_wos& operator =(const io_port_wos& other_) + { + shadow_value = other_.shadow_value; + address = other_.address; + return *this; + } + + /// Set the IO port address. + void set_address(void* address_) + { + address = reinterpret_cast<pointer>(address_); + } + + /// Get the IO port address. + pointer get_address() + { + return address; + } + + /// Get the IO port address. + const_pointer get_address() const + { + return address; + } + + /// Get the iterator. + iterator get_iterator() + { + return iterator(*this); + } + + /// Read. + operator T() const + { + return shadow_value; + } + + /// Read. + T read() const + { + return shadow_value; + } + + /// Write. + void write(T value_) + { + shadow_value = value_; + *address = shadow_value; + } + + /// Write. + io_port_wos& operator =(T value_) + { + shadow_value = value_; + *address = shadow_value; + return *this; + } + + /// Read / Write + io_port_wos& operator *() + { + return *this; + } + + /// Read + const_reference operator *() const + { + return shadow_value; + } + + /// Increment + io_port_wos& operator ++() + { + return *this; + } + + /// Increment + io_port_wos operator ++(int) + { + return *this; + } + + private: + + T shadow_value; + pointer address; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iterator.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,117 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ITERATOR__ +#define __ETL_ITERATOR__ + +#include <iterator> + +#include "platform.h" +#include "type_traits.h" + +///\defgroup iterator iterator +///\ingroup utilities + +namespace etl +{ + template <typename T> + struct is_input_iterator + { + static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::input_iterator_tag>::value; + }; + + template <typename T> + struct is_output_iterator + { + static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::output_iterator_tag>::value; + }; + + template <typename T> + struct is_forward_iterator + { + static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::forward_iterator_tag>::value; + }; + + template <typename T> + struct is_bidirectional_iterator + { + static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::bidirectional_iterator_tag>::value; + }; + + template <typename T> + struct is_random_iterator + { + static const bool value = etl::is_same<typename std::iterator_traits<T>::iterator_category, std::random_access_iterator_tag>::value; + }; + + template <typename T> + struct is_input_iterator_concept + { + static const bool value = etl::is_input_iterator<T>::value || + etl::is_forward_iterator<T>::value || + etl::is_bidirectional_iterator<T>::value || + etl::is_random_iterator<T>::value; + }; + + template <typename T> + struct is_output_iterator_concept + { + static const bool value = etl::is_output_iterator<T>::value || + etl::is_forward_iterator<T>::value || + etl::is_bidirectional_iterator<T>::value || + etl::is_random_iterator<T>::value; + }; + + template <typename T> + struct is_forward_iterator_concept + { + static const bool value = etl::is_forward_iterator<T>::value || + etl::is_bidirectional_iterator<T>::value || + etl::is_random_iterator<T>::value; + }; + + template <typename T> + struct is_bidirectional_iterator_concept + { + static const bool value = etl::is_bidirectional_iterator<T>::value || + etl::is_random_iterator<T>::value; + }; + + template <typename T> + struct is_random_iterator_concept + { + static const bool value = etl::is_random_iterator<T>::value; + }; + +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jenkins.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,122 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_JENKINS__ +#define __ETL_JENKINS__ + +#include <stdint.h> +#include <iterator> + +#include "platform.h" +#include "static_assert.h" +#include "type_traits.h" +#include "error_handler.h" +#include "ihash.h" +#include "frame_check_sequence.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup jenkins Jenkins 32 hash calculation +///\ingroup maths + +namespace etl +{ + //*************************************************************************** + /// Jenkins policy. + /// Calculates 32 bit Jenkins hash. + //*************************************************************************** + struct jenkins_policy + { + typedef uint32_t value_type; + + inline uint32_t initial() + { + is_finalised = false; + + return 0; + } + + inline uint32_t add(value_type hash, uint8_t value) const + { + ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised)); + + hash += value; + hash += (hash << 10); + hash ^= (hash >> 6); + + return hash; + } + + inline uint32_t final(value_type hash) + { + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + is_finalised = true; + + return hash; + } + + bool is_finalised; + }; + + //************************************************************************* + /// jenkins + //************************************************************************* + class jenkins : public etl::frame_check_sequence<etl::jenkins_policy> + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + jenkins() + { + this->reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + jenkins(TIterator begin, const TIterator end) + { + this->reset(); + this->add(begin, end); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/largest.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,229 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -olargest.h -DNTypes=<n> largest_generator.h +// Where <n> is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_LARGEST__ +#define __ETL_LARGEST__ + +///\defgroup largest largest +///\ingroup utilities + +#include "platform.h" +#include "type_traits.h" +#include "smallest.h" +#include "static_assert.h" + +namespace etl +{ + //*************************************************************************** + /// Template to determine the largest type and size. + /// Supports up to 16 types. + /// Defines 'value_type' which is the type of the largest parameter. + /// Defines 'size' which is the size of the largest parameter. + ///\ingroup largest + //*************************************************************************** + template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void> + struct largest_type + { + // Define 'largest_other' as 'largest_type' with all but the first parameter. + typedef typename largest_type<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type largest_other; + + // Set 'type' to be the largest of the first parameter and any of the others. + // This is recursive. + typedef typename etl::conditional<(sizeof(T1) > sizeof(largest_other)), // Boolean + T1, // TrueType + largest_other> // FalseType + ::type type; // The largest type of the two. + + // The size of the largest type. + enum + { + size = sizeof(type) + }; + }; + + //*************************************************************************** + // Specialisation for one template parameter. + //*************************************************************************** + template <typename T1> + struct largest_type<T1, void, void, void, void, void, void, void, + void, void, void, void, void, void, void, void> + { + typedef T1 type; + + enum + { + size = sizeof(type) + }; + }; + + //*************************************************************************** + /// Template to determine the largest alignment. + /// Supports up to 16 types. + /// Defines <b>value</b> which is the largest alignment of all the parameters. + ///\ingroup largest + //*************************************************************************** + template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void> + struct largest_alignment + { + // Define 'largest_other' as 'largest_type' with all but the first parameter. + typedef typename largest_alignment<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type largest_other; + + // Set 'type' to be the largest of the first parameter and any of the others. + // This is recursive. + typedef typename etl::conditional<(etl::alignment_of<T1>::value > etl::alignment_of<largest_other>::value), // Boolean + T1, // TrueType + largest_other> // FalseType + ::type type; // The largest type of the two. + + // The largest alignment. + enum + { + value = etl::alignment_of<type>::value + }; + }; + + //*************************************************************************** + // Specialisation for one template parameter. + //*************************************************************************** + template <typename T1> + struct largest_alignment<T1, void, void, void, void, void, void, void, + void, void, void, void, void, void, void, void> + { + typedef T1 type; + + enum + { + value = etl::alignment_of<type>::value + }; + }; + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + ///\ingroup largest + //*************************************************************************** + template <typename T> + struct larger_int_type + { + STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type"); + + typedef typename etl::smallest_int_for_bits<etl::integral_limits<typename etl::make_signed<T>::type>::bits + 1>::type type; + }; + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + ///\ingroup largest + //*************************************************************************** + template <typename T> + struct larger_uint_type + { + STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type"); + + typedef typename etl::smallest_uint_for_bits<etl::integral_limits<typename etl::make_unsigned<T>::type>::bits + 1>::type type; + }; + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + /// The returned type will be of the same sign. + ///\ingroup largest + //*************************************************************************** + template <typename T, bool IS_SIGNED = etl::is_signed<T>::value> + struct larger_type; + + template <typename T> + struct larger_type<T, false> + { + STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type"); + + typedef typename etl::smallest_uint_for_bits<etl::integral_limits<T>::bits + 1>::type type; + }; + + template <typename T> + struct larger_type<T, true> + { + STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type"); + + typedef typename etl::smallest_int_for_bits<etl::integral_limits<T>::bits + 1>::type type; + }; + + //*************************************************************************** + /// Template to determine the largest type, size and alignment. + /// Supports up to 16 types. + /// Defines <b>value</b> which is the largest type, size and alignment of all the parameters. + ///\ingroup largest + //*************************************************************************** + template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void> + struct largest + { + typedef typename etl::largest_type<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type type; + + enum + { + size = etl::largest_type<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size, + alignment = etl::largest_alignment<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value + }; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/largest_generator.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,302 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -olargest.h -DNTypes=<n> largest_generator.h +// Where <n> is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_LARGEST__ +#define __ETL_LARGEST__ + +///\defgroup largest largest +///\ingroup utilities + +#include "platform.h" +#include "type_traits.h" +#include "smallest.h" +#include "static_assert.h" + +namespace etl +{ + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the largest type and size.") + cog.outl("/// Supports up to %s types." % NTypes) + cog.outl("/// Defines 'value_type' which is the type of the largest parameter.") + cog.outl("/// Defines 'size' which is the size of the largest parameter.") + cog.outl("///\ingroup largest") + cog.outl("//***************************************************************************") + cog.out("template <typename T1, ") + for n in range(2, int(NTypes)): + cog.out("typename T%s = void, " % n) + if n % 4 == 0: + cog.outl("") + cog.out(" ") + cog.outl("typename T%s = void>" % int(NTypes)) + cog.outl("struct largest_type") + cog.outl("{") + cog.outl(" // Define 'largest_other' as 'largest_type' with all but the first parameter. ") + cog.out(" typedef typename largest_type<") + for n in range(2, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type largest_other;" % int(NTypes)) + cog.outl("") + cog.outl(" // Set 'type' to be the largest of the first parameter and any of the others.") + cog.outl(" // This is recursive.") + cog.outl(" typedef typename etl::conditional<(sizeof(T1) > sizeof(largest_other)), // Boolean") + cog.outl(" T1, // TrueType") + cog.outl(" largest_other> // FalseType") + cog.outl(" ::type type; // The largest type of the two.") + cog.outl("") + cog.outl(" // The size of the largest type.") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for one template parameter.") + cog.outl("//***************************************************************************") + cog.outl("template <typename T1>") + cog.out("struct largest_type<T1, ") + for n in range(2, int(NTypes)): + cog.out("void, ") + if n % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl("void>") + cog.outl("{") + cog.outl(" typedef T1 type;") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the largest alignment.") + cog.outl("/// Supports up to %s types." % int(NTypes)) + cog.outl("/// Defines <b>value</b> which is the largest alignment of all the parameters.") + cog.outl("///\ingroup largest") + cog.outl("//***************************************************************************") + cog.out("template <typename T1, ") + for n in range(2, int(NTypes)): + cog.out("typename T%s = void, " % n) + if n % 4 == 0: + cog.outl("") + cog.out(" ") + cog.outl("typename T%s = void>" % int(NTypes)) + cog.outl("struct largest_alignment") + cog.outl("{") + cog.outl(" // Define 'largest_other' as 'largest_type' with all but the first parameter. ") + cog.out(" typedef typename largest_alignment<") + for n in range(2, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type largest_other;" % int(NTypes)) + cog.outl("") + cog.outl(" // Set 'type' to be the largest of the first parameter and any of the others.") + cog.outl(" // This is recursive.") + cog.outl(" typedef typename etl::conditional<(etl::alignment_of<T1>::value > etl::alignment_of<largest_other>::value), // Boolean") + cog.outl(" T1, // TrueType") + cog.outl(" largest_other> // FalseType") + cog.outl(" ::type type; // The largest type of the two.") + cog.outl("") + cog.outl(" // The largest alignment.") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" value = etl::alignment_of<type>::value") + cog.outl(" };") + cog.outl("};") + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for one template parameter.") + cog.outl("//***************************************************************************") + cog.outl("template <typename T1>") + cog.out("struct largest_alignment<T1, ") + for n in range(2, int(NTypes)): + cog.out("void, ") + if n % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl("void>") + cog.outl("{") + cog.outl(" typedef T1 type;") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" value = etl::alignment_of<type>::value") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + ///\ingroup largest + //*************************************************************************** + template <typename T> + struct larger_int_type + { + STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type"); + + typedef typename etl::smallest_int_for_bits<etl::integral_limits<typename etl::make_signed<T>::type>::bits + 1>::type type; + }; + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + ///\ingroup largest + //*************************************************************************** + template <typename T> + struct larger_uint_type + { + STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type"); + + typedef typename etl::smallest_uint_for_bits<etl::integral_limits<typename etl::make_unsigned<T>::type>::bits + 1>::type type; + }; + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + /// The returned type will be of the same sign. + ///\ingroup largest + //*************************************************************************** + template <typename T, bool IS_SIGNED = etl::is_signed<T>::value> + struct larger_type; + + template <typename T> + struct larger_type<T, false> + { + STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type"); + + typedef typename etl::smallest_uint_for_bits<etl::integral_limits<T>::bits + 1>::type type; + }; + + template <typename T> + struct larger_type<T, true> + { + STATIC_ASSERT(etl::is_integral<T>::value, "Must be an integral type"); + + typedef typename etl::smallest_int_for_bits<etl::integral_limits<T>::bits + 1>::type type; + }; + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the largest type, size and alignment.") + cog.outl("/// Supports up to %s types." % NTypes) + cog.outl("/// Defines <b>value</b> which is the largest type, size and alignment of all the parameters.") + cog.outl("///\ingroup largest") + cog.outl("//***************************************************************************") + cog.out("template <typename T1, ") + for n in range(2, int(NTypes)): + cog.out("typename T%s = void, " % n) + if n % 4 == 0: + cog.outl("") + cog.out(" ") + cog.outl("typename T%s = void>" % NTypes) + cog.outl("struct largest") + cog.outl("{") + cog.out(" typedef typename etl::largest_type<") + for n in range(1, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type type;" % NTypes) + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.out(" size = etl::largest_type<") + for n in range(1, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::size," % NTypes) + cog.out(" alignment = etl::largest_alignment<") + for n in range(1, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::value" % NTypes) + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/list.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1736 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_LIST__ +#define __ETL_LIST__ + +#include <iterator> +#include <algorithm> +#include <functional> +#include <stddef.h> + +#include "platform.h" +#include "container.h" +#include "pool.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "nullptr.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "algorithm.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#undef ETL_FILE +#define ETL_FILE "7" + +//***************************************************************************** +///\defgroup list list +/// A linked list with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the list. + ///\ingroup list + //*************************************************************************** + class list_exception : public exception + { + public: + + list_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the list. + ///\ingroup list + //*************************************************************************** + class list_full : public list_exception + { + public: + + list_full(string_type file_name_, numeric_type line_number_) + : list_exception(ETL_ERROR_TEXT("list:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Empty exception for the list. + ///\ingroup list + //*************************************************************************** + class list_empty : public list_exception + { + public: + + list_empty(string_type file_name_, numeric_type line_number_) + : list_exception(ETL_ERROR_TEXT("list:empty", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the list. + ///\ingroup list + //*************************************************************************** + class list_iterator : public list_exception + { + public: + + list_iterator(string_type file_name_, numeric_type line_number_) + : list_exception(ETL_ERROR_TEXT("list:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Unsorted exception for the list. + ///\ingroup list + //*************************************************************************** + class list_unsorted : public list_exception + { + public: + + list_unsorted(string_type file_name_, numeric_type line_number_) + : list_exception(ETL_ERROR_TEXT("list:unsorted", ETL_FILE"D"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for all lists. + ///\ingroup list + //*************************************************************************** + class list_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of list. + + //************************************************************************* + /// The node element in the list. + //************************************************************************* + struct node_t + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + node_t() + : previous(std::nullptr), + next(std::nullptr) + { + } + + //*********************************************************************** + /// Reverses the previous & next pointers. + //*********************************************************************** + inline void reverse() + { + std::swap(previous, next); + } + + node_t* previous; + node_t* next; + }; + + //************************************************************************* + /// Reverses the list. + //************************************************************************* + void reverse() + { + if (is_trivial_list()) + { + return; + } + + node_t* p_node = terminal_node.next; + + while (p_node != &terminal_node) + { + node_t* p_temp = p_node->previous; + p_node->previous = p_node->next; + p_node->next = p_temp; + p_node = p_node->previous; + } + + // Terminal node. + node_t* p_temp = p_node->previous; + p_node->previous = p_node->next; + p_node->next = p_temp; + } + + //************************************************************************* + /// Gets the maximum possible size of the list. + //************************************************************************* + size_type max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Gets the size of the list. + //************************************************************************* + size_type size() const + { + return p_node_pool->size(); + } + + //************************************************************************* + /// Checks to see if the list is empty. + //************************************************************************* + bool empty() const + { + return p_node_pool->empty(); + } + + //************************************************************************* + /// Checks to see if the list is full. + //************************************************************************* + bool full() const + { + return p_node_pool->size() == MAX_SIZE; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + //************************************************************************* + /// Is the list a trivial length? + //************************************************************************* + bool is_trivial_list() const + { + return (size() < 2); + } + + protected: + + //************************************************************************* + /// Get the head node. + //************************************************************************* + node_t& get_head() + { + return *terminal_node.next; + } + + //************************************************************************* + /// Get the head node. + //************************************************************************* + const node_t& get_head() const + { + return *terminal_node.next; + } + + //************************************************************************* + /// Get the tail node. + //************************************************************************* + node_t& get_tail() + { + return *terminal_node.previous; + } + + //************************************************************************* + /// Get the tail node. + //************************************************************************* + const node_t& get_tail() const + { + return *terminal_node.previous; + } + + //************************************************************************* + /// Insert a node before 'position'. + //************************************************************************* + void insert_node(node_t& position, node_t& node) + { + // Connect to the list. + join(*position.previous, node); + join(node, position); + } + + //************************************************************************* + /// Join two nodes. + //************************************************************************* + void join(node_t& left, node_t& right) + { + left.next = &right; + right.previous = &left; + } + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + list_base(etl::ipool& node_pool_, size_type max_size_) + : p_node_pool(&node_pool_), + MAX_SIZE(max_size_) + + { + } + + etl::ipool* p_node_pool; ///< The pool of data nodes used in the list. + node_t terminal_node; ///< The node that acts as the list start and end. + const size_type MAX_SIZE; ///< The maximum size of the list. + etl::debug_count construct_count; ///< Internal debugging. + }; + + //*************************************************************************** + /// A templated base for all etl::list types. + ///\ingroup list + //*************************************************************************** + template <typename T> + class ilist : public etl::list_base + { + public: + + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + + protected: + + typedef typename etl::parameter_type<T>::type parameter_t; + + //************************************************************************* + /// The data node element in the list. + //************************************************************************* + struct data_node_t : public node_t + { + explicit data_node_t(parameter_t value_) + : value(value_) + { + } + + T value; + }; + + private: + + //************************************************************************* + /// Downcast a node_t* to a data_node_t* + //************************************************************************* + static data_node_t* data_cast(node_t* p_node) + { + return reinterpret_cast<data_node_t*>(p_node); + } + + //************************************************************************* + /// Downcast a node_t& to a data_node_t& + //************************************************************************* + static data_node_t& data_cast(node_t& node) + { + return reinterpret_cast<data_node_t&>(node); + } + + //************************************************************************* + /// Downcast a const node_t* to a const data_node_t* + //************************************************************************* + static const data_node_t* data_cast(const node_t* p_node) + { + return reinterpret_cast<const data_node_t*>(p_node); + } + + //************************************************************************* + /// Downcast a const node_t& to a const data_node_t& + //************************************************************************* + static const data_node_t& data_cast(const node_t& node) + { + return reinterpret_cast<const data_node_t&>(node); + } + + public: + + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, T> + { + public: + + friend class ilist; + + iterator() + : p_node(nullptr) + { + } + + iterator(node_t& node) + : p_node(&node) + { + } + + iterator(const iterator& other) + : p_node(other.p_node) + { + } + + iterator& operator ++() + { + p_node = p_node->next; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_node = p_node->next; + return temp; + } + + iterator& operator --() + { + p_node = p_node->previous; + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + p_node = p_node->previous; + return temp; + } + + iterator operator =(const iterator& other) + { + p_node = other.p_node; + return *this; + } + + reference operator *() + { + return ilist::data_cast(p_node)->value; + } + + const_reference operator *() const + { + return ilist::data_cast(p_node)->value; + } + + pointer operator &() + { + return &(ilist::data_cast(p_node)->value); + } + + const_pointer operator &() const + { + return &(ilist::data_cast(p_node)->value); + } + + pointer operator ->() + { + return &(ilist::data_cast(p_node)->value); + } + + const_pointer operator ->() const + { + return &(ilist::data_cast(p_node)->value); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_node == rhs.p_node; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + node_t* p_node; + }; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const T> + { + public: + + friend class ilist; + + const_iterator() + : p_node(nullptr) + { + } + + const_iterator(node_t& node) + : p_node(&node) + { + } + + const_iterator(const node_t& node) + : p_node(&node) + { + } + + const_iterator(const typename ilist::iterator& other) + : p_node(other.p_node) + { + } + + const_iterator(const const_iterator& other) + : p_node(other.p_node) + { + } + + const_iterator& operator ++() + { + p_node = p_node->next; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_node = p_node->next; + return temp; + } + + const_iterator& operator --() + { + p_node = p_node->previous; + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + p_node = p_node->previous; + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return ilist::data_cast(p_node)->value; + } + + const_pointer operator &() const + { + return &(ilist::data_cast(p_node)->value); + } + + const_pointer operator ->() const + { + return &(ilist::data_cast(p_node)->value); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_node == rhs.p_node; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + const node_t* p_node; + }; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + //************************************************************************* + /// Gets the beginning of the list. + //************************************************************************* + iterator begin() + { + return iterator(get_head()); + } + + //************************************************************************* + /// Gets the beginning of the list. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(get_head()); + } + + //************************************************************************* + /// Gets the end of the list. + //************************************************************************* + iterator end() + { + return iterator(terminal_node); + } + + //************************************************************************* + /// Gets the end of the list. + //************************************************************************* + const_iterator end() const + { + return const_iterator(static_cast<const data_node_t&>(terminal_node)); + } + + //************************************************************************* + /// Gets the beginning of the list. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(get_head()); + } + + //************************************************************************* + /// Gets the end of the list. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(static_cast<const data_node_t&>(terminal_node)); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(terminal_node); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(static_cast<const data_node_t&>(terminal_node)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(get_head()); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(static_cast<const data_node_t&>(terminal_node)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(get_head()); + } + + //************************************************************************* + /// Gets a reference to the first element. + //************************************************************************* + reference front() + { + return data_cast(get_head()).value; + } + + //************************************************************************* + /// Gets a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return data_cast(get_head()).value; + } + + //************************************************************************* + /// Gets a reference to the last element. + //************************************************************************* + reference back() + { + return data_cast(get_tail()).value; + } + + //************************************************************************* + /// Gets a reference to the last element. + //************************************************************************* + const_reference back() const + { + return data_cast(get_tail()).value; + } + + //************************************************************************* + /// Assigns a range of values to the list. + /// If asserts or exceptions are enabled throws etl::list_full if the list does not have enough free space. + /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined throws list_iterator if the iterators are reversed. + //************************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d >= 0, ETL_ERROR(list_iterator)); + ETL_ASSERT(size_t(d) <= MAX_SIZE, ETL_ERROR(list_full)); +#endif + initialise(); + + // Add all of the elements. + while (first != last) + { + data_node_t& node = allocate_data_node(*first); + join(get_tail(), node); + join(node, terminal_node); + ++first; + } + } + + //************************************************************************* + /// Assigns 'n' copies of a value to the list. + //************************************************************************* + void assign(size_t n, parameter_t value) + { +#if defined(ETL_DEBUG) + ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(list_full)); +#endif + + initialise(); + + // Add all of the elements. + while (size() < n) + { + data_node_t& node = allocate_data_node(value); + join(*terminal_node.previous, node); + join(node, terminal_node); + } + } + + //************************************************************************* + /// Adds a node to the front of the list so a new value can be assigned to front(). + //************************************************************************* + void push_front() + { + push_front(T()); + } + + //************************************************************************* + /// Pushes a value to the front of the list. + //************************************************************************* + void push_front(parameter_t value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + insert_node(get_head(), allocate_data_node(value)); + } + + //************************************************************************* + /// Emplaces a value to the front of the list.. + //************************************************************************* + template <typename T1> + void emplace_front(const T1& value1) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1); + ++construct_count; + insert_node(get_head(), *p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the front of the list.. + //************************************************************************* + template <typename T1, typename T2> + void emplace_front(const T1& value1, const T2& value2) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2); + ++construct_count; + insert_node(get_head(), *p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the front of the list.. + //************************************************************************* + template <typename T1, typename T2, typename T3> + void emplace_front(const T1& value1, const T2& value2, const T3& value3) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3); + ++construct_count; + insert_node(get_head(), *p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the front of the list.. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + void emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3, value4); + ++construct_count; + insert_node(get_head(), *p_data_node); + } + + //************************************************************************* + /// Removes a value from the front of the list. + //************************************************************************* + void pop_front() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(list_empty)); +#endif + node_t& node = get_head(); + remove_node(node); + } + + //************************************************************************* + /// Adds a node to the back of the list so a new value can be assigned to back(). + //************************************************************************* + void push_back() + { + push_back(T()); + } + + //************************************************************************* + /// Pushes a value to the back of the list.. + //************************************************************************* + void push_back(parameter_t value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + insert_node(terminal_node, allocate_data_node(value)); + } + + //************************************************************************* + /// Emplaces a value to the back of the list.. + //************************************************************************* + template <typename T1> + void emplace_back(const T1& value1) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1); + ++construct_count; + insert_node(terminal_node, *p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the back of the list.. + //************************************************************************* + template <typename T1, typename T2> + void emplace_back(const T1& value1, const T2& value2) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2); + ++construct_count; + insert_node(terminal_node, *p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the back of the list.. + //************************************************************************* + template <typename T1, typename T2, typename T3> + void emplace_back(const T1& value1, const T2& value2, const T3& value3) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3); + ++construct_count; + insert_node(terminal_node, *p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the back of the list.. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + void emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(list_full)); +#endif + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3, value4); + ++construct_count; + insert_node(terminal_node, *p_data_node); + } + + //************************************************************************* + /// Removes a value from the back of the list. + //************************************************************************* + void pop_back() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(list_empty)); +#endif + node_t& node = get_tail(); + remove_node(node); + } + + //************************************************************************* + /// Inserts a value to the list at the specified position. + //************************************************************************* + iterator insert(iterator position, const value_type& value) + { + ETL_ASSERT(!full(), ETL_ERROR(list_full)); + + data_node_t& data_node = allocate_data_node(value); + insert_node(*position.p_node, data_node); + + return iterator(data_node); + } + + //************************************************************************* + /// Emplaces a value to the list at the specified position. + //************************************************************************* + template <typename T1> + iterator emplace(iterator position, const T1& value1) + { + ETL_ASSERT(!full(), ETL_ERROR(list_full)); + + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1); + ++construct_count; + insert_node(*position.p_node, *p_data_node); + + return iterator(*p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the list at the specified position. + //************************************************************************* + template <typename T1, typename T2> + iterator emplace(iterator position, const T1& value1, const T2& value2) + { + ETL_ASSERT(!full(), ETL_ERROR(list_full)); + + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2); + ++construct_count; + insert_node(*position.p_node, *p_data_node); + + return iterator(*p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the list at the specified position. + //************************************************************************* + template <typename T1, typename T2, typename T3> + iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3) + { + ETL_ASSERT(!full(), ETL_ERROR(list_full)); + + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3); + ++construct_count; + insert_node(*position.p_node, *p_data_node); + + return iterator(*p_data_node); + } + + //************************************************************************* + /// Emplaces a value to the list at the specified position. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + ETL_ASSERT(!full(), ETL_ERROR(list_full)); + + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value1, value2, value3, value4); + ++construct_count; + insert_node(*position.p_node, *p_data_node); + + return iterator(*p_data_node); + } + + //************************************************************************* + /// Inserts 'n' copies of a value to the list at the specified position. + //************************************************************************* + void insert(iterator position, size_t n, const value_type& value) + { + for (size_t i = 0; i < n; ++i) + { + ETL_ASSERT(!full(), ETL_ERROR(list_full)); + + // Set up the next free node and insert. + insert_node(*position.p_node, allocate_data_node(value)); + } + } + + //************************************************************************* + /// Inserts a range of values to the list at the specified position. + //************************************************************************* + template <typename TIterator> + void insert(iterator position, TIterator first, TIterator last) + { + while (first != last) + { + ETL_ASSERT(!full(), ETL_ERROR(list_full)); + + // Set up the next free node and insert. + insert_node(*position.p_node, allocate_data_node(*first++)); + } + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase(iterator position) + { + ++position; + remove_node(*position.p_node->previous); + return position; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(iterator first, iterator last) + { + node_t* p_first = first.p_node; + node_t* p_last = last.p_node; + node_t* p_next; + + // Join the ends. + join(*(p_first->previous), *p_last); + + // Erase the ones in between. + while (p_first != p_last) + { + p_next = p_first->next; // Remember the next node. + destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the current node. + p_first = p_next; // Move to the next node. + } + + return last; + } + + //************************************************************************* + /// Resizes the list. + //************************************************************************* + void resize(size_t n) + { + resize(n, T()); + } + + //************************************************************************* + /// Resizes the list. + //************************************************************************* + void resize(size_t n, parameter_t value) + { + ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(list_full)); + + // Smaller? + if (n < size()) + { + iterator i_start = end(); + std::advance(i_start, -difference_type(size() - n)); + erase(i_start, end()); + } + // Larger? + else if (n > size()) + { + insert(end(), n - size(), value); + } + } + + //************************************************************************* + /// Clears the list. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + // Removes the values specified. + //************************************************************************* + void remove(const value_type& value) + { + iterator iValue = begin(); + + while (iValue != end()) + { + if (value == *iValue) + { + iValue = erase(iValue); + } + else + { + ++iValue; + } + } + } + + //************************************************************************* + /// Removes according to a predicate. + //************************************************************************* + template <typename TPredicate> + void remove_if(TPredicate predicate) + { + iterator iValue = begin(); + + while (iValue != end()) + { + if (predicate(*iValue)) + { + iValue = erase(iValue); + } + else + { + ++iValue; + } + } + } + + //************************************************************************* + /// Removes all but the first element from every consecutive group of equal + /// elements in the container. + //************************************************************************* + void unique() + { + unique(std::equal_to<T>()); + } + + //************************************************************************* + /// Removes all but the first element from every consecutive group of equal + /// elements in the container. + //************************************************************************* + template <typename TIsEqual> + void unique(TIsEqual isEqual) + { + if (empty()) + { + return; + } + + iterator i_item = begin(); + ++i_item; + iterator i_previous = begin(); + + while (i_item != end()) + { + if (isEqual(*i_previous, *i_item)) + { + i_item = erase(i_item); + } + else + { + i_previous = i_item; + ++i_item; + } + } + } + + //************************************************************************* + /// Splices from another list to this. + //************************************************************************* + void splice(iterator to, ilist& other) + { + if (&other != this) + { + insert(to, other.begin(), other.end()); + other.erase(other.begin(), other.end()); + } + } + + //************************************************************************* + /// Splices an element from another list to this. + //************************************************************************* + void splice(iterator to, ilist& other, iterator from) + { + if (&other == this) + { + // Internal move. + move(to, from); + } + else + { + // From another list. + insert(to, *from); + other.erase(from); + } + } + + //************************************************************************* + /// Splices a range of elements from another list to this. + //************************************************************************* + void splice(iterator to, ilist& other, iterator first, iterator last) + { + if (&other == this) + { + // Internal move. + move(to, first, last); + } + else + { + // From another list. + insert(to, first, last); + other.erase(first, last); + } + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + void merge(ilist& other) + { + merge(other, std::less<value_type>()); + } + + //************************************************************************* + /// Merge another list into this one. Both lists should be sorted. + //************************************************************************* + template <typename TCompare> + void merge(ilist& other, TCompare compare) + { + if (!other.empty()) + { +#if defined(ETL_DEBUG) + ETL_ASSERT(etl::is_sorted(other.begin(), other.end(), compare), ETL_ERROR(list_unsorted)); + ETL_ASSERT(etl::is_sorted(begin(), end(), compare), ETL_ERROR(list_unsorted)); +#endif + + ilist::iterator other_begin = other.begin(); + ilist::iterator other_end = other.end(); + + ilist::iterator this_begin = begin(); + ilist::iterator this_end = end(); + + while ((this_begin != this_end) && (other_begin != other_end)) + { + // Find the place to insert. + while ((this_begin != this_end) && !(compare(*other_begin, *this_begin))) + { + ++this_begin; + } + + // Insert. + if (this_begin != this_end) + { + while ((other_begin != other_end) && (compare(*other_begin, *this_begin))) + { + insert(this_begin, *other_begin); + ++other_begin; + } + } + } + + // Any left over? + if ((this_begin == this_end) && (other_begin != other_end)) + { + insert(this_end, other_begin, other_end); + } + + other.clear(); + } + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + /// Uses 'less-than operator as the predicate. + //************************************************************************* + void sort() + { + sort(std::less<T>()); + } + + //************************************************************************* + /// Sort using in-place merge sort algorithm. + /// Uses a supplied predicate function or functor. + /// This is not my algorithm. I got it off the web somewhere. + //************************************************************************* + template <typename TCompare> + void sort(TCompare compare) + { + iterator i_left; + iterator i_right; + iterator i_node; + iterator i_head; + iterator i_tail; + int list_size = 1; + int number_of_merges; + int left_size; + int right_size; + + if (is_trivial_list()) + { + return; + } + + while (true) + { + i_left = begin(); + i_head = end(); + i_tail = end(); + + number_of_merges = 0; // Count the number of merges we do in this pass. + + while (i_left != end()) + { + ++number_of_merges; // There exists a merge to be done. + i_right = i_left; + left_size = 0; + + // Step 'list_size' places along from left + for (int i = 0; i < list_size; ++i) + { + ++left_size; + ++i_right; + + if (i_right == end()) + { + break; + } + } + + // If right hasn't fallen off end, we have two lists to merge. + right_size = list_size; + + // Now we have two lists. Merge them. + while (left_size > 0 || (right_size > 0 && i_right != end())) + { + // Decide whether the next node of merge comes from left or right. + if (left_size == 0) + { + // Left is empty. The node must come from right. + i_node = i_right++; + --right_size; + } + else if (right_size == 0 || i_right == end()) + { + // Right is empty. The node must come from left. + i_node = i_left++; + --left_size; + } + else if (!compare(*i_right, *i_left)) + { + // First node of left is lower or same. The node must come from left. + i_node = i_left++; + --left_size; + } + else + { + // First node of right is lower. The node must come from right. + i_node = i_right; + ++i_right; + --right_size; + } + + // Add the next node to the merged head. + if (i_head == end()) + { + join(*i_head.p_node, *i_node.p_node); + i_head = i_node; + i_tail = i_node; + } + else + { + join(*i_tail.p_node, *i_node.p_node); + i_tail = i_node; + } + + join(*i_tail.p_node, terminal_node); + } + + // Now left has stepped `list_size' places along, and right has too. + i_left = i_right; + } + + // If we have done only one merge, we're finished. + if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case + { + return; + } + + // Otherwise repeat, merging lists twice the size + list_size *= 2; + } + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + ilist& operator = (const ilist& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + ilist(etl::ipool& node_pool, size_t max_size_) + : list_base(node_pool, max_size_) + { + } + + //************************************************************************* + /// Initialise the list. + //************************************************************************* + void initialise() + { + if (!empty()) + { + node_t* p_first = terminal_node.next; + node_t* p_last = &terminal_node; + + while (p_first != p_last) + { + destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the current node. + p_first = p_first->next; // Move to the next node. + } + } + + join(terminal_node, terminal_node); + } + + private: + + //************************************************************************* + /// Moves an element from one position to another within the list. + /// Moves the element at position 'from' to the position before 'to'. + //************************************************************************* + void move(iterator to, iterator from) + { + if (from == to) + { + return; // Can't more to before yourself! + } + + node_t& from_node = *from.p_node; + node_t& to_node = *to.p_node; + + // Disconnect the node from the list. + join(*from_node.previous, *from_node.next); + + // Attach it to the new position. + join(*to_node.previous, from_node); + join(from_node, to_node); + } + + //************************************************************************* + /// Moves a range from one position to another within the list. + /// Moves a range at position 'first'/'last' to the position before 'to'. + //************************************************************************* + void move(iterator to, iterator first, iterator last) + { + if ((first == to) || (last == to)) + { + return; // Can't more to before yourself! + } + +#if defined(ETL_DEBUG) + // Check that we are not doing an illegal move! + for (const_iterator item = first; item != last; ++item) + { + ETL_ASSERT(item != to, ETL_ERROR(list_iterator)); + } +#endif + + node_t& first_node = *first.p_node; + node_t& last_node = *last.p_node; + node_t& to_node = *to.p_node; + node_t& final_node = *last_node.previous; + + // Disconnect the range from the list. + join(*first_node.previous, last_node); + + // Attach it to the new position. + join(*to_node.previous, first_node); + join(final_node, to_node); + } + + //************************************************************************* + /// Remove a node. + //************************************************************************* + void remove_node(node_t& node) + { + // Disconnect the node from the list. + join(*node.previous, *node.next); + + // Destroy the pool object. + destroy_data_node(static_cast<data_node_t&>(node)); + } + + //************************************************************************* + /// Allocate a data_node_t. + //************************************************************************* + data_node_t& allocate_data_node(parameter_t value) + { + data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); + ::new (&(p_data_node->value)) T(value); + ++construct_count; + + return *p_data_node; + } + + //************************************************************************* + /// Destroy a data_node_t. + //************************************************************************* + void destroy_data_node(data_node_t& node) + { + node.value.~T(); + p_node_pool->release(&node); + --construct_count; + } + + // Disable copy construction. + ilist(const ilist&); + }; + + //************************************************************************* + /// A templated list implementation that uses a fixed size buffer. + ///\note 'merge' and 'splice' and are not supported. + //************************************************************************* + template <typename T, const size_t MAX_SIZE_> + class list : public etl::ilist<T> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + public: + + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + list() + : etl::ilist<T>(node_pool, MAX_SIZE) + { + etl::ilist<T>::initialise(); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~list() + { + etl::ilist<T>::initialise(); + } + + //************************************************************************* + /// Construct from size. + //************************************************************************* + explicit list(size_t initial_size) + : etl::ilist<T>(node_pool, MAX_SIZE) + { + etl::ilist<T>::assign(initial_size, T()); + } + + //************************************************************************* + /// Construct from size and value. + //************************************************************************* + list(size_t initial_size, typename ilist<T>::parameter_t value) + : etl::ilist<T>(node_pool, MAX_SIZE) + { + etl::ilist<T>::assign(initial_size, value); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + list(const list& other) + : etl::ilist<T>(node_pool, MAX_SIZE) + { + if (this != &other) + { + etl::ilist<T>::assign(other.cbegin(), other.cend()); + } + } + + //************************************************************************* + /// Construct from range. + //************************************************************************* + template <typename TIterator> + list(TIterator first, TIterator last) + : ilist<T>(node_pool, MAX_SIZE) + { + etl::ilist<T>::assign(first, last); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + list& operator = (const list& rhs) + { + if (&rhs != this) + { + etl::ilist<T>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of nodes used in the list. + etl::pool<typename etl::ilist<T>::data_node_t, MAX_SIZE> node_pool; + }; +} + +//************************************************************************* +/// Equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator ==(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs) +{ + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +//************************************************************************* +/// Not equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator !=(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs) +{ + return !(lhs == rhs); +} + +//************************************************************************* +/// Less than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator <(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); +} + +//************************************************************************* +/// Greater than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator >(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs) +{ + return (rhs < lhs); +} + +//************************************************************************* +/// Less than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than or equal +/// to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator <=(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs) +{ + return !(lhs > rhs); +} + +//************************************************************************* +/// Greater than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than or +/// equal to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename T> +bool operator >=(const etl::ilist<T>& lhs, const etl::ilist<T>& rhs) +{ + return !(lhs < rhs); +} + + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/log.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,116 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_LOG__ +#define __ETL_LOG__ + +#include <stddef.h> + +#include "platform.h" + +///\defgroup log log +/// log<N, BASE> : Calculates logs to any base, rounded down to the nearest integer.<br> +/// log2<N> : Calculates logs to base 2, rounded down to the nearest integer.<br> +/// log10<N> : Calculates logs to base 10, rounded down to the nearest integer.<br> +///\ingroup maths + +namespace etl +{ + //*************************************************************************** + ///\ingroup log + /// The base generic log template. + /// Defines <b>value</b> as the log of the number at the specified base. + /// The result is rounded down to the next integer. + ///\tparam NV The number to find the log of. + ///\tparam BASE The base of the log. + //*************************************************************************** + template <const size_t NV, const size_t BASE> + struct log + { + enum value_type + { + // Recursive definition. + value = (NV >= BASE) ? 1 + log<NV / BASE, BASE>::value : 0 + }; + }; + + //*************************************************************************** + // Specialisation for N = 1 + //*************************************************************************** + template <const size_t BASE> + struct log<1, BASE> + { + enum value_type + { + value = 0 + }; + }; + + //*************************************************************************** + // Specialisation for N = 0 + //*************************************************************************** + template <const size_t BASE> + struct log<0, BASE> + { + enum value_type + { + value = 0 + }; + }; + + //*************************************************************************** + ///\ingroup log + /// Calculates base 2 logs. + //*************************************************************************** + template <const size_t NV> + struct log2 + { + enum value_type + { + value = log<NV, 2>::value + }; + }; + + //*************************************************************************** + ///\ingroup log + /// Calculates base 10 logs. + //*************************************************************************** + template <const size_t NV> + struct log10 + { + enum value_type + { + value = log<NV, 10>::value + }; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/map.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,2160 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove, rlindeman + +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_MAP__ +#define __ETL_MAP__ + +#include <stddef.h> +#include <iterator> +#include <functional> +#include <iterator> +#include <algorithm> + +#include "platform.h" +#include "container.h" +#include "pool.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "nullptr.h" +#include "type_traits.h" +#include "parameter_type.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#undef ETL_FILE +#define ETL_FILE "8" + +//***************************************************************************** +///\defgroup map map +/// A map with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the map. + ///\ingroup map + //*************************************************************************** + class map_exception : public etl::exception + { + public: + + map_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the map. + ///\ingroup map + //*************************************************************************** + class map_full : public etl::map_exception + { + public: + + map_full(string_type file_name_, numeric_type line_number_) + : etl::map_exception("map:full", file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Map out of bounds exception. + ///\ingroup map + //*************************************************************************** + class map_out_of_bounds : public etl::map_exception + { + public: + + map_out_of_bounds(string_type file_name_, numeric_type line_number_) + : etl::map_exception("map:bounds", file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the map. + ///\ingroup map + //*************************************************************************** + class map_iterator : public etl::map_exception + { + public: + + map_iterator(string_type file_name_, numeric_type line_number_) + : etl::map_exception("map:iterator", file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for all maps. + ///\ingroup map + //*************************************************************************** + class map_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of map. + + //************************************************************************* + /// Gets the size of the map. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Gets the maximum possible size of the map. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + //************************************************************************* + /// Checks to see if the map is empty. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Checks to see if the map is full. + //************************************************************************* + bool full() const + { + return current_size == CAPACITY; + } + + //************************************************************************* + /// Returns the capacity of the vector. + ///\return The capacity of the vector. + //************************************************************************* + size_type capacity() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + enum + { + kLeft = 0, + kRight = 1, + kNeither = 2 + }; + + //************************************************************************* + /// The node element in the map. + //************************************************************************* + struct Node + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + Node() : + weight(uint_least8_t(kNeither)), + dir(uint_least8_t(kNeither)) + { + } + + ~Node() + { + + } + + //*********************************************************************** + /// Marks the node as a leaf. + //*********************************************************************** + void mark_as_leaf() + { + weight = uint_least8_t(kNeither); + dir = uint_least8_t(kNeither); + children[0] = std::nullptr; + children[1] = std::nullptr; + } + + Node* children[2]; + uint_least8_t weight; + uint_least8_t dir; + }; + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + map_base(size_type max_size_) + : current_size(0) + , CAPACITY(max_size_) + , root_node(std::nullptr) + + { + } + + //************************************************************************* + /// Balance the critical node at the position provided as needed + //************************************************************************* + void balance_node(Node*& critical_node) + { + // Step 1: Update weights for all children of the critical node up to the + // newly inserted node. This step is costly (in terms of traversing nodes + // multiple times during insertion) but doesn't require as much recursion + Node* weight_node = critical_node->children[critical_node->dir]; + while (weight_node) + { + // Keep going until we reach a terminal node (dir == kNeither) + if (uint_least8_t(kNeither) != weight_node->dir) + { + // Does this insert balance the previous weight factor value? + if (weight_node->weight == 1 - weight_node->dir) + { + weight_node->weight = uint_least8_t(kNeither); + } + else + { + weight_node->weight = weight_node->dir; + } + + // Update weight factor node to point to next node + weight_node = weight_node->children[weight_node->dir]; + } + else + { + // Stop loop, terminal node found + break; + } + } // while(weight_node) + + // Step 2: Update weight for critical_node or rotate tree to balance node + if (uint_least8_t(kNeither) == critical_node->weight) + { + critical_node->weight = critical_node->dir; + } + // If direction is different than weight, then it will now be balanced + else if (critical_node->dir != critical_node->weight) + { + critical_node->weight = uint_least8_t(kNeither); + } + // Rotate is required to balance the tree at the critical node + else + { + // If critical node matches child node direction then perform a two + // node rotate in the direction of the critical node + if (critical_node->weight == critical_node->children[critical_node->dir]->dir) + { + rotate_2node(critical_node, critical_node->dir); + } + // Otherwise perform a three node rotation in the direction of the + // critical node + else + { + rotate_3node(critical_node, critical_node->dir, + critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); + } + } + } + + //************************************************************************* + /// Rotate two nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_2node(Node*& position, uint_least8_t dir) + { + // A C A B + // B C -> A E OR B C -> D A + // D E B D D E E C + // C (new position) becomes the root + // A (position) takes ownership of D as its children[kRight] child + // C (new position) takes ownership of A as its left child + // OR + // B (new position) becomes the root + // A (position) takes ownership of E as its left child + // B (new position) takes ownership of A as its right child + + // Capture new root + Node* new_root = position->children[dir]; + // Replace position's previous child with new root's other child + position->children[dir] = new_root->children[1 - dir]; + // New root now becomes parent of current position + new_root->children[1 - dir] = position; + // Clear weight factor from current position + position->weight = uint_least8_t(kNeither); + // Newly detached right now becomes current position + position = new_root; + // Clear weight factor from new root + position->weight = uint_least8_t(kNeither); + } + + //************************************************************************* + /// Rotate three nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third) + { + // __A__ __E__ __A__ __D__ + // _B_ C -> B A OR B _C_ -> A C + // D E D F G C D E B F G E + // F G F G + // E (new position) becomes the root + // B (position) takes ownership of F as its left child + // A takes ownership of G as its right child + // OR + // D (new position) becomes the root + // A (position) takes ownership of F as its right child + // C takes ownership of G as its left child + + // Capture new root (either E or D depending on dir) + Node* new_root = position->children[dir]->children[1 - dir]; + // Set weight factor for B or C based on F or G existing and being a different than dir + position->children[dir]->weight = third != uint_least8_t(kNeither) && third != dir ? dir : uint_least8_t(kNeither); + + // Detach new root from its tree (replace with new roots child) + position->children[dir]->children[1 - dir] = + new_root->children[dir]; + // Attach current left tree to new root + new_root->children[dir] = position->children[dir]; + // Set weight factor for A based on F or G + position->weight = third != uint_least8_t(kNeither) && third == dir ? 1 - dir : uint_least8_t(kNeither); + + // Move new root's right tree to current roots left tree + position->children[dir] = new_root->children[1 - dir]; + // Attach current root to new roots right tree + new_root->children[1 - dir] = position; + // Replace current position with new root + position = new_root; + // Clear weight factor for new current position + position->weight = uint_least8_t(kNeither); + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* find_limit_node(Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + const Node* find_limit_node(const Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + const Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Attach the provided node to the position provided + //************************************************************************* + void attach_node(Node*& position, Node& node) + { + // Mark new node as leaf on attach to tree at position provided + node.mark_as_leaf(); + + // Add the node here + position = &node; + + // One more. + ++current_size; + } + + //************************************************************************* + /// Detach the node at the position provided + //************************************************************************* + void detach_node(Node*& position, Node*& replacement) + { + // Make temporary copy of actual nodes involved because we might lose + // their references in the process (e.g. position is the same as + // replacement or replacement is a child of position) + Node* detached = position; + Node* swap = replacement; + + // Update current position to point to swap (replacement) node first + position = swap; + + // Update replacement node to point to child in opposite direction + // otherwise we might lose the other child of the swap node + replacement = swap->children[1 - swap->dir]; + + // Point swap node to detached node's children and weight + swap->children[kLeft] = detached->children[kLeft]; + swap->children[kRight] = detached->children[kRight]; + swap->weight = detached->weight; + } + + size_type current_size; ///< The number of the used nodes. + const size_type CAPACITY; ///< The maximum size of the map. + Node* root_node; ///< The node that acts as the map root. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// A templated base for all etl::map types. + ///\ingroup map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + class imap : public etl::map_base + { + public: + + typedef TKey key_type; + typedef std::pair<const TKey, TMapped> value_type; + typedef TMapped mapped_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + //************************************************************************* + /// How to compare two key elements. + //************************************************************************* + struct key_comp + { + bool operator ()(const key_type& key1, const key_type& key2) const + { + return key_compare()(key1, key2); + } + }; + + //************************************************************************* + /// How to compare two value elements. + //************************************************************************* + struct value_comp + { + bool operator ()(const value_type& value1, const value_type& value2) const + { + return key_compare()(value1.first, value2.first); + } + }; + + protected: + + //************************************************************************* + /// The data node element in the map. + //************************************************************************* + struct Data_Node : public Node + { + explicit Data_Node(value_type value_) + : value(value_) + { + } + + ~Data_Node() + { + + } + + value_type value; + }; + + /// Defines the key value parameter type + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + //************************************************************************* + /// How to compare node elements. + //************************************************************************* + bool node_comp(const Data_Node& node1, const Data_Node& node2) const + { + return key_compare()(node1.value.first, node2.value.first); + } + bool node_comp(const Data_Node& node, key_parameter_t key) const + { + return key_compare()(node.value.first, key); + } + bool node_comp(key_parameter_t key, const Data_Node& node) const + { + return key_compare()(key, node.value.first); + } + + private: + + /// The pool of data nodes used in the map. + ipool* p_node_pool; + + //************************************************************************* + /// Downcast a Node* to a Data_Node* + //************************************************************************* + static Data_Node* data_cast(Node* p_node) + { + return static_cast<Data_Node*>(p_node); + } + + //************************************************************************* + /// Downcast a Node& to a Data_Node& + //************************************************************************* + static Data_Node& data_cast(Node& node) + { + return static_cast<Data_Node&>(node); + } + + //************************************************************************* + /// Downcast a const Node* to a const Data_Node* + //************************************************************************* + static const Data_Node* data_cast(const Node* p_node) + { + return static_cast<const Data_Node*>(p_node); + } + + //************************************************************************* + /// Downcast a const Node& to a const Data_Node& + //************************************************************************* + static const Data_Node& data_cast(const Node& node) + { + return static_cast<const Data_Node&>(node); + } + + public: + + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type> + { + public: + + friend class imap; + + iterator() + : p_map(std::nullptr) + , p_node(std::nullptr) + { + } + + iterator(imap& map) + : p_map(&map) + , p_node(std::nullptr) + { + } + + iterator(imap& map, Node* node) + : p_map(&map) + , p_node(node) + { + } + + iterator(const iterator& other) + : p_map(other.p_map) + , p_node(other.p_node) + { + } + + ~iterator() + { + } + + iterator& operator ++() + { + p_map->next_node(p_node); + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_map->next_node(p_node); + return temp; + } + + iterator& operator --() + { + p_map->prev_node(p_node); + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + p_map->prev_node(p_node); + return temp; + } + + iterator operator =(const iterator& other) + { + p_map = other.p_map; + p_node = other.p_node; + return *this; + } + + reference operator *() + { + return imap::data_cast(p_node)->value; + } + + const_reference operator *() const + { + return imap::data_cast(p_node)->value; + } + + pointer operator &() + { + return &(imap::data_cast(p_node)->value); + } + + const_pointer operator &() const + { + return &(imap::data_cast(p_node)->value); + } + + pointer operator ->() + { + return &(imap::data_cast(p_node)->value); + } + + const_pointer operator ->() const + { + return &(imap::data_cast(p_node)->value); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + // Pointer to map associated with this iterator + imap* p_map; + + // Pointer to the current node for this iterator + Node* p_node; + }; + + friend class iterator; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> + { + public: + + friend class imap; + + const_iterator() + : p_map(std::nullptr) + , p_node(std::nullptr) + { + } + + const_iterator(const imap& map) + : p_map(&map) + , p_node(std::nullptr) + { + } + + const_iterator(const imap& map, const Node* node) + : p_map(&map) + , p_node(node) + { + } + + const_iterator(const typename imap::iterator& other) + : p_map(other.p_map) + , p_node(other.p_node) + { + } + + const_iterator(const const_iterator& other) + : p_map(other.p_map) + , p_node(other.p_node) + { + } + + ~const_iterator() + { + } + + const_iterator& operator ++() + { + p_map->next_node(p_node); + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_map->next_node(p_node); + return temp; + } + + const_iterator& operator --() + { + p_map->prev_node(p_node); + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + p_map->prev_node(p_node); + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_map = other.p_map; + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return imap::data_cast(p_node)->value; + } + + const_pointer operator &() const + { + return imap::data_cast(p_node)->value; + } + + const_pointer operator ->() const + { + return &(imap::data_cast(p_node)->value); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_map == rhs.p_map && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + // Pointer to map associated with this iterator + const imap* p_map; + + // Pointer to the current node for this iterator + const Node* p_node; + }; + + friend class const_iterator; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + + //************************************************************************* + /// Gets the beginning of the map. + //************************************************************************* + iterator begin() + { + return iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the beginning of the map. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the end of the map. + //************************************************************************* + iterator end() + { + return iterator(*this); + } + + //************************************************************************* + /// Gets the end of the map. + //************************************************************************* + const_iterator end() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the beginning of the map. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the end of the map. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft))); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft))); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft))); + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& operator [](key_parameter_t key) + { + iterator i_element = find(key); + + if (!i_element.p_node) + { + // Doesn't exist, so create a new one. + i_element = insert(std::make_pair(key, mapped_type())).first; + } + + return i_element->second; + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::lookup_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& at(key_parameter_t key) + { + iterator i_element = find(key); + + ETL_ASSERT(i_element.p_node != std::nullptr, ETL_ERROR(map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::lookup_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A const reference to the value at index 'key' + //********************************************************************* + const mapped_type& at(key_parameter_t key) const + { + const_iterator i_element = find(key); + + ETL_ASSERT(i_element.p_node != std::nullptr, ETL_ERROR(map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Assigns values to the map. + /// If asserts or exceptions are enabled, emits map_full if the map does not have enough free space. + /// If asserts or exceptions are enabled, emits map_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { + initialise(); + insert(first, last); + } + + //************************************************************************* + /// Clears the map. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Counts the number of elements that contain the key specified. + ///\param key The key to search for. + ///\return 1 if element was found, 0 otherwise. + //********************************************************************* + size_type count(key_parameter_t key) const + { + return find_node(root_node, key) ? 1 : 0; + } + + //************************************************************************* + /// Returns two iterators with bounding (lower bound, upper bound) the key + /// provided + //************************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + return std::make_pair<iterator, iterator>( + iterator(*this, find_lower_node(root_node, key)), + iterator(*this, find_upper_node(root_node, key))); + } + + //************************************************************************* + /// Returns two const iterators with bounding (lower bound, upper bound) + /// the key provided. + //************************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + return std::make_pair<const_iterator, const_iterator>( + const_iterator(*this, find_lower_node(root_node, key)), + const_iterator(*this, find_upper_node(root_node, key))); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + void erase(iterator position) + { + // Remove the node by its key + erase((*position).first); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase(const_iterator position) + { + // Find the parent node to be removed + Node*& reference_node = find_node(root_node, position.p_node); + iterator next(*this, reference_node); + ++next; + + remove_node(root_node, (*position).first); + + return next; + } + + //************************************************************************* + // Erase the key specified. + //************************************************************************* + size_type erase(key_parameter_t key) + { + // Return 1 if key value was found and removed + return remove_node(root_node, key) ? 1 : 0; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(iterator first, iterator last) + { + iterator next; + while (first != last) + { + next = erase(const_iterator(first++)); + } + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + iterator next; + while (first != last) + { + next = erase(first++); + } + + return next; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_parameter_t key) + { + return iterator(*this, find_node(root_node, key)); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + return const_iterator(*this, find_node(root_node, key)); + } + + //********************************************************************* + /// Inserts a value to the map. + /// If asserts or exceptions are enabled, emits map_full if the map is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(const value_type& value) + { + // Default to no inserted node + Node* inserted_node = std::nullptr; + bool inserted = false; + + ETL_ASSERT(!full(), ETL_ERROR(map_full)); + + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might be std::nullptr if node was a duplicate) + inserted_node = insert_node(root_node, node); + inserted = inserted_node == &node; + + // Insert node into tree and return iterator to new node location in tree + return std::make_pair(iterator(*this, inserted_node), inserted); + } + + //********************************************************************* + /// Inserts a value to the map starting at the position recommended. + /// If asserts or exceptions are enabled, emits map_full if the map is already full. + ///\param position The position that would precede the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator, const value_type& value) + { + // Default to no inserted node + Node* inserted_node = std::nullptr; + + ETL_ASSERT(!full(), ETL_ERROR(map_full)); + + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might be std::nullptr if node was a duplicate) + inserted_node = insert_node(root_node, node); + + // Insert node into tree and return iterator to new node location in tree + return iterator(*this, inserted_node); + } + + //********************************************************************* + /// Inserts a value to the map starting at the position recommended. + /// If asserts or exceptions are enabled, emits map_full if the map is already full. + ///\param position The position that would precede the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator, const value_type& value) + { + // Default to no inserted node + Node* inserted_node = std::nullptr; + + ETL_ASSERT(!full(), ETL_ERROR(map_full)); + + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might be std::nullptr if node was a duplicate) + inserted_node = insert_node(root_node, node); + + // Insert node into tree and return iterator to new node location in tree + return iterator(*this, inserted_node); + } + + //********************************************************************* + /// Inserts a range of values to the map. + /// If asserts or exceptions are enabled, emits map_full if the map does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go before the key provided or end() + /// if all keys are considered to go before the key provided. + ///\return An iterator pointing to the element not before key or end() + //********************************************************************* + iterator lower_bound(key_parameter_t key) + { + return iterator(*this, find_lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go before the key provided + /// or end() if all keys are considered to go before the key provided. + ///\return An const_iterator pointing to the element not before key or end() + //********************************************************************* + const_iterator lower_bound(key_parameter_t key) const + { + return const_iterator(*this, find_lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go after the key provided or end() + /// if all keys are considered to go after the key provided. + ///\return An iterator pointing to the element after key or end() + //********************************************************************* + iterator upper_bound(key_parameter_t key) + { + return iterator(*this, find_upper_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go after the key provided + /// or end() if all keys are considered to go after the key provided. + ///\return An const_iterator pointing to the element after key or end() + //********************************************************************* + const_iterator upper_bound(key_parameter_t key) const + { + return const_iterator(*this, find_upper_node(root_node, key)); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + imap& operator = (const imap& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + imap(etl::ipool& node_pool, size_t max_size_) + : etl::map_base(max_size_) + , p_node_pool(&node_pool) + { + } + + //************************************************************************* + /// Initialise the map. + //************************************************************************* + void initialise() + { + erase(begin(), end()); + } + + private: + + //************************************************************************* + /// Allocate a Data_Node. + //************************************************************************* + Data_Node& allocate_data_node(value_type value) + { + Data_Node& node = *p_node_pool->allocate<Data_Node>(); + ::new (&node.value) const value_type(value); + ++construct_count; + return node; + } + + //************************************************************************* + /// Destroy a Data_Node. + //************************************************************************* + void destroy_data_node(Data_Node& node) + { + node.value.~value_type(); + p_node_pool->release(&node); + --construct_count; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + Node* find_node(Node* position, key_parameter_t key) + { + Node* found = position; + while (found) + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = imap::data_cast(*found); + + // Compare the node value to the current position value + if (node_comp(key, found_data_node)) + { + // Keep searching for the node on the left + found = found->children[kLeft]; + } + else if (node_comp(found_data_node, key)) + { + // Keep searching for the node on the right + found = found->children[kRight]; + } + else + { + // Node that matches the key provided was found, exit loop + break; + } + } + + // Return the node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + const Node* find_node(const Node* position, key_parameter_t key) const + { + const Node* found = position; + while (found) + { + // Downcast found to Data_Node class for comparison and other operations + const Data_Node& found_data_node = imap::data_cast(*found); + + // Compare the node value to the current position value + if (node_comp(key, found_data_node)) + { + // Keep searching for the node on the left + found = found->children[kLeft]; + } + else if (node_comp(found_data_node, key)) + { + // Keep searching for the node on the right + found = found->children[kRight]; + } + else + { + // Node that matches the key provided was found, exit loop + break; + } + } + + // Return the node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Find the reference node matching the node provided + //************************************************************************* + Node*& find_node(Node*& position, const Node* node) + { + Node* found = position; + while (found) + { + if (found->children[kLeft] == node) + { + return found->children[kLeft]; + } + else if (found->children[kRight] == node) + { + return found->children[kRight]; + } + else + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = imap::data_cast(*found); + const Data_Node& data_node = imap::data_cast(*node); + + // Compare the node value to the current position value + if (node_comp(data_node, found_data_node)) + { + // Keep searching for the node on the left + found = found->children[kLeft]; + } + else if (node_comp(found_data_node, data_node)) + { + // Keep searching for the node on the right + found = found->children[kRight]; + } + else + { + // Return position provided (it matches the node) + return position; + } + } + } + + // Return root node if nothing was found + return root_node; + } + + //************************************************************************* + /// Find the parent node that contains the node provided in its left or + /// right tree + //************************************************************************* + Node* find_parent_node(Node* position, const Node* node) + { + // Default to no parent node found + Node* found = std::nullptr; + + // If the position provided is the same as the node then there is no parent + if (position && node && position != node) + { + while (position) + { + // Is this position not the parent of the node we are looking for? + if (position->children[kLeft] != node && + position->children[kRight] != node) + { + // Downcast node and position to Data_Node references for key comparisons + const Data_Node& node_data_node = imap::data_cast(*node); + Data_Node& position_data_node = imap::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(node_data_node, position_data_node)) + { + // Keep looking for parent on the left + position = position->children[kLeft]; + } + else if (node_comp(position_data_node, node_data_node)) + { + // Keep looking for parent on the right + position = position->children[kRight]; + } + } + else + { + // Return the current position as the parent node found + found = position; + + // Parent node found, exit loop + break; + } + } + } + + // Return the parent node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Find the parent node that contains the node provided in its left or + /// right tree + //************************************************************************* + const Node* find_parent_node(const Node* position, const Node* node) const + { + // Default to no parent node found + const Node* found = std::nullptr; + + // If the position provided is the same as the node then there is no parent + if (position && node && position != node) + { + while (position) + { + // Is this position not the parent of the node we are looking for? + if (position->children[kLeft] != node && + position->children[kRight] != node) + { + // Downcast node and position to Data_Node references for key comparisons + const Data_Node& node_data_node = imap::data_cast(*node); + const Data_Node& position_data_node = imap::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(node_data_node, position_data_node)) + { + // Keep looking for parent on the left + position = position->children[kLeft]; + } + else if (node_comp(position_data_node, node_data_node)) + { + // Keep looking for parent on the right + position = position->children[kRight]; + } + } + else + { + // Return the current position as the parent node found + found = position; + + // Parent node found, exit loop + break; + } + } + } + + // Return the parent node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Find the node whose key is not considered to go before the key provided + //************************************************************************* + Node* find_lower_node(Node* position, key_parameter_t key) const + { + // Something at this position? keep going + Node* lower_node = position; + while (lower_node) + { + // Downcast lower node to Data_Node reference for key comparisons + Data_Node& data_node = imap::data_cast(*lower_node); + // Compare the key value to the current lower node key value + if (node_comp(key, data_node)) + { + if (lower_node->children[kLeft]) + { + lower_node = lower_node->children[kLeft]; + } + else + { + // Found lowest node + break; + } + } + else if (node_comp(data_node, key)) + { + lower_node = lower_node->children[kRight]; + } + else + { + // Found equal node + break; + } + } + + // Return the lower_node position found + return lower_node; + } + + //************************************************************************* + /// Find the node whose key is considered to go after the key provided + //************************************************************************* + Node* find_upper_node(Node* position, key_parameter_t key) const + { + // Keep track of parent of last upper node + Node* upper_node = std::nullptr; + // Start with position provided + Node* node = position; + while (node) + { + // Downcast position to Data_Node reference for key comparisons + Data_Node& data_node = imap::data_cast(*node); + // Compare the key value to the current upper node key value + if (node_comp(key, data_node)) + { + upper_node = node; + node = node->children[kLeft]; + } + else if (node_comp(data_node, key)) + { + node = node->children[kRight]; + } + else if (node->children[kRight]) + { + upper_node = find_limit_node(node->children[kRight], kLeft); + break; + } + else + { + break; + } + } + + // Return the upper node position found (might be std::nullptr) + return upper_node; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + Node* insert_node(Node*& position, Data_Node& node) + { + // Find the location where the node belongs + Node* found = position; + + // Was position provided not empty? then find where the node belongs + if (position) + { + // Find the critical parent node (default to std::nullptr) + Node* critical_parent_node = std::nullptr; + Node* critical_node = root_node; + + while (found) + { + // Search for critical weight node (all nodes whose weight factor + // is set to kNeither (balanced) + if (kNeither != found->weight) + { + critical_node = found; + } + + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = imap::data_cast(*found); + + // Is the node provided to the left of the current position? + if (node_comp(node, found_data_node)) + { + // Update direction taken to insert new node in parent node + found->dir = kLeft; + } + // Is the node provided to the right of the current position? + else if (node_comp(found_data_node, node)) + { + // Update direction taken to insert new node in parent node + found->dir = kRight; + } + else + { + // Update direction taken to insert new node in parent node + found->dir = kNeither; + + // Clear critical node value to skip weight step below + critical_node = std::nullptr; + + // Destroy the node provided (its a duplicate) + destroy_data_node(node); + + // Exit loop, duplicate node found + break; + } + + // Is there a child of this parent node? + if (found->children[found->dir]) + { + // Will this node be the parent of the next critical node whose + // weight factor is set to kNeither (balanced)? + if (kNeither != found->children[found->dir]->weight) + { + critical_parent_node = found; + } + + // Keep looking for empty spot to insert new node + found = found->children[found->dir]; + } + else + { + // Attatch node to right + attach_node(found->children[found->dir], node); + + // Return newly added node + found = found->children[found->dir]; + + // Exit loop + break; + } + } + + // Was a critical node found that should be checked for balance? + if (critical_node) + { + if (critical_parent_node == std::nullptr && critical_node == root_node) + { + balance_node(root_node); + } + else if (critical_parent_node == std::nullptr && critical_node == position) + { + balance_node(position); + } + else + { + balance_node(critical_parent_node->children[critical_parent_node->dir]); + } + } + } + else + { + // Attatch node to current position + attach_node(position, node); + + // Return newly added node at current position + found = position; + } + + // Return the node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(Node*&position) + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(const Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(Node*&position) + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = find_parent_node(root_node, position); + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(const Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = find_parent_node(root_node, position); + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Remove the node specified from somewhere starting at the position + /// provided + //************************************************************************* + Node* remove_node(Node*& position, key_parameter_t key) + { + // Step 1: Find the target node that matches the key provided, the + // replacement node (might be the same as target node), and the critical + // node to start rebalancing the tree from (up to the replacement node) + Node* found_parent = std::nullptr; + Node* found = std::nullptr; + Node* replace_parent = std::nullptr; + Node* replace = position; + Node* balance_parent = std::nullptr; + Node* balance = root_node; + while (replace) + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& replace_data_node = imap::data_cast(*replace); + + // Compare the key provided to the replace data node key + if (node_comp(key, replace_data_node)) + { + // Update the direction to the target/replace node + replace->dir = kLeft; + } + else if (node_comp(replace_data_node, key)) + { + // Update the direction to the target/replace node + replace->dir = kRight; + } + else + { + // Update the direction to the replace node (target node found here) + replace->dir = replace->children[kLeft] ? kLeft : kRight; + + // Note the target node was found (and its parent) + found_parent = replace_parent; + found = replace; + } + // Replacement node found if its missing a child in the replace->dir + // value set above + if (replace->children[replace->dir] == std::nullptr) + { + // Exit loop once replace node is found (target might not have been) + break; + } + + // If replacement node weight is kNeither or we are taking the shorter + // path of replacement node and our sibling (on longer path) is + // balanced then we need to update the balance node to match this + // replacement node but all our ancestors will not require rebalancing + if ((replace->weight == kNeither) || + (replace->weight == (1 - replace->dir) && + replace->children[1 - replace->dir]->weight == kNeither)) + { + // Update balance node (and its parent) to replacement node + balance_parent = replace_parent; + balance = replace; + } + + // Keep searching for the replacement node + replace_parent = replace; + replace = replace->children[replace->dir]; + } + + // If target node was found, proceed with rebalancing and replacement + if (found) + { + // Step 2: Update weights from critical node to replacement parent node + while (balance) + { + if (balance->children[balance->dir] == std::nullptr) + { + break; + } + + if (balance->weight == kNeither) + { + balance->weight = 1 - balance->dir; + } + else if (balance->weight == balance->dir) + { + balance->weight = kNeither; + } + else + { + int weight = balance->children[1 - balance->dir]->weight; + // Perform a 3 node rotation if weight is same as balance->dir + if (weight == balance->dir) + { + // Is the root node being rebalanced (no parent) + if (balance_parent == std::nullptr) + { + rotate_3node(root_node, 1 - balance->dir, + balance->children[1 - balance->dir]->children[balance->dir]->weight); + } + else + { + rotate_3node(balance_parent->children[balance_parent->dir], 1 - balance->dir, + balance->children[1 - balance->dir]->children[balance->dir]->weight); + } + } + // Already balanced, rebalance and make it heavy in opposite + // direction of the node being removed + else if (weight == kNeither) + { + // Is the root node being rebalanced (no parent) + if (balance_parent == std::nullptr) + { + rotate_2node(root_node, 1 - balance->dir); + root_node->weight = balance->dir; + } + else + { + rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir); + balance_parent->children[balance_parent->dir]->weight = balance->dir; + } + // Update balance node weight in opposite direction of node removed + balance->weight = 1 - balance->dir; + } + // Rebalance and leave it balanced + else + { + // Is the root node being rebalanced (no parent) + if (balance_parent == std::nullptr) + { + rotate_2node(root_node, 1 - balance->dir); + } + else + { + rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir); + } + } + + // Is balance node the same as the target node found? then update + // its parent after the rotation performed above + if (balance == found) + { + if (balance_parent) + { + found_parent = balance_parent->children[balance_parent->dir]; + // Update dir since it is likely stale + found_parent->dir = found_parent->children[kLeft] == found ? kLeft : kRight; + } + else + { + found_parent = root_node; + root_node->dir = root_node->children[kLeft] == found ? kLeft : kRight; + } + } + } + + // Next balance node to consider + balance_parent = balance; + balance = balance->children[balance->dir]; + } // while(balance) + + // Step 3: Swap found node with replacement node + if (found_parent) + { + // Handle traditional case + detach_node(found_parent->children[found_parent->dir], + replace_parent->children[replace_parent->dir]); + } + // Handle root node removal + else + { + // Valid replacement node for root node being removed? + if (replace_parent) + { + detach_node(root_node, replace_parent->children[replace_parent->dir]); + } + else + { + // Target node and replacement node are both root node + detach_node(root_node, root_node); + } + } + + // Downcast found into data node + Data_Node& found_data_node = imap::data_cast(*found); + + // One less. + --current_size; + + // Destroy the node removed + destroy_data_node(found_data_node); + } // if(found) + + // Return node found (might be std::nullptr) + return found; + } + + // Disable copy construction. + imap(const imap&); + }; + + //************************************************************************* + /// A templated map implementation that uses a fixed size buffer. + //************************************************************************* + template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> > + class map : public etl::imap<TKey, TValue, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + map() + : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE) + { + etl::imap<TKey, TValue, TCompare>::initialise(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + map(const map& other) + : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE) + { + etl::imap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + map(TIterator first, TIterator last) + : etl::imap<TKey, TValue, TCompare>(node_pool, MAX_SIZE) + { + etl::imap<TKey, TValue, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~map() + { + etl::imap<TKey, TValue, TCompare>::initialise(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + map& operator = (const map& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + etl::imap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of data nodes used for the map. + etl::pool<typename etl::imap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool; + }; +} + +//*************************************************************************** +/// Equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> +///\ingroup lookup +//*************************************************************************** +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator ==(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs) +{ + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +//*************************************************************************** +/// Not equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> +///\ingroup lookup +//*************************************************************************** +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator !=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs) +{ + return !(lhs == rhs); +} + +//************************************************************************* +/// Less than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator <(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); +} + +//************************************************************************* +/// Greater than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator >(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs) +{ + return (rhs < lhs); +} + +//************************************************************************* +/// Less than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than or equal +/// to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator <=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs) +{ + return !(lhs > rhs); +} + +//************************************************************************* +/// Greater than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than or +/// equal to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator >=(const etl::imap<TKey, TMapped, TKeyCompare>& lhs, const etl::imap<TKey, TMapped, TKeyCompare>& rhs) +{ + return !(lhs < rhs); +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memory.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,773 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_MEMORY__ +#define __ETL_MEMORY__ + +#include <iterator> +#include <algorithm> + +#include "platform.h" +#include "type_traits.h" + +///\defgroup memory memory +///\ingroup etl +namespace etl +{ + //***************************************************************************** + /// Gets the address of an object. + ///\ingroup memory + //***************************************************************************** + template <typename T> + T* addressof(T& t) + { + return reinterpret_cast<T*>(&const_cast<char&>(reinterpret_cast<const volatile char&>(t))); + } + + //***************************************************************************** + /// Fills uninitialised memory range with a value. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename T> + typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value) + { + std::fill(o_begin, o_end, value); + + return o_end; + } + + //***************************************************************************** + /// Fills uninitialised memory range with a value. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename T> + typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value) + { + typedef typename std::iterator_traits<TOutputIterator>::value_type value_type; + + while (o_begin != o_end) + { + ::new (static_cast<void*>(etl::addressof(*o_begin))) value_type(value); + ++o_begin; + } + + return o_end; + } + + //***************************************************************************** + /// Fills uninitialised memory range with a value. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename T, typename TCounter> + typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value, TCounter& count) + { + count += std::distance(o_begin, o_end); + + std::fill(o_begin, o_end, value); + + return o_end; + } + + //***************************************************************************** + /// Fills uninitialised memory range with a value. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename T, typename TCounter> + typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value, TCounter& count) + { + count += std::distance(o_begin, o_end); + + etl::uninitialized_fill(o_begin, o_end, value); + + return o_end; + } + + //***************************************************************************** + /// Fills uninitialised memory with N values. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TSize, typename T> + inline TOutputIterator uninitialized_fill_n(TOutputIterator o_begin, TSize n, const T& value) + { + return etl::uninitialized_fill(o_begin, o_begin + n, value); + } + + //***************************************************************************** + /// Fills uninitialised memory with N values. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TSize, typename T, typename TCounter> + inline TOutputIterator uninitialized_fill_n(TOutputIterator o_begin, TSize n, const T& value, TCounter& count) + { + count += n; + + return etl::uninitialized_fill(o_begin, o_begin + n, value); + } + + //***************************************************************************** + /// Copies a range of objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TInputIterator, typename TOutputIterator> + typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) + { + return std::copy(i_begin, i_end, o_begin); + } + + //***************************************************************************** + /// Copies a range of objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TInputIterator, typename TOutputIterator> + typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) + { + typedef typename std::iterator_traits<TOutputIterator>::value_type value_type; + + TOutputIterator o_end = o_begin; + + while (i_begin != i_end) + { + ::new (static_cast<void*>(etl::addressof(*o_end))) value_type(*i_begin); + ++i_begin; + ++o_end; + } + + return o_end; + } + + //***************************************************************************** + /// Copies a range of objects to uninitialised memory. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TInputIterator, typename TOutputIterator, typename TCounter> + typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count) + { + TOutputIterator o_end = std::copy(i_begin, i_end, o_begin); + count += std::distance(o_begin, o_end); + + return o_end; + } + + //***************************************************************************** + /// Copies a range of objects to uninitialised memory. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TInputIterator, typename TOutputIterator, typename TCounter> + typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count) + { + TOutputIterator o_end = etl::uninitialized_copy(i_begin, i_end, o_begin); + + count += std::distance(o_begin, o_end); + + return o_end; + } + + //***************************************************************************** + /// Copies N objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TInputIterator, typename TSize, typename TOutputIterator> + inline TOutputIterator uninitialized_copy_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin) + { + return etl::uninitialized_copy(i_begin, i_begin + n, o_begin); + } + + //***************************************************************************** + /// Copies N objects to uninitialised memory. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TInputIterator, typename TSize, typename TOutputIterator, typename TCounter> + inline TOutputIterator uninitialized_copy_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TCounter& count) + { + count += n; + + return etl::uninitialized_copy(i_begin, i_begin + n, o_begin); + } + + //***************************************************************************** + /// Default contruct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T> + typename etl::enable_if<etl::is_trivially_constructible<T>::value, void>::type + create_default_at(T* /*p*/) + { + } + + //***************************************************************************** + /// Default contruct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TCounter> + typename etl::enable_if<etl::is_trivially_constructible<T>::value, void>::type + create_default_at(T* /*p*/, TCounter& count) + { + ++count; + } + + //***************************************************************************** + /// Default contruct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T> + typename etl::enable_if<!etl::is_trivially_constructible<T>::value, void>::type + create_default_at(T* p) + { + ::new (p) T; + } + + //***************************************************************************** + /// Default contruct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TCounter> + typename etl::enable_if<!etl::is_trivially_constructible<T>::value, void>::type + create_default_at(T* p, TCounter& count) + { + ::new (p) T; + ++count; + } + + //***************************************************************************** + /// Default initialises a range of objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator> + typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type + uninitialized_default_construct(TOutputIterator /*o_begin*/, TOutputIterator /*o_end*/) + { + } + + //***************************************************************************** + /// Default initialises a range of objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator> + typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type + uninitialized_default_construct(TOutputIterator o_begin, TOutputIterator o_end) + { + typedef typename std::iterator_traits<TOutputIterator>::value_type value_type; + + while (o_begin != o_end) + { + ::new (static_cast<void*>(etl::addressof(*o_begin))) value_type; + ++o_begin; + } + } + + //***************************************************************************** + /// Default initialises a range of objects to uninitialised memory. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TCounter> + typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type + uninitialized_default_construct(TOutputIterator o_begin, TOutputIterator o_end, TCounter& count) + { + count = std::distance(o_begin, o_end); + } + + //***************************************************************************** + /// Default initialises a range of objects to uninitialised memory. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TCounter> + typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type + uninitialized_default_construct(TOutputIterator o_begin, TOutputIterator o_end, TCounter& count) + { + count += std::distance(o_begin, o_end); + + etl::uninitialized_default_construct(o_begin, o_end); + } + + //***************************************************************************** + /// Default initialises N objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TSize> + typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_default_construct_n(TOutputIterator o_begin, TSize n) + { + TOutputIterator o_end = o_begin + n; + + return o_end; + } + + //***************************************************************************** + /// Default initialises N objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TSize> + typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_default_construct_n(TOutputIterator o_begin, TSize n) + { + TOutputIterator o_end = o_begin + n; + + etl::uninitialized_default_construct(o_begin, o_end); + + return o_end; + } + + //***************************************************************************** + /// Default initialises N objects to uninitialised memory. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TSize, typename TCounter> + typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_default_construct_n(TOutputIterator o_begin, TSize n, TCounter& count) + { + TOutputIterator o_end = o_begin + n; + + count += n; + + return o_end; + } + + //***************************************************************************** + /// Default initialises N objects to uninitialised memory. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TSize, typename TCounter> + typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, TOutputIterator>::type + uninitialized_default_construct_n(TOutputIterator o_begin, TSize n, TCounter& count) + { + TOutputIterator o_end = o_begin + n; + + etl::uninitialized_default_construct(o_begin, o_end); + + count += n; + + return o_end; + } + + //***************************************************************************** + /// Value construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T> + inline void create_value_at(T* p) + { + ::new (p) T(); + } + + //***************************************************************************** + /// Value construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TCounter> + inline void create_value_at(T* p, TCounter& count) + { + ::new (p) T(); + ++count; + } + + //***************************************************************************** + /// Copy construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T> + inline void create_copy_at(T* p, const T& value) + { + ::new (p) T(value); + } + + //***************************************************************************** + /// Copy construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TCounter> + inline void create_copy_at(T* p, const T& value, TCounter& count) + { + ::new (p) T(value); + ++count; + } + + //***************************************************************************** + /// Construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T> + inline T& make_default_at(T* p) + { + ::new (p) T(); + return *reinterpret_cast<T*>(p); + } + + //***************************************************************************** + /// Construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TCounter> + inline T& make_default_at(T* p, TCounter& count) + { + ::new (p) T(); + ++count; + return *reinterpret_cast<T*>(p); + } + + //***************************************************************************** + /// Construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T> + inline T& make_copy_at(T* p, const T& other) + { + ::new (p) T(other); + return *reinterpret_cast<T*>(p); + } + + //***************************************************************************** + /// Construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TCounter> + inline T& make_copy_at(T* p, const T& other, TCounter& count) + { + ::new (p) T(other); + ++count; + return *reinterpret_cast<T*>(p); + } + + //***************************************************************************** + /// Construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TParameter> + inline T& make_value_at(T* p, const TParameter& value) + { + ::new (p) T(value); + return *reinterpret_cast<T*>(p); + } + + //***************************************************************************** + /// Construct an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TParameter, typename TCounter> + inline T& make_value_at(T* p, const TParameter& value, TCounter& count) + { + ::new (p) T(value); + ++count; + return *reinterpret_cast<T*>(p); + } + + //***************************************************************************** + /// Default initialises a range of objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator> + typename etl::enable_if<etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type + uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end) + { + typedef typename std::iterator_traits<TOutputIterator>::value_type value_type; + + std::fill(o_begin, o_end, value_type()); + } + + //***************************************************************************** + /// Default initialises a range of objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator> + typename etl::enable_if<!etl::is_trivially_constructible<typename std::iterator_traits<TOutputIterator>::value_type>::value, void>::type + uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end) + { + typedef typename std::iterator_traits<TOutputIterator>::value_type value_type; + + while (o_begin != o_end) + { + ::new (static_cast<void*>(etl::addressof(*o_begin))) value_type(); + ++o_begin; + } + } + + //***************************************************************************** + /// Default initialises a range of objects to uninitialised memory. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TCounter> + void uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end, TCounter& count) + { + count += std::distance(o_begin, o_end); + + etl::uninitialized_value_construct(o_begin, o_end); + } + + //***************************************************************************** + /// Default initialises N objects to uninitialised memory. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TSize> + TOutputIterator uninitialized_value_construct_n(TOutputIterator o_begin, TSize n) + { + TOutputIterator o_end = o_begin + n; + + etl::uninitialized_value_construct(o_begin, o_end); + + return o_end; + } + + //***************************************************************************** + /// Default initialises N objects to uninitialised memory. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TOutputIterator, typename TSize, typename TCounter> + TOutputIterator uninitialized_value_construct_n(TOutputIterator o_begin, TSize n, TCounter& count) + { + TOutputIterator o_end = o_begin + n; + + etl::uninitialized_value_construct(o_begin, o_end); + + count += n; + + return o_end; + } + + //***************************************************************************** + /// Destroys an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T> + typename etl::enable_if<etl::is_trivially_destructible<T>::value, void>::type + destroy_at(T* /*p*/) + { + } + + //***************************************************************************** + /// Destroys an item at address p. + ///\ingroup memory + //***************************************************************************** + template <typename T> + typename etl::enable_if<!etl::is_trivially_destructible<T>::value, void>::type + destroy_at(T* p) + { + p->~T(); + } + + //***************************************************************************** + /// Destroys an item at address p. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TCounter> + typename etl::enable_if<etl::is_trivially_destructible<T>::value, void>::type + destroy_at(T* /*p*/, TCounter& count) + { + --count; + } + + //***************************************************************************** + /// Destroys an item at address p. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename T, typename TCounter> + typename etl::enable_if<!etl::is_trivially_destructible<T>::value, void>::type + destroy_at(T* p, TCounter& count) + { + p->~T(); + --count; + } + + //***************************************************************************** + /// Destroys a range of items. + ///\ingroup memory + //***************************************************************************** + template <typename TIterator> + typename etl::enable_if<etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, void>::type + destroy(TIterator /*i_begin*/, TIterator /*i_end*/) + { + } + + //***************************************************************************** + /// Destroys a range of items. + ///\ingroup memory + //***************************************************************************** + template <typename TIterator> + typename etl::enable_if<!etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, void>::type + destroy(TIterator i_begin, TIterator i_end) + { + while (i_begin != i_end) + { + etl::destroy_at(etl::addressof(*i_begin)); + ++i_begin; + } + } + + //***************************************************************************** + /// Destroys a range of items. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TIterator, typename TCounter> + typename etl::enable_if<etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, void>::type + destroy(TIterator i_begin, TIterator i_end, TCounter& count) + { + count -= std::distance(i_begin, i_end); + } + + //***************************************************************************** + /// Destroys a range of items. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TIterator, typename TCounter> + typename etl::enable_if<!etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, void>::type + destroy(TIterator i_begin, TIterator i_end, TCounter& count) + { + count -= std::distance(i_begin, i_end); + + while (i_begin != i_end) + { + etl::destroy_at(etl::addressof(*i_begin)); + ++i_begin; + } + } + + //***************************************************************************** + /// Destroys a number of items. + ///\ingroup memory + //***************************************************************************** + template <typename TIterator, typename TSize> + typename etl::enable_if<etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, TIterator>::type + destroy_n(TIterator i_begin, TSize n) + { + return i_begin + n; + } + + //***************************************************************************** + /// Destroys a number of items. + ///\ingroup memory + //***************************************************************************** + template <typename TIterator, typename TSize> + typename etl::enable_if<!etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, TIterator>::type + destroy_n(TIterator i_begin, TSize n) + { + while (n > 0) + { + etl::destroy_at(etl::addressof(*i_begin)); + ++i_begin; + --n; + } + + return i_begin; + } + + //***************************************************************************** + /// Destroys a number of items. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TIterator, typename TSize, typename TCounter> + typename etl::enable_if<etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, TIterator>::type + destroy_n(TIterator i_begin, TSize n, TCounter& count) + { + count -= n; + return i_begin + n; + } + + //***************************************************************************** + /// Destroys a number of items. + /// Debug counter version. + ///\ingroup memory + //***************************************************************************** + template <typename TIterator, typename TSize, typename TCounter> + typename etl::enable_if<!etl::is_trivially_destructible<typename std::iterator_traits<TIterator>::value_type>::value, TIterator>::type + destroy_n(TIterator i_begin, TSize n, TCounter& count) + { + count -= n; + + while (n > 0) + { + etl::destroy_at(etl::addressof(*i_begin)); + ++i_begin; + --n; + } + + return i_begin; + } + + //***************************************************************************** + /// Copy constructs a derived class to an address. + ///\tparam T The derived type. + ///\ingroup memory + //***************************************************************************** + template <typename T> + struct create_copy + { + void create_copy_at(void* p) + { + new (p) T(static_cast<const T&>(*this)); + } + + template <typename TCounter> + void create_copy_at(void* p, TCounter& count) + { + new (p) T(static_cast<const T&>(*this)); + ++count; + } + + T& make_copy_at(void* p) + { + new (p) T(static_cast<const T&>(*this)); + return *reinterpret_cast<T*>(p); + } + + template <typename TCounter> + T& make_copy_at(void* p, TCounter& count) + { + new (p) T(static_cast<const T&>(*this)); + ++count; + return *reinterpret_cast<T*>(p); + } + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/message.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,106 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_MESSAGE__ +#define __ETL_MESSAGE__ + +#include <stdint.h> + +#include "platform.h" +#include "error_handler.h" +#include "exception.h" +#include "message_types.h" + +#undef ETL_FILE +#define ETL_FILE "38" + +namespace etl +{ + //*************************************************************************** + class message_exception : public etl::exception + { + public: + + message_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + class unhandled_message_exception : public etl::message_exception + { + public: + + unhandled_message_exception(string_type file_name_, numeric_type line_number_) + : message_exception(ETL_ERROR_TEXT("message:unknown", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + class imessage + { + public: + +#ifdef ETL_MESSAGES_ARE_VIRTUAL + virtual ~imessage() + { + } +#endif + + imessage(etl::message_id_t id) + : message_id(id) + { + } + + const etl::message_id_t message_id; + }; + + //*************************************************************************** + template <const etl::message_id_t ID_> + class message : public imessage + { + public: + + message() + : imessage(ID_) + { + } + + enum + { + ID = ID_ + }; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/message_bus.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,391 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_MESSAGE_BUS_ +#define __ETL_MESSAGE_BUS_ + +#include <stdint.h> +#include <algorithm> + +#include "platform.h" +#include "algorithm.h" +#include "vector.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "message_types.h" +#include "message.h" +#include "message_router.h" + +#undef ETL_FILE +#define ETL_FILE "39" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for message bus + //*************************************************************************** + class message_bus_exception : public etl::exception + { + public: + + message_bus_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Too many subscribers. + //*************************************************************************** + class message_bus_too_many_subscribers : public etl::message_bus_exception + { + public: + + message_bus_too_many_subscribers(string_type file_name_, numeric_type line_number_) + : message_bus_exception(ETL_ERROR_TEXT("message bus:too many subscribers", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Interface for message bus + //*************************************************************************** + class imessage_bus : public etl::imessage_router + { + private: + + typedef etl::ivector<etl::imessage_router*> router_list_t; + + public: + + using etl::imessage_router::receive; + + //******************************************* + /// Subscribe to the bus. + //******************************************* + bool subscribe(etl::imessage_router& router) + { + bool ok = true; + + // There's no point actually adding null routers. + if (!router.is_null_router()) + { + ok = !router_list.full(); + + ETL_ASSERT(ok, ETL_ERROR(etl::message_bus_too_many_subscribers)); + + if (ok) + { + if (router.is_bus()) + { + // Message busses get added to the end. + router_list.push_back(&router); + } + else + { + // Routers get added in id order. + router_list_t::iterator irouter = std::upper_bound(router_list.begin(), + router_list.end(), + router.get_message_router_id(), + compare_router_id()); + + router_list.insert(irouter, &router); + } + } + } + + return ok; + } + + //******************************************* + /// Unsubscribe from the bus. + //******************************************* + void unsubscribe(etl::message_router_id_t id) + { + if (id == etl::imessage_bus::ALL_MESSAGE_ROUTERS) + { + clear(); + } + else + { + std::pair<router_list_t::iterator, router_list_t::iterator> range = std::equal_range(router_list.begin(), + router_list.end(), + id, + compare_router_id()); + + router_list.erase(range.first, range.second); + } + } + + //******************************************* + void unsubscribe(etl::imessage_router& router) + { + router_list_t::iterator irouter = std::find(router_list.begin(), + router_list.end(), + &router); + + if (irouter != router_list.end()) + { + router_list.erase(irouter); + } + } + + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, etl::imessage_router::ALL_MESSAGE_ROUTERS, message); + } + + //******************************************* + void receive(etl::message_router_id_t destination_router_id, + const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, destination_router_id, message); + } + + //******************************************* + void receive(etl::imessage_router& source, + const etl::imessage& message) + { + receive(source, etl::imessage_router::ALL_MESSAGE_ROUTERS, message); + } + + //******************************************* + void receive(etl::imessage_router& source, + etl::message_router_id_t destination_router_id, + const etl::imessage& message) + { + switch (destination_router_id) + { + //***************************** + // Null message router. These routers can never be subscribed. + case etl::imessage_router::NULL_MESSAGE_ROUTER: + { + break; + } + + //***************************** + // Broadcast to all routers. + case etl::imessage_router::ALL_MESSAGE_ROUTERS: + { + router_list_t::iterator irouter = router_list.begin(); + + // Broadcast to everyone. + while (irouter != router_list.end()) + { + etl::imessage_router& router = **irouter; + + if (router.is_bus()) + { + // The router is actually a bus. + etl::imessage_bus& bus = static_cast<etl::imessage_bus&>(router); + + // So pass it on. + bus.receive(source, destination_router_id, message); + } + else if (router.accepts(message.message_id)) + { + router.receive(source, message); + } + + ++irouter; + } + + break; + } + + //***************************** + // Must be an addressed message. + default: + { + router_list_t::iterator irouter = router_list.begin(); + + // Find routers with the id. + std::pair<router_list_t::iterator, router_list_t::iterator> range = std::equal_range(router_list.begin(), + router_list.end(), + destination_router_id, + compare_router_id()); + + // Call all of them. + while (range.first != range.second) + { + if ((*(range.first))->accepts(message.message_id)) + { + (*(range.first))->receive(source, message); + } + + ++range.first; + } + + // Do any message buses. + // These are always at the end of the list. + irouter = std::lower_bound(router_list.begin(), + router_list.end(), + etl::imessage_bus::MESSAGE_BUS, + compare_router_id()); + + while (irouter != router_list.end()) + { + // The router is actually a bus. + etl::imessage_bus& bus = static_cast<etl::imessage_bus&>(**irouter); + + // So pass it on. + bus.receive(source, destination_router_id, message); + + ++irouter; + } + + break; + } + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this message bus accept the message id? + /// Yes!, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t) const + { + return true; + } + + //******************************************* + size_t size() const + { + return router_list.size(); + } + + //******************************************* + void clear() + { + return router_list.clear(); + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + imessage_bus(router_list_t& list) + : imessage_router(etl::imessage_router::MESSAGE_BUS), + router_list(list) + { + } + + private: + + //******************************************* + // How to compare routers to router ids. + //******************************************* + struct compare_router_id + { + bool operator()(const etl::imessage_router* prouter, etl::message_router_id_t id) const + { + return prouter->get_message_router_id() < id; + } + + bool operator()(etl::message_router_id_t id, const etl::imessage_router* prouter) const + { + return id < prouter->get_message_router_id(); + } + }; + + router_list_t& router_list; + }; + + //*************************************************************************** + /// The message bus + //*************************************************************************** + template <uint_least8_t MAX_ROUTERS_> + class message_bus : public etl::imessage_bus + { + public: + + //******************************************* + /// Constructor. + //******************************************* + message_bus() + : imessage_bus(router_list) + { + } + + private: + + etl::vector<etl::imessage_router*, MAX_ROUTERS_> router_list; + }; + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_bus& bus, + const etl::imessage& message) + { + bus.receive(message); + } + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_bus& bus, + etl::message_router_id_t id, + const etl::imessage& message) + { + bus.receive(id, message); + } + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_bus& bus, + const etl::imessage& message) + { + bus.receive(source, message); + } + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_bus& bus, + etl::message_router_id_t id, + const etl::imessage& message) + { + bus.receive(source, id, message); + } +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/message_router.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,2531 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -omessage_router.h -DHandlers=<n> message_router_generator.h +// Where <n> is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 messages... +// python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_MESSAGE_ROUTER__ +#define __ETL_MESSAGE_ROUTER__ + +#include <stdint.h> + +#include "platform.h" +#include "message.h" +#include "message_types.h" +#include "alignment.h" +#include "error_handler.h" +#include "exception.h" +#include "largest.h" +#include "nullptr.h" + +#undef ETL_FILE +#define ETL_FILE "35" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for message router + //*************************************************************************** + class message_router_exception : public etl::exception + { + public: + + message_router_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Router id is out of the legal range. + //*************************************************************************** + class message_router_illegal_id : public etl::message_router_exception + { + public: + + message_router_illegal_id(string_type file_name_, numeric_type line_number_) + : message_router_exception(ETL_ERROR_TEXT("message router:illegal id", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + class imessage_router + { + public: + + virtual ~imessage_router() {} + virtual void receive(const etl::imessage& message) = 0; + virtual void receive(imessage_router& source, const etl::imessage& message) = 0; + virtual bool accepts(etl::message_id_t id) const = 0; + + //******************************************** + bool accepts(const etl::imessage& msg) const + { + return accepts(msg.message_id); + } + + //******************************************** + etl::message_router_id_t get_message_router_id() const + { + return message_router_id; + } + + //******************************************** + bool is_null_router() const + { + return (message_router_id == NULL_MESSAGE_ROUTER); + } + + //******************************************** + bool is_bus() const + { + return (message_router_id == MESSAGE_BUS); + } + + //******************************************** + void set_successor(imessage_router& successor_) + { + successor = &successor_; + } + + //******************************************** + imessage_router& get_successor() const + { + return *successor; + } + + //******************************************** + bool has_successor() const + { + return (successor != nullptr); + } + + enum + { + NULL_MESSAGE_ROUTER = 255, + MESSAGE_BUS = 254, + ALL_MESSAGE_ROUTERS = 253, + MAX_MESSAGE_ROUTER = 249 + }; + + protected: + + imessage_router(etl::message_router_id_t id_) + : successor(nullptr), + message_router_id(id_) + { + } + + imessage_router(etl::message_router_id_t id_, + imessage_router& successor_) + : successor(&successor_), + message_router_id(id_) + { + } + + private: + + // Disabled. + imessage_router(const imessage_router&); + imessage_router& operator =(const imessage_router&); + + etl::imessage_router* successor; + + etl::message_router_id_t message_router_id; + }; + + //*************************************************************************** + /// This router can be used either as a sink for messages + /// or as a producer-only of messages such an interrupt routine. + //*************************************************************************** + class null_message_router : public imessage_router + { + public: + + null_message_router() + : imessage_router(imessage_router::NULL_MESSAGE_ROUTER) + { + } + + //******************************************** + void receive(const etl::imessage&) + { + } + + //******************************************** + void receive(etl::imessage_router&, const etl::imessage&) + { + } + + //******************************************** + bool accepts(etl::message_id_t) const + { + return false; + } + + //******************************************** + static null_message_router& instance() + { + static null_message_router nmr; + return nmr; + } + }; + + //*************************************************************************** + /// Send a message to a router. + /// Sets the 'sender' to etl::null_message_router type. + //*************************************************************************** + inline static void send_message(etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a message to a router. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(source, message); + } + + //*************************************************************************** + // The definition for all 16 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void> + class message_router : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break; + case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break; + case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break; + case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break; + case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break; + case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break; + case T14::ID: ::new (p) T14(static_cast<const T14&>(msg)); break; + case T15::ID: ::new (p) T15(static_cast<const T15&>(msg)); break; + case T16::ID: ::new (p) T16(static_cast<const T16&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const etl::message_id_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break; + case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break; + case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break; + case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break; + case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break; + case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break; + case T14::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T14&>(msg)); break; + case T15::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T15&>(msg)); break; + case T16::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T16&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: case T16::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 15 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13, typename T14, typename T15> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break; + case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break; + case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break; + case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break; + case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break; + case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break; + case T14::ID: ::new (p) T14(static_cast<const T14&>(msg)); break; + case T15::ID: ::new (p) T15(static_cast<const T15&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break; + case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break; + case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break; + case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break; + case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break; + case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break; + case T14::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T14&>(msg)); break; + case T15::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T15&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 14 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13, typename T14> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break; + case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break; + case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break; + case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break; + case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break; + case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break; + case T14::ID: ::new (p) T14(static_cast<const T14&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break; + case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break; + case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break; + case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break; + case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break; + case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break; + case T14::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T14&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 13 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break; + case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break; + case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break; + case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break; + case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break; + case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break; + case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break; + case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break; + case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break; + case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break; + case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 12 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break; + case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break; + case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break; + case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break; + case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break; + case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break; + case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break; + case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break; + case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 11 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break; + case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break; + case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break; + case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break; + case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break; + case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break; + case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 10 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break; + case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break; + case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break; + case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break; + case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 9 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, void, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break; + case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break; + case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 8 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, void, void, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 7 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, void, void, void, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6, T7>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 6 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6> + class message_router<TDerived, T1, T2, T3, T4, T5, T6, void, void, void, void, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5, T6>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 5 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4, + typename T5> + class message_router<TDerived, T1, T2, T3, T4, T5, void, void, void, void, void, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4, T5>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4, T5>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 4 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3, typename T4> + class message_router<TDerived, T1, T2, T3, T4, void, void, void, void, void, void, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3, T4>::size, + ALIGNMENT = etl::largest<T1, T2, T3, T4>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 3 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2, typename T3> + class message_router<TDerived, T1, T2, T3, void, void, void, void, void, void, void, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2, T3>::size, + ALIGNMENT = etl::largest<T1, T2, T3>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 2 message types. + //*************************************************************************** + template <typename TDerived, + typename T1, typename T2> + class message_router<TDerived, T1, T2, void, void, void, void, void, void, void, void, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1, T2>::size, + ALIGNMENT = etl::largest<T1, T2>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 1 message type. + //*************************************************************************** + template <typename TDerived, + typename T1> + class message_router<TDerived, T1, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.message_id; + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template <typename T> + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of<T, T1>::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast<const T&>(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast<etl::imessage*>(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast<etl::imessage*>(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast<const etl::imessage*>(data); + } + + enum + { + SIZE = etl::largest<T1>::size, + ALIGNMENT = etl::largest<T1>::alignment + }; + + private: + + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id_) + : imessage_router(id_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) + : imessage_router(id_, successor_) + { + ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.message_id; + + switch (id) + { + case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break; + default: + { + if (has_successor()) + { + get_successor().receive(source, msg); + } + else + { + static_cast<TDerived*>(this)->on_receive_unknown(source, msg); + } + break; + } + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: + return true; break; + default: + return false; break; + } + } + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/message_router_generator.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,589 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -omessage_router.h -DHandlers=<n> message_router_generator.h +// Where <n> is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 messages... +// python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_MESSAGE_ROUTER__ +#define __ETL_MESSAGE_ROUTER__ + +#include <stdint.h> + +#include "platform.h" +#include "message.h" +#include "message_types.h" +#include "alignment.h" +#include "error_handler.h" +#include "exception.h" +#include "largest.h" +#include "nullptr.h" + +#undef ETL_FILE +#define ETL_FILE "35" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for message router + //*************************************************************************** + class message_router_exception : public etl::exception + { + public: + + message_router_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Router id is out of the legal range. + //*************************************************************************** + class message_router_illegal_id : public etl::message_router_exception + { + public: + + message_router_illegal_id(string_type file_name_, numeric_type line_number_) + : message_router_exception(ETL_ERROR_TEXT("message router:illegal id", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + class imessage_router + { + public: + + virtual ~imessage_router() {} + virtual void receive(const etl::imessage& message) = 0; + virtual void receive(imessage_router& source, const etl::imessage& message) = 0; + virtual bool accepts(etl::message_id_t id) const = 0; + + //******************************************** + bool accepts(const etl::imessage& msg) const + { + return accepts(msg.message_id); + } + + //******************************************** + etl::message_router_id_t get_message_router_id() const + { + return message_router_id; + } + + //******************************************** + bool is_null_router() const + { + return (message_router_id == NULL_MESSAGE_ROUTER); + } + + //******************************************** + bool is_bus() const + { + return (message_router_id == MESSAGE_BUS); + } + + //******************************************** + void set_successor(imessage_router& successor_) + { + successor = &successor_; + } + + //******************************************** + imessage_router& get_successor() const + { + return *successor; + } + + //******************************************** + bool has_successor() const + { + return (successor != std::nullptr); + } + + enum + { + NULL_MESSAGE_ROUTER = 255, + MESSAGE_BUS = 254, + ALL_MESSAGE_ROUTERS = 253, + MAX_MESSAGE_ROUTER = 249 + }; + + protected: + + imessage_router(etl::message_router_id_t id_) + : successor(std::nullptr), + message_router_id(id_) + { + } + + imessage_router(etl::message_router_id_t id_, + imessage_router& successor_) + : successor(&successor_), + message_router_id(id_) + { + } + + private: + + // Disabled. + imessage_router(const imessage_router&); + imessage_router& operator =(const imessage_router&); + + etl::imessage_router* successor; + + etl::message_router_id_t message_router_id; + }; + + //*************************************************************************** + /// This router can be used either as a sink for messages + /// or as a producer-only of messages such an interrupt routine. + //*************************************************************************** + class null_message_router : public imessage_router + { + public: + + null_message_router() + : imessage_router(imessage_router::NULL_MESSAGE_ROUTER) + { + } + + //******************************************** + void receive(const etl::imessage&) + { + } + + //******************************************** + void receive(etl::imessage_router&, const etl::imessage&) + { + } + + //******************************************** + bool accepts(etl::message_id_t) const + { + return false; + } + + //******************************************** + static null_message_router& instance() + { + static null_message_router nmr; + return nmr; + } + }; + + //*************************************************************************** + /// Send a message to a router. + /// Sets the 'sender' to etl::null_message_router type. + //*************************************************************************** + inline static void send_message(etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a message to a router. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(source, message); + } + + /*[[[cog + import cog + ################################################ + # The first definition for all of the messages. + ################################################ + cog.outl("//***************************************************************************") + cog.outl("// The definition for all %s message types." % Handlers) + cog.outl("//***************************************************************************") + cog.outl("template <typename TDerived,") + cog.out(" ") + cog.out("typename T1, ") + for n in range(2, int(Handlers)): + cog.out("typename T%s = void, " % n) + if n % 4 == 0: + cog.outl("") + cog.out(" ") + cog.outl("typename T%s = void>" % int(Handlers)) + cog.out("class message_router") + cog.outl(" : public imessage_router") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" class message_packet") + cog.outl(" {") + cog.outl(" public:") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" explicit message_packet(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const size_t id = msg.message_id;") + cog.outl("") + cog.outl(" void* p = data;") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for n in range(1, int(Handlers) + 1): + cog.outl(" case T%s::ID: ::new (p) T%s(static_cast<const T%s&>(msg)); break;" % (n, n, n)) + cog.outl(" default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" template <typename T>") + cog.outl(" explicit message_packet(const T& msg)") + cog.outl(" {") + cog.out(" STATIC_ASSERT((etl::is_one_of<T, ") + for n in range(1, int(Handlers)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("""T%s>::value), "Unsupported type for this message packet");""" % int(Handlers)) + cog.outl("") + cog.outl(" void* p = data;") + cog.outl(" ::new (p) T(static_cast<const T&>(msg));") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" ~message_packet()") + cog.outl(" {") + cog.outl(" static_cast<etl::imessage*>(data)->~imessage();") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" etl::imessage& get()") + cog.outl(" {") + cog.outl(" return *static_cast<etl::imessage*>(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" const etl::imessage& get() const") + cog.outl(" {") + cog.outl(" return *static_cast<const etl::imessage*>(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.out(" SIZE = etl::largest<") + for n in range(1, int(Handlers)): + cog.out("T%s, " % n) + cog.outl("T%s>::size," % int(Handlers)) + cog.out(" ALIGNMENT = etl::largest<") + for n in range(1, int(Handlers)): + cog.out("T%s, " % n) + cog.outl("T%s>::alignment" % int(Handlers)) + cog.outl(" };") + cog.outl("") + cog.outl(" private:") + cog.outl("") + cog.outl(" typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;") + cog.outl(" };") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" message_router(etl::message_router_id_t id_)") + cog.outl(" : imessage_router(id_)") + cog.outl(" {") + cog.outl(" ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)") + cog.outl(" : imessage_router(id_, successor_)") + cog.outl(" {") + cog.outl(" ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" receive(etl::null_message_router::instance(), msg);") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const etl::message_id_t id = msg.message_id;") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for n in range(1, int(Handlers) + 1): + cog.out(" case T%d::ID:" % n) + cog.out(" static_cast<TDerived*>(this)->on_receive(source, static_cast<const T%d&>(msg));" % n) + cog.outl(" break;") + cog.outl(" default:") + cog.outl(" {") + cog.outl(" if (has_successor())") + cog.outl(" {") + cog.outl(" get_successor().receive(source, msg);") + cog.outl(" }") + cog.outl(" else") + cog.outl(" {") + cog.outl(" static_cast<TDerived*>(this)->on_receive_unknown(source, msg);") + cog.outl(" }") + cog.outl(" break;") + cog.outl(" }") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" using imessage_router::accepts;") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" bool accepts(etl::message_id_t id) const") + cog.outl(" {") + cog.outl(" switch (id)") + cog.outl(" {") + cog.out(" ") + for n in range(1, int(Handlers) + 1): + cog.out("case T%d::ID: " % n) + if n % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl(" return true; break;") + cog.outl(" default:") + cog.outl(" return false; break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("};") + + #################################### + # All of the other specialisations. + #################################### + for n in range(int(Handlers) - 1, 0, -1): + cog.outl("") + cog.outl("//***************************************************************************") + if n == 1: + cog.outl("// Specialisation for %d message type." % n) + else: + cog.outl("// Specialisation for %d message types." % n) + cog.outl("//***************************************************************************") + cog.outl("template <typename TDerived, ") + cog.out(" ") + for t in range(1, n): + cog.out("typename T%d, " % t) + if t % 4 == 0: + cog.outl("") + cog.out(" ") + cog.outl("typename T%d>" % n) + cog.out("class message_router<TDerived, ") + for t in range(1, n + 1): + cog.out("T%d, " % t) + if t % 16 == 0: + cog.outl("") + cog.out(" ") + for t in range(n + 1, int(Handlers)): + cog.out("void, ") + if t % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("void>") + cog.outl(" : public imessage_router") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" class message_packet") + cog.outl(" {") + cog.outl(" public:") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" explicit message_packet(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const size_t id = msg.message_id;") + cog.outl("") + cog.outl(" void* p = data;") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for t in range(1, n + 1): + cog.outl(" case T%s::ID: ::new (p) T%s(static_cast<const T%s&>(msg)); break;" % (t, t, t)) + cog.outl(" default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" template <typename T>") + cog.outl(" explicit message_packet(const T& msg)") + cog.outl(" {") + cog.out(" STATIC_ASSERT((etl::is_one_of<T, ") + for t in range(1, n): + cog.out("T%s, " % t) + if t % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("""T%s>::value), "Unsupported type for this message packet");""" % n) + cog.outl("") + cog.outl(" void* p = data;") + cog.outl(" ::new (p) T(static_cast<const T&>(msg));") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" ~message_packet()") + cog.outl(" {") + cog.outl(" static_cast<etl::imessage*>(data)->~imessage();") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" etl::imessage& get()") + cog.outl(" {") + cog.outl(" return *static_cast<etl::imessage*>(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" const etl::imessage& get() const") + cog.outl(" {") + cog.outl(" return *static_cast<const etl::imessage*>(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.out(" SIZE = etl::largest<") + for t in range(1, n): + cog.out("T%s, " % t) + cog.outl("T%s>::size," % n) + cog.out(" ALIGNMENT = etl::largest<") + for t in range(1, n): + cog.out("T%s, " % t) + cog.outl("T%s>::alignment" % n) + cog.outl(" };") + cog.outl("") + cog.outl(" private:") + cog.outl("") + cog.outl(" typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;") + cog.outl(" };") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" message_router(etl::message_router_id_t id_)") + cog.outl(" : imessage_router(id_)") + cog.outl(" {") + cog.outl(" ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)") + cog.outl(" : imessage_router(id_, successor_)") + cog.outl(" {") + cog.outl(" ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" receive(etl::null_message_router::instance(), msg);") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const size_t id = msg.message_id;") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for t in range(1, n + 1): + cog.out(" case T%d::ID:" % t) + cog.out(" static_cast<TDerived*>(this)->on_receive(source, static_cast<const T%d&>(msg));" % t) + cog.outl(" break;") + cog.outl(" default:") + cog.outl(" {") + cog.outl(" if (has_successor())") + cog.outl(" {") + cog.outl(" get_successor().receive(source, msg);") + cog.outl(" }") + cog.outl(" else") + cog.outl(" {") + cog.outl(" static_cast<TDerived*>(this)->on_receive_unknown(source, msg);") + cog.outl(" }") + cog.outl(" break;") + cog.outl(" }") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" using imessage_router::accepts;") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" bool accepts(etl::message_id_t id) const") + cog.outl(" {") + cog.outl(" switch (id)") + cog.outl(" {") + cog.out(" ") + for t in range(1, n + 1): + cog.out("case T%d::ID: " % t) + if t % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl("") + cog.outl(" return true; break;") + cog.outl(" default:") + cog.outl(" return false; break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/message_timer.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,659 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_MESSAGE_TIMER__ +#define __ETL_MESSAGE_TIMER__ + +#include <stdint.h> +#include <algorithm> + +#include "platform.h" +#include "nullptr.h" +#include "message_types.h" +#include "message.h" +#include "message_router.h" +#include "message_bus.h" +#include "static_assert.h" +#include "timer.h" +#include "atomic.h" + +#undef ETL_FILE +#define ETL_FILE "41" + +namespace etl +{ + //************************************************************************* + /// The configuration of a timer. + struct message_timer_data + { + //******************************************* + message_timer_data() + : p_message(std::nullptr), + p_router(std::nullptr), + period(0), + delta(etl::timer::state::INACTIVE), + destination_router_id(etl::imessage_bus::ALL_MESSAGE_ROUTERS), + id(etl::timer::id::NO_TIMER), + previous(etl::timer::id::NO_TIMER), + next(etl::timer::id::NO_TIMER), + repeating(true) + { + } + + //******************************************* + message_timer_data(etl::timer::id::type id_, + const etl::imessage& message_, + etl::imessage_router& irouter_, + uint32_t period_, + bool repeating_, + etl::message_router_id_t destination_router_id_) + : p_message(&message_), + p_router(&irouter_), + period(period_), + delta(etl::timer::state::INACTIVE), + id(id_), + previous(etl::timer::id::NO_TIMER), + next(etl::timer::id::NO_TIMER), + repeating(repeating_) + { + if (irouter_.is_bus()) + { + destination_router_id = destination_router_id_; + } + else + { + destination_router_id = etl::imessage_bus::ALL_MESSAGE_ROUTERS; + } + } + + //******************************************* + /// Returns true if the timer is active. + //******************************************* + bool is_active() const + { + return delta != etl::timer::state::INACTIVE; + } + + //******************************************* + /// Sets the timer to the inactive state. + //******************************************* + void set_inactive() + { + delta = etl::timer::state::INACTIVE; + } + + const etl::imessage* p_message; + etl::imessage_router* p_router; + uint32_t period; + uint32_t delta; + etl::message_router_id_t destination_router_id; + etl::timer::id::type id; + uint_least8_t previous; + uint_least8_t next; + bool repeating; + + private: + + // Disabled. + message_timer_data(const message_timer_data& other); + message_timer_data& operator =(const message_timer_data& other); + }; + + namespace __private_message_timer__ + { + //************************************************************************* + /// A specialised intrusive linked list for timer data. + //************************************************************************* + class list + { + public: + + //******************************* + list(etl::message_timer_data* ptimers_) + : head(etl::timer::id::NO_TIMER), + tail(etl::timer::id::NO_TIMER), + current(etl::timer::id::NO_TIMER), + ptimers(ptimers_) + { + } + + //******************************* + bool empty() const + { + return head == etl::timer::id::NO_TIMER; + } + + //******************************* + // Inserts the timer at the correct delta position + //******************************* + void insert(etl::timer::id::type id_) + { + etl::message_timer_data& timer = ptimers[id_]; + + if (head == etl::timer::id::NO_TIMER) + { + // No entries yet. + head = id_; + tail = id_; + timer.previous = etl::timer::id::NO_TIMER; + timer.next = etl::timer::id::NO_TIMER; + } + else + { + // We already have entries. + etl::timer::id::type test_id = begin(); + + while (test_id != etl::timer::id::NO_TIMER) + { + etl::message_timer_data& test = ptimers[test_id]; + + // Find the correct place to insert. + if (timer.delta <= test.delta) + { + if (test.id == head) + { + head = timer.id; + } + + // Insert before test. + timer.previous = test.previous; + test.previous = timer.id; + timer.next = test.id; + + // Adjust the next delta to compensate. + test.delta -= timer.delta; + + if (timer.previous != etl::timer::id::NO_TIMER) + { + ptimers[timer.previous].next = timer.id; + } + break; + } + else + { + timer.delta -= test.delta; + } + + test_id = next(test_id); + } + + // Reached the end? + if (test_id == etl::timer::id::NO_TIMER) + { + // Tag on to the tail. + ptimers[tail].next = timer.id; + timer.previous = tail; + timer.next = etl::timer::id::NO_TIMER; + tail = timer.id; + } + } + } + + //******************************* + void remove(etl::timer::id::type id_, bool has_expired) + { + etl::message_timer_data& timer = ptimers[id_]; + + if (head == id_) + { + head = timer.next; + } + else + { + ptimers[timer.previous].next = timer.next; + } + + if (tail == id_) + { + tail = timer.previous; + } + else + { + ptimers[timer.next].previous = timer.previous; + } + + if (!has_expired) + { + // Adjust the next delta. + if (timer.next != etl::timer::id::NO_TIMER) + { + ptimers[timer.next].delta += timer.delta; + } + } + + timer.previous = etl::timer::id::NO_TIMER; + timer.next = etl::timer::id::NO_TIMER; + timer.delta = etl::timer::state::INACTIVE; + } + + //******************************* + etl::message_timer_data& front() + { + return ptimers[head]; + } + + //******************************* + etl::timer::id::type begin() + { + current = head; + return current; + } + + //******************************* + etl::timer::id::type previous(etl::timer::id::type last) + { + current = ptimers[last].previous; + return current; + } + + //******************************* + etl::timer::id::type next(etl::timer::id::type last) + { + current = ptimers[last].next; + return current; + } + + //******************************* + void clear() + { + etl::timer::id::type id = begin(); + + while (id != etl::timer::id::NO_TIMER) + { + etl::message_timer_data& timer = ptimers[id]; + id = next(id); + timer.next = etl::timer::id::NO_TIMER; + } + + head = etl::timer::id::NO_TIMER; + tail = etl::timer::id::NO_TIMER; + current = etl::timer::id::NO_TIMER; + } + + private: + + etl::timer::id::type head; + etl::timer::id::type tail; + etl::timer::id::type current; + + etl::message_timer_data* const ptimers; + }; + } + + //*************************************************************************** + /// Interface for message timer + //*************************************************************************** + class imessage_timer + { + public: + + //******************************************* + /// Register a timer. + //******************************************* + etl::timer::id::type register_timer(const etl::imessage& message_, + etl::imessage_router& router_, + uint32_t period_, + bool repeating_, + etl::message_router_id_t destination_router_id_ = etl::imessage_router::ALL_MESSAGE_ROUTERS) + { + etl::timer::id::type id = etl::timer::id::NO_TIMER; + + disable_timer_updates(); + + bool is_space = (registered_timers < MAX_TIMERS); + + if (is_space) + { + // There's no point adding null message routers. + if (!router_.is_null_router()) + { + // Search for the free space. + for (uint_least8_t i = 0; i < MAX_TIMERS; ++i) + { + etl::message_timer_data& timer = timer_array[i]; + + if (timer.id == etl::timer::id::NO_TIMER) + { + // Create in-place. + new (&timer) message_timer_data(i, message_, router_, period_, repeating_, destination_router_id_); + ++registered_timers; + id = i; + break; + } + } + } + } + + enable_timer_updates(); + + return id; + } + + //******************************************* + /// Unregister a timer. + //******************************************* + bool unregister_timer(etl::timer::id::type id_) + { + bool result = false; + + if (id_ != etl::timer::id::NO_TIMER) + { + disable_timer_updates(); + + etl::message_timer_data& timer = timer_array[id_]; + + if (timer.id != etl::timer::id::NO_TIMER) + { + if (timer.is_active()) + { + active_list.remove(timer.id, true); + + // Reset in-place. + new (&timer) message_timer_data(); + --registered_timers; + + result = true; + } + } + + enable_timer_updates(); + } + + return result; + } + + //******************************************* + /// Enable/disable the timer. + //******************************************* + void enable(bool state_) + { + enabled = state_; + } + + //******************************************* + /// Get the enable/disable state. + //******************************************* + bool is_running() const + { + return enabled; + } + + //******************************************* + /// Clears the timer of data. + //******************************************* + void clear() + { + disable_timer_updates(); + + active_list.clear(); + + for (int i = 0; i < MAX_TIMERS; ++i) + { + new (&timer_array[i]) message_timer_data(); + } + + registered_timers = 0; + + enable_timer_updates(); + } + + //******************************************* + // Called by the timer service to indicate the + // amount of time that has elapsed since the last successful call to 'tick'. + // Returns true if the tick was processed, + // false if not. + //******************************************* + bool tick(uint32_t count) + { + if (enabled) + { + if (process_semaphore.load() == 0) + { + // We have something to do? + bool has_active = !active_list.empty(); + + if (has_active) + { + while (has_active && (count >= active_list.front().delta)) + { + etl::message_timer_data& timer = active_list.front(); + + count -= timer.delta; + + active_list.remove(timer.id, true); + + if (timer.repeating) + { + timer.delta = timer.period; + active_list.insert(timer.id); + } + + if (timer.p_router != std::nullptr) + { + if (timer.p_router->is_bus()) + { + // Send to a message bus. + etl::imessage_bus& bus = static_cast<etl::imessage_bus&>(*(timer.p_router)); + bus.receive(timer.destination_router_id, *(timer.p_message)); + } + else + { + // Send to a router. + timer.p_router->receive(*(timer.p_message)); + } + } + + has_active = !active_list.empty(); + } + + if (has_active) + { + // Subtract any remainder from the next due timeout. + active_list.front().delta -= count; + } + } + + return true; + } + } + + return false; + } + + //******************************************* + /// Starts a timer. + //******************************************* + bool start(etl::timer::id::type id_, bool immediate_ = false) + { + bool result = false; + + disable_timer_updates(); + + // Valid timer id? + if (id_ != etl::timer::id::NO_TIMER) + { + etl::message_timer_data& timer = timer_array[id_]; + + // Registered timer? + if (timer.id != etl::timer::id::NO_TIMER) + { + // Has a valid period. + if (timer.period != etl::timer::state::INACTIVE) + { + if (timer.is_active()) + { + active_list.remove(timer.id, false); + } + + timer.delta = immediate_ ? 0 : timer.period; + active_list.insert(timer.id); + + result = true; + } + } + } + + enable_timer_updates(); + + return result; + } + + //******************************************* + /// Stops a timer. + //******************************************* + bool stop(etl::timer::id::type id_) + { + bool result = false; + + disable_timer_updates(); + + // Valid timer id? + if (id_ != etl::timer::id::NO_TIMER) + { + etl::message_timer_data& timer = timer_array[id_]; + + // Registered timer? + if (timer.id != etl::timer::id::NO_TIMER) + { + if (timer.is_active()) + { + active_list.remove(timer.id, false); + result = true; + } + } + } + + enable_timer_updates(); + + return result; + } + + //******************************************* + /// Sets a timer's period. + //******************************************* + bool set_period(etl::timer::id::type id_, uint32_t period_) + { + if (stop(id_)) + { + timer_array[id_].period = period_; + return start(id_); + } + + return false; + } + + //******************************************* + /// Sets a timer's mode. + //******************************************* + bool set_mode(etl::timer::id::type id_, bool repeating_) + { + if (stop(id_)) + { + timer_array[id_].repeating = repeating_; + return start(id_); + } + + return false; + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + imessage_timer(message_timer_data* const timer_array_, const uint_least8_t MAX_TIMERS_) + : timer_array(timer_array_), + active_list(timer_array_), + enabled(false), + process_semaphore(0), + registered_timers(0), + MAX_TIMERS(MAX_TIMERS_) + { + } + + private: + + //******************************************* + /// Enable timer callback events. + //******************************************* + void enable_timer_updates() + { + --process_semaphore; + } + + //******************************************* + /// Disable timer callback events. + //******************************************* + void disable_timer_updates() + { + ++process_semaphore; + } + + // The array of timer data structures. + message_timer_data* const timer_array; + + // The list of active timers. + __private_message_timer__::list active_list; + + volatile bool enabled; + volatile etl::timer_semaphore_t process_semaphore; + volatile uint_least8_t registered_timers; + + public: + + const uint_least8_t MAX_TIMERS; + }; + + //*************************************************************************** + /// The message timer + //*************************************************************************** + template <uint_least8_t MAX_TIMERS_> + class message_timer : public etl::imessage_timer + { + public: + + STATIC_ASSERT(MAX_TIMERS_ <= 254, "No more than 254 timers are allowed"); + + //******************************************* + /// Constructor. + //******************************************* + message_timer() + : imessage_timer(timer_array, MAX_TIMERS_) + { + } + + private: + + message_timer_data timer_array[MAX_TIMERS_]; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/message_types.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,49 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_MESSAGE_DEFS__ +#define __ETL_MESSAGE_DEFS__ + +#include <stdint.h> + +#include "platform.h" + +namespace etl +{ + /// Allow alternative type for message id. +#if !defined(ETL_MESSAGE_ID_TYPE) + typedef uint_least8_t message_id_t; +#else + typedef ETL_MESSAGE_ID_TYPE message_id_t; +#endif + + typedef uint_least8_t message_router_id_t; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimap.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,2045 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove, rlindeman + +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_MULTIMAP__ +#define __ETL_MULTIMAP__ + +#include <stddef.h> +#include <iterator> +#include <algorithm> +#include <functional> + +#include "platform.h" +#include "container.h" +#include "pool.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "nullptr.h" +#include "type_traits.h" +#include "parameter_type.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#undef ETL_FILE +#define ETL_FILE "9" + +//***************************************************************************** +/// A multimap with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the map. + ///\ingroup map + //*************************************************************************** + class multimap_exception : public etl::exception + { + public: + + multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the map. + ///\ingroup map + //*************************************************************************** + class multimap_full : public etl::multimap_exception + { + public: + + multimap_full(string_type file_name_, numeric_type line_number_) + : etl::multimap_exception("multimap:full", file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Map out of bounds exception. + ///\ingroup map + //*************************************************************************** + class multimap_out_of_bounds : public etl::multimap_exception + { + public: + + multimap_out_of_bounds(string_type file_name_, numeric_type line_number_) + : etl::multimap_exception("multimap:bounds", file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the map. + ///\ingroup map + //*************************************************************************** + class multimap_iterator : public etl::multimap_exception + { + public: + + multimap_iterator(string_type file_name_, numeric_type line_number_) + : etl::multimap_exception("multimap:iterator", file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for all maps. + ///\ingroup map + //*************************************************************************** + class multimap_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of map. + + //************************************************************************* + /// Gets the size of the map. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Gets the maximum possible size of the map. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + //************************************************************************* + /// Checks to see if the map is empty. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Checks to see if the map is full. + //************************************************************************* + bool full() const + { + return current_size == CAPACITY; + } + + //************************************************************************* + /// Returns the capacity of the vector. + ///\return The capacity of the vector. + //************************************************************************* + size_type capacity() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + enum + { + kLeft, + kRight, + kNeither + }; + + //************************************************************************* + /// The node element in the multimap. + //************************************************************************* + struct Node + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + Node() : + weight(kNeither), + dir(kNeither) + { + } + + //*********************************************************************** + /// Marks the node as a leaf. + //*********************************************************************** + void mark_as_leaf() + { + weight = kNeither; + dir = kNeither; + parent = std::nullptr; + children[0] = std::nullptr; + children[1] = std::nullptr; + } + + Node* parent; + Node* children[2]; + uint_least8_t weight; + uint_least8_t dir; + }; + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + multimap_base(size_type max_size_) + : current_size(0) + , CAPACITY(max_size_) + , root_node(std::nullptr) + + { + } + + //************************************************************************* + /// Balance the critical node at the position provided as needed + //************************************************************************* + void balance_node(Node*& critical_node) + { + // Step 1: Update weights for all children of the critical node up to the + // newly inserted node. This step is costly (in terms of traversing nodes + // multiple times during insertion) but doesn't require as much recursion + Node* weight_node = critical_node->children[critical_node->dir]; + while (weight_node) + { + // Keep going until we reach a terminal node (dir == kNeither) + if (kNeither != weight_node->dir) + { + // Does this insert balance the previous weight factor value? + if (weight_node->weight == 1 - weight_node->dir) + { + weight_node->weight = kNeither; + } + else + { + weight_node->weight = weight_node->dir; + } + + // Update weight factor node to point to next node + weight_node = weight_node->children[weight_node->dir]; + } + else + { + // Stop loop, terminal node found + break; + } + } // while(weight_node) + + // Step 2: Update weight for critical_node or rotate tree to balance node + if (kNeither == critical_node->weight) + { + critical_node->weight = critical_node->dir; + } + // If direction is different than weight, then it will now be balanced + else if (critical_node->dir != critical_node->weight) + { + critical_node->weight = kNeither; + } + // Rotate is required to balance the tree at the critical node + else + { + // If critical node matches child node direction then perform a two + // node rotate in the direction of the critical node + if (critical_node->weight == critical_node->children[critical_node->dir]->dir) + { + rotate_2node(critical_node, critical_node->dir); + } + // Otherwise perform a three node rotation in the direction of the + // critical node + else + { + rotate_3node(critical_node, critical_node->dir, + critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); + } + } + } + + //************************************************************************* + /// Rotate two nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_2node(Node*& position, uint_least8_t dir) + { + // A C A B + // B C -> A E OR B C -> D A + // D E B D D E E C + // C (new position) becomes the root + // A (position) takes ownership of D as its children[kRight] child + // C (new position) takes ownership of A as its left child + // OR + // B (new position) becomes the root + // A (position) takes ownership of E as its left child + // B (new position) takes ownership of A as its right child + + // Capture new root (either B or C depending on dir) and its parent + Node* new_root = position->children[dir]; + + // Replace position's previous child with new root's other child + position->children[dir] = new_root->children[1 - dir]; + // Update new root's other child parent pointer + if (position->children[dir]) + { + position->children[dir]->parent = position; + } + + // New root's parent becomes current position's parent + new_root->parent = position->parent; + new_root->children[1 - dir] = position; + new_root->dir = 1 - dir; + + // Clear weight factor from current position + position->weight = kNeither; + // Position's parent becomes new_root + position->parent = new_root; + position = new_root; + // Clear weight factor from new root + position->weight = kNeither; + } + + //************************************************************************* + /// Rotate three nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third) + { + // __A__ __E__ __A__ __D__ + // _B_ C -> B A OR B _C_ -> A C + // D E D F G C D E B F G E + // F G F G + // E (new position) becomes the root + // B (position) takes ownership of F as its left child + // A takes ownership of G as its right child + // OR + // D (new position) becomes the root + // A (position) takes ownership of F as its right child + // C takes ownership of G as its left child + + // Capture new root (either E or D depending on dir) + Node* new_root = position->children[dir]->children[1 - dir]; + // Set weight factor for B or C based on F or G existing and being a different than dir + position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; + + // Detach new root from its tree (replace with new roots child) + position->children[dir]->children[1 - dir] = new_root->children[dir]; + // Update new roots child parent pointer + if (new_root->children[dir]) + { + new_root->children[dir]->parent = position->children[dir]; + } + + // Attach current left tree to new root and update its parent + new_root->children[dir] = position->children[dir]; + position->children[dir]->parent = new_root; + + // Set weight factor for A based on F or G + position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; + + // Move new root's right tree to current roots left tree + position->children[dir] = new_root->children[1 - dir]; + if (new_root->children[1 - dir]) + { + new_root->children[1 - dir]->parent = position; + } + + // Attach current root to new roots right tree and assume its parent + new_root->parent = position->parent; + new_root->children[1 - dir] = position; + new_root->dir = 1 - dir; + + // Update current position's parent and replace with new root + position->parent = new_root; + position = new_root; + // Clear weight factor for new current position + position->weight = kNeither; + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; // find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(const Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(const Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* find_limit_node(Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Attach the provided node to the position provided + //************************************************************************* + void attach_node(Node* parent, Node*& position, Node& node) + { + // Mark new node as leaf on attach to tree at position provided + node.mark_as_leaf(); + + // Keep track of this node's parent + node.parent = parent; + + // Add the node here + position = &node; + + // One more. + ++current_size; + } + + //************************************************************************* + /// Detach the node at the position provided + //************************************************************************* + void detach_node(Node*& position, Node*& replacement) + { + // Make temporary copy of actual nodes involved because we might lose + // their references in the process (e.g. position is the same as + // replacement or replacement is a child of position) + Node* detached = position; + Node* swap = replacement; + + // Update current position to point to swap (replacement) node first + position = swap; + + // Update replacement node to point to child in opposite direction + // otherwise we might lose the other child of the swap node + replacement = swap->children[1 - swap->dir]; + + // Point swap node to detached node's parent, children and weight + swap->parent = detached->parent; + swap->children[kLeft] = detached->children[kLeft]; + swap->children[kRight] = detached->children[kRight]; + if (swap->children[kLeft]) + { + swap->children[kLeft]->parent = swap; + } + if (swap->children[kRight]) + { + swap->children[kRight]->parent = swap; + } + swap->weight = detached->weight; + } + + size_type current_size; ///< The number of the used nodes. + const size_type CAPACITY; ///< The maximum size of the map. + Node* root_node; ///< The node that acts as the multimap root. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// A templated base for all etl::multimap types. + ///\ingroup map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + class imultimap : public etl::multimap_base + { + public: + + typedef std::pair<const TKey, TMapped> value_type; + typedef const TKey key_type; + typedef TMapped mapped_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + //************************************************************************* + /// How to compare two key elements. + //************************************************************************* + struct key_comp + { + bool operator ()(const key_type& key1, const key_type& key2) const + { + return key_compare()(key1, key2); + } + }; + + //************************************************************************* + /// How to compare two value elements. + //************************************************************************* + struct value_comp + { + bool operator ()(const value_type& value1, const value_type& value2) const + { + return key_compare()(value1.first, value2.first); + } + }; + + protected: + + //************************************************************************* + /// The data node element in the multimap. + //************************************************************************* + struct Data_Node : public Node + { + explicit Data_Node(value_type value_) + : value(value_) + { + } + + value_type value; + }; + + /// Defines the key value parameter type + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + //************************************************************************* + /// How to compare node elements. + //************************************************************************* + bool node_comp(const Data_Node& node1, const Data_Node& node2) const + { + return key_compare()(node1.value.first, node2.value.first); + } + + bool node_comp(const Data_Node& node, key_parameter_t key) const + { + return key_compare()(node.value.first, key); + } + + bool node_comp(key_parameter_t key, const Data_Node& node) const + { + return key_compare()(key, node.value.first); + } + + private: + + /// The pool of data nodes used in the multimap. + ipool* p_node_pool; + + //************************************************************************* + /// Downcast a Node* to a Data_Node* + //************************************************************************* + static Data_Node* data_cast(Node* p_node) + { + return static_cast<Data_Node*>(p_node); + } + + //************************************************************************* + /// Downcast a Node& to a Data_Node& + //************************************************************************* + static Data_Node& data_cast(Node& node) + { + return static_cast<Data_Node&>(node); + } + + //************************************************************************* + /// Downcast a const Node* to a const Data_Node* + //************************************************************************* + static const Data_Node* data_cast(const Node* p_node) + { + return static_cast<const Data_Node*>(p_node); + } + + //************************************************************************* + /// Downcast a const Node& to a const Data_Node& + //************************************************************************* + static const Data_Node& data_cast(const Node& node) + { + return static_cast<const Data_Node&>(node); + } + + public: + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type> + { + public: + + friend class imultimap; + + iterator() + : p_multimap(std::nullptr) + , p_node(std::nullptr) + { + } + + iterator(imultimap& multimap) + : p_multimap(&multimap) + , p_node(std::nullptr) + { + } + + iterator(imultimap& multimap, Node* node) + : p_multimap(&multimap) + , p_node(node) + { + } + + iterator(const iterator& other) + : p_multimap(other.p_multimap) + , p_node(other.p_node) + { + } + + ~iterator() + { + } + + iterator& operator ++() + { + p_multimap->next_node(p_node); + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_multimap->next_node(p_node); + return temp; + } + + iterator& operator --() + { + p_multimap->prev_node(p_node); + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + p_multimap->prev_node(p_node); + return temp; + } + + iterator operator =(const iterator& other) + { + p_multimap = other.p_multimap; + p_node = other.p_node; + return *this; + } + + reference operator *() + { + return imultimap::data_cast(p_node)->value; + } + + const_reference operator *() const + { + return imultimap::data_cast(p_node)->value; + } + + pointer operator &() + { + return &(imultimap::data_cast(p_node)->value); + } + + const_pointer operator &() const + { + return &(imultimap::data_cast(p_node)->value); + } + + pointer operator ->() + { + return &(imultimap::data_cast(p_node)->value); + } + + const_pointer operator ->() const + { + return &(imultimap::data_cast(p_node)->value); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + // Pointer to multimap associated with this iterator + imultimap* p_multimap; + + // Pointer to the current node for this iterator + Node* p_node; + }; + friend class iterator; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> + { + public: + + friend class imultimap; + + const_iterator() + : p_multimap(std::nullptr) + , p_node(std::nullptr) + { + } + + const_iterator(const imultimap& multimap) + : p_multimap(&multimap) + , p_node(std::nullptr) + { + } + + const_iterator(const imultimap& multimap, const Node* node) + : p_multimap(&multimap) + , p_node(node) + { + } + + const_iterator(const typename imultimap::iterator& other) + : p_multimap(other.p_multimap) + , p_node(other.p_node) + { + } + + const_iterator(const const_iterator& other) + : p_multimap(other.p_multimap) + , p_node(other.p_node) + { + } + + ~const_iterator() + { + } + + const_iterator& operator ++() + { + p_multimap->next_node(p_node); + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_multimap->next_node(p_node); + return temp; + } + + const_iterator& operator --() + { + p_multimap->prev_node(p_node); + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + p_multimap->prev_node(p_node); + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_multimap = other.p_multimap; + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return imultimap::data_cast(p_node)->value; + } + + const_pointer operator &() const + { + return imultimap::data_cast(p_node)->value; + } + + const_pointer operator ->() const + { + return &(imultimap::data_cast(p_node)->value); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + // Pointer to multimap associated with this iterator + const imultimap* p_multimap; + + // Pointer to the current node for this iterator + const Node* p_node; + }; + friend class const_iterator; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + + //************************************************************************* + /// Gets the beginning of the multimap. + //************************************************************************* + iterator begin() + { + return iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the beginning of the multimap. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the end of the multimap. + //************************************************************************* + iterator end() + { + return iterator(*this); + } + + //************************************************************************* + /// Gets the end of the multimap. + //************************************************************************* + const_iterator end() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the beginning of the multimap. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the end of the multimap. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft))); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft))); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft))); + } + + //********************************************************************* + /// Assigns values to the multimap. + /// If asserts or exceptions are enabled, emits map_full if the multimap does not have enough free space. + /// If asserts or exceptions are enabled, emits map_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { + initialise(); + insert(first, last); + } + + //************************************************************************* + /// Clears the multimap. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Counts the number of elements that contain the key specified. + ///\param key The key to search for. + ///\return 1 if element was found, 0 otherwise. + //********************************************************************* + size_type count(key_parameter_t key) const + { + return count_nodes(key); + } + + //************************************************************************* + /// Returns two iterators with bounding (lower bound, upper bound) the key + /// provided + //************************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + return std::make_pair<iterator, iterator>( + iterator(*this, find_lower_node(root_node, key)), + iterator(*this, find_upper_node(root_node, key))); + } + + //************************************************************************* + /// Returns two const iterators with bounding (lower bound, upper bound) + /// the key provided. + //************************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + return std::make_pair<const_iterator, const_iterator>( + const_iterator(*this, find_lower_node(root_node, key)), + const_iterator(*this, find_upper_node(root_node, key))); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + void erase(iterator position) + { + // Remove the node by its node specified in iterator position + (void)erase(const_iterator(position)); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase(const_iterator position) + { + // Cast const away from node to be removed. This is necessary because the + // STL definition of this method requires we provide the next node in the + // sequence as an iterator. + Node* node = const_cast<Node*>(position.p_node); + iterator next(*this, node); + ++next; + + // Remove the non-const node provided + remove_node(node); + + return next; + } + + //************************************************************************* + // Erase the key specified. + //************************************************************************* + size_type erase(key_parameter_t key) + { + // Number of nodes removed + size_type d = 0; + const_iterator lower(*this, find_lower_node(root_node, key)); + const_iterator upper(*this, find_upper_node(root_node, key)); + while (lower != upper) + { + // Increment count for each node removed + ++d; + // Remove node using the other erase method + (void)erase(lower++); + } + + // Return the total count erased + return d; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(iterator first, iterator last) + { + iterator next; + while (first != last) + { + next = erase(const_iterator(first++)); + } + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + iterator next; + while (first != last) + { + next = erase(first++); + } + + return next; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_parameter_t key) + { + return iterator(*this, find_node(root_node, key)); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + return const_iterator(*this, find_node(root_node, key)); + } + + //********************************************************************* + /// Inserts a value to the multimap. + /// If asserts or exceptions are enabled, emits map_full if the multimap is already full. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const value_type& value) + { + // Default to no inserted node + Node* inserted_node = std::nullptr; + + ETL_ASSERT(!full(), ETL_ERROR(multimap_full)); + + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might be std::nullptr if node was a duplicate) + inserted_node = insert_node(root_node, node); + + // Insert node into tree and return iterator to new node location in tree + return iterator(*this, inserted_node); + } + + //********************************************************************* + /// Inserts a value to the multimap starting at the position recommended. + /// If asserts or exceptions are enabled, emits map_full if the multimap is already full. + ///\param position The position that would precede the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator /*position*/, const value_type& value) + { + // Ignore position provided and just do a normal insert + return insert(value); + } + + //********************************************************************* + /// Inserts a value to the multimap starting at the position recommended. + /// If asserts or exceptions are enabled, emits map_full if the multimap is already full. + ///\param position The position that would precede the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator /*position*/, const value_type& value) + { + // Ignore position provided and just do a normal insert + return insert(value); + } + + //********************************************************************* + /// Inserts a range of values to the multimap. + /// If asserts or exceptions are enabled, emits map_full if the multimap does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go before the key provided or end() + /// if all keys are considered to go before the key provided. + ///\return An iterator pointing to the element not before key or end() + //********************************************************************* + iterator lower_bound(key_parameter_t key) + { + return iterator(*this, find_lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go before the key provided + /// or end() if all keys are considered to go before the key provided. + ///\return An const_iterator pointing to the element not before key or end() + //********************************************************************* + const_iterator lower_bound(key_parameter_t key) const + { + return const_iterator(*this, find_lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go after the key provided or end() + /// if all keys are considered to go after the key provided. + ///\return An iterator pointing to the element after key or end() + //********************************************************************* + iterator upper_bound(key_parameter_t key) + { + return iterator(*this, find_upper_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go after the key provided + /// or end() if all keys are considered to go after the key provided. + ///\return An const_iterator pointing to the element after key or end() + //********************************************************************* + const_iterator upper_bound(key_parameter_t key) const + { + return const_iterator(*this, find_upper_node(root_node, key)); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + imultimap& operator = (const imultimap& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + imultimap(etl::ipool& node_pool, size_t max_size_) + : multimap_base(max_size_) + , p_node_pool(&node_pool) + { + } + + //************************************************************************* + /// Initialise the multimap. + //************************************************************************* + void initialise() + { + erase(begin(), end()); + } + + private: + + //************************************************************************* + /// Allocate a Data_Node. + //************************************************************************* + Data_Node& allocate_data_node(value_type value) + { + Data_Node& node = *p_node_pool->allocate<Data_Node>(); + ::new (&node.value) const value_type(value); + ++construct_count; + return node; + } + + //************************************************************************* + /// Destroy a Data_Node. + //************************************************************************* + void destroy_data_node(Data_Node& node) + { + node.value.~value_type(); + p_node_pool->release(&node); + --construct_count; + } + + //************************************************************************* + /// Count the nodes that match the key provided + //************************************************************************* + size_type count_nodes(key_parameter_t key) const + { + // Number of nodes that match the key provided result + size_type result = 0; + + // Find lower and upper nodes for the key provided + const Node* lower = find_lower_node(root_node, key); + const Node* upper = find_upper_node(root_node, key); + + // Loop from lower node to upper node and find nodes that match + while (lower != upper) + { + // Downcast found to Data_Node class for comparison and other operations + const Data_Node& data_node = imultimap::data_cast(*lower); + + if (!node_comp(key, data_node) && !node_comp(data_node, key)) + { + // This node matches the key provided + ++result; + } + + // Move on to the next node + next_node(lower); + } + + // Return the number of nodes that match + return result; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + Node* find_node(Node* position, key_parameter_t key) const + { + Node* found = std::nullptr; + while (position) + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& data_node = imultimap::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(key, data_node)) + { + // Keep searching for the node on the left + position = position->children[kLeft]; + } + else if (node_comp(data_node, key)) + { + // Keep searching for the node on the right + position = position->children[kRight]; + } + else + { + // We found one, keep looking for more on the left + found = position; + position = position->children[kLeft]; + } + } + + // Return the node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + const Node* find_node(const Node* position, key_parameter_t key) const + { + const Node* found = std::nullptr; + while (position) + { + // Downcast found to Data_Node class for comparison and other operations + const Data_Node& data_node = imultimap::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(key, data_node)) + { + // Keep searching for the node on the left + position = position->children[kLeft]; + } + else if (node_comp(data_node, key)) + { + // Keep searching for the node on the right + position = position->children[kRight]; + } + else + { + // We found one, keep looking for more on the left + found = position; + position = position->children[kLeft]; + } + } + + // Return the node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Find the node whose key is not considered to go before the key provided + //************************************************************************* + Node* find_lower_node(Node* position, key_parameter_t key) const + { + // Something at this position? keep going + Node* lower_node = std::nullptr; + while (position) + { + // Downcast lower node to Data_Node reference for key comparisons + Data_Node& data_node = imultimap::data_cast(*position); + // Compare the key value to the current lower node key value + if (node_comp(key, data_node)) + { + lower_node = position; + if (position->children[kLeft]) + { + position = position->children[kLeft]; + } + else + { + // Found lowest node + break; + } + } + else if (node_comp(data_node, key)) + { + position = position->children[kRight]; + } + else + { + // Make note of current position, but keep looking to left for more + lower_node = position; + position = position->children[kLeft]; + } + } + + // Return the lower_node position found + return lower_node; + } + + //************************************************************************* + /// Find the node whose key is considered to go after the key provided + //************************************************************************* + Node* find_upper_node(Node* position, key_parameter_t key) const + { + // Keep track of parent of last upper node + Node* upper_node = std::nullptr; + // Has an equal node been found? start with no + bool found = false; + while (position) + { + // Downcast position to Data_Node reference for key comparisons + Data_Node& data_node = imultimap::data_cast(*position); + // Compare the key value to the current upper node key value + if (node_comp(data_node, key)) + { + position = position->children[kRight]; + } + else if (node_comp(key, data_node)) + { + upper_node = position; + // If a node equal to key hasn't been found go left + if (!found && position->children[kLeft]) + { + position = position->children[kLeft]; + } + else + { + break; + } + } + else + { + // We found an equal item, break on next bigger item + found = true; + next_node(position); + } + } + + // Return the upper node position found (might be std::nullptr) + return upper_node; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + Node* insert_node(Node*& position, Data_Node& node) + { + // Find the location where the node belongs + Node* found = position; + + // Was position provided not empty? then find where the node belongs + if (position) + { + // Find the critical parent node (default to std::nullptr) + Node* critical_parent_node = std::nullptr; + Node* critical_node = root_node; + + while (found) + { + // Search for critical weight node (all nodes whose weight factor + // is set to kNeither (balanced) + if (kNeither != found->weight) + { + critical_node = found; + } + + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = imultimap::data_cast(*found); + + // Is the node provided to the left of the current position? + if (node_comp(node, found_data_node)) + { + // Update direction taken to insert new node in parent node + found->dir = kLeft; + } + // Is the node provided to the right of the current position? + else if (node_comp(found_data_node, node)) + { + // Update direction taken to insert new node in parent node + found->dir = kRight; + } + else + { + // Update direction taken to insert new node in parent (and + // duplicate) node to the right. + found->dir = kRight; + } + + // Is there a child of this parent node? + if (found->children[found->dir]) + { + // Will this node be the parent of the next critical node whose + // weight factor is set to kNeither (balanced)? + if (kNeither != found->children[found->dir]->weight) + { + critical_parent_node = found; + } + + // Keep looking for empty spot to insert new node + found = found->children[found->dir]; + } + else + { + // Attach node as a child of the parent node found + attach_node(found, found->children[found->dir], node); + + // Return newly added node + found = found->children[found->dir]; + + // Exit loop + break; + } + } + + // Was a critical node found that should be checked for balance? + if (critical_node) + { + if (critical_parent_node == std::nullptr && critical_node == root_node) + { + balance_node(root_node); + } + else if (critical_parent_node == std::nullptr && critical_node == position) + { + balance_node(position); + } + else + { + balance_node(critical_parent_node->children[critical_parent_node->dir]); + } + } + } + else + { + // Attach node to current position (which is assumed to be root) + attach_node(std::nullptr, position, node); + + // Return newly added node at current position + found = position; + } + + // Return the node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Remove the node specified from somewhere starting at the position + /// provided + //************************************************************************* + void remove_node(Node* node) + { + // If valid found node was provided then proceed with steps 1 through 5 + if (node) + { + // Downcast found node provided to Data_Node class + Data_Node& data_node = imultimap::data_cast(*node); + + // Keep track of node as found node + Node* found = node; + + // Step 1: Mark path from node provided back to the root node using the + // internal temporary dir member value and using the parent pointer. This + // will allow us to avoid recursion in finding the node in a tree that + //might contain duplicate keys to be found. + while (node) + { + if (node->parent) + { + // Which direction does parent use to get to this node? + node->parent->dir = + node->parent->children[kLeft] == node ? kLeft : kRight; + + // Make this nodes parent the next node + node = node->parent; + } + else + { + // Root node found - break loop + break; + } + } + + // Step 2: Follow the path provided above until we reach the node + // provided and look for the balance node to start rebalancing the tree + // from (up to the replacement node that will be found in step 3) + Node* balance = root_node; + while (node) + { + // Did we reach the node provided originally (found) then go to step 3 + if (node == found) + { + // Update the direction towards a replacement node at the found node + node->dir = node->children[kLeft] ? kLeft : kRight; + + // Exit loop and proceed with step 3 + break; + } + else + { + // If this nodes weight is kNeither or we are taking the shorter path + // to the next node and our sibling (on longer path) is balanced then + // we need to update the balance node to this node but all our + // ancestors will not require rebalancing + if ((node->weight == kNeither) || + (node->weight == (1 - node->dir) && + node->children[1 - node->dir]->weight == kNeither)) + { + // Update balance node to this node + balance = node; + } + + // Keep searching for found in the direction provided in step 1 + node = node->children[node->dir]; + } + } + // The value for node should not be std::nullptr at this point otherwise + // step 1 failed to provide the correct path to found. Step 5 will fail + // (probably subtly) if node should be std::nullptr at this point + + // Step 3: Find the node (node should be equal to found at this point) + // to replace found with (might end up equal to found) while also + // continuing to update balance the same as in step 2 above. + while (node) + { + // Replacement node found if its missing a child in the replace->dir + // value set at the end of step 2 above + if (node->children[node->dir] == std::nullptr) + { + // Exit loop once node to replace found is determined + break; + } + + // If this nodes weight is kNeither or we are taking the shorter path + // to the next node and our sibling (on longer path) is balanced then + // we need to update the balance node to this node but all our + // ancestors will not require rebalancing + if ((node->weight == kNeither) || + (node->weight == (1 - node->dir) && + node->children[1 - node->dir]->weight == kNeither)) + { + // Update balance node to this node + balance = node; + } + + // Keep searching for replacement node in the direction specified above + node = node->children[node->dir]; + + // Downcast node to Data_Node class for comparison operations + Data_Node& replace_data_node = imultimap::data_cast(*node); + + // Compare the key provided to the replace data node key + if (node_comp(data_node, replace_data_node)) + { + // Update the direction to the replace node + node->dir = kLeft; + } + else if (node_comp(replace_data_node, data_node)) + { + // Update the direction to the replace node + node->dir = kRight; + } + else + { + // Update the direction to the replace node + node->dir = node->children[kLeft] ? kLeft : kRight; + } + } // while(node) + + // Step 4: Update weights from balance to parent of node determined + // in step 3 above rotating (2 or 3 node rotations) as needed. + while (balance) + { + // Break when balance node reaches the parent of replacement node + if (balance->children[balance->dir] == std::nullptr) + { + break; + } + + // If balance node is balanced already (kNeither) then just imbalance + // the node in the opposite direction of the node being removed + if (balance->weight == kNeither) + { + balance->weight = 1 - balance->dir; + } + // If balance node is imbalanced in the opposite direction of the + // node being removed then the node now becomes balanced + else if (balance->weight == balance->dir) + { + balance->weight = kNeither; + } + // Otherwise a rotation is required at this node + else + { + int weight = balance->children[1 - balance->dir]->weight; + // Perform a 3 node rotation if weight is same as balance->dir + if (weight == balance->dir) + { + // Is the root node being rebalanced (no parent) + if (balance->parent == std::nullptr) + { + rotate_3node(root_node, 1 - balance->dir, + balance->children[1 - balance->dir]->children[balance->dir]->weight); + } + else + { + rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir, + balance->children[1 - balance->dir]->children[balance->dir]->weight); + } + } + // Already balanced, rebalance and make it heavy in opposite + // direction of the node being removed + else if (weight == kNeither) + { + // Is the root node being rebalanced (no parent) + if (balance->parent == std::nullptr) + { + rotate_2node(root_node, 1 - balance->dir); + root_node->weight = balance->dir; + } + else + { + // Balance parent might change during rotate, keep local copy + // to old parent so its weight can be updated after the 2 node + // rotate is completed + Node* old_parent = balance->parent; + rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir); + old_parent->children[old_parent->dir]->weight = balance->dir; + } + // Update balance node weight in opposite direction of node removed + balance->weight = 1 - balance->dir; + } + // Rebalance and leave it balanced + else + { + // Is the root node being rebalanced (no parent) + if (balance->parent == std::nullptr) + { + rotate_2node(root_node, 1 - balance->dir); + } + else + { + rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir); + } + } + } + + // Next balance node to consider + balance = balance->children[balance->dir]; + } // while(balance) + + // Step 5: Swap found with node (replacement) + if (found->parent) + { + // Handle traditional case + detach_node(found->parent->children[found->parent->dir], + node->parent->children[node->parent->dir]); + } + // Handle root node removal + else + { + // Valid replacement node for root node being removed? + if (node->parent) + { + detach_node(root_node, node->parent->children[node->parent->dir]); + } + else + { + // Found node and replacement node are both root node + detach_node(root_node, root_node); + } + } + + // One less. + --current_size; + + // Destroy the node detached above + destroy_data_node(data_node); + } // if(found) + } + + // Disable copy construction. + imultimap(const imultimap&); + }; + + //************************************************************************* + /// A templated multimap implementation that uses a fixed size buffer. + //************************************************************************* + template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> > + class multimap : public etl::imultimap<TKey, TValue, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + multimap() + : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE) + { + etl::imultimap<TKey, TValue, TCompare>::initialise(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + multimap(const multimap& other) + : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE) + { + etl::imultimap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + multimap(TIterator first, TIterator last) + : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE) + { + etl::imultimap<TKey, TValue, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~multimap() + { + etl::imultimap<TKey, TValue, TCompare>::initialise(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + multimap& operator = (const multimap& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + etl::imultimap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of data nodes used for the multimap. + etl::pool<typename etl::imultimap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool; + }; +} + +//*************************************************************************** +/// Equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> +///\ingroup lookup +//*************************************************************************** +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator ==(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs) +{ + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +//*************************************************************************** +/// Not equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> +///\ingroup lookup +//*************************************************************************** +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator !=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs) +{ + return !(lhs == rhs); +} + +//************************************************************************* +/// Less than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator <(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); +} + +//************************************************************************* +/// Greater than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator >(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs) +{ + return (rhs < lhs); +} + +//************************************************************************* +/// Less than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than or equal +/// to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator <=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs) +{ + return !(lhs > rhs); +} + +//************************************************************************* +/// Greater than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than or +/// equal to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename TKey, typename TMapped, typename TKeyCompare> +bool operator >=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs) +{ + return !(lhs < rhs); +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multiset.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,2025 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove, rlindeman + +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_MULTISET__ +#define __ETL_MULTISET__ + +#include <stddef.h> +#include <iterator> +#include <algorithm> +#include <functional> + +#include "platform.h" +#include "parameter_type.h" +#include "container.h" +#include "pool.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "nullptr.h" +#include "type_traits.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#undef ETL_FILE +#define ETL_FILE "10" + +//***************************************************************************** +/// A multiset with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the set. + ///\ingroup set + //*************************************************************************** + class multiset_exception : public etl::exception + { + public: + + multiset_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the set. + ///\ingroup set + //*************************************************************************** + class multiset_full : public etl::multiset_exception + { + public: + + multiset_full(string_type file_name_, numeric_type line_number_) + : etl::multiset_exception(ETL_ERROR_TEXT("multiset:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Map out of bounds exception. + ///\ingroup set + //*************************************************************************** + class multiset_out_of_bounds : public etl::multiset_exception + { + public: + + multiset_out_of_bounds(string_type file_name_, numeric_type line_number_) + : etl::multiset_exception(ETL_ERROR_TEXT("multiset:bounds", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the set. + ///\ingroup set + //*************************************************************************** + class multiset_iterator : public etl::multiset_exception + { + public: + + multiset_iterator(string_type file_name_, numeric_type line_number_) + : etl::multiset_exception(ETL_ERROR_TEXT("multiset:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for all sets. + ///\ingroup set + //*************************************************************************** + class multiset_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of set. + + //************************************************************************* + /// Gets the size of the set. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Gets the maximum possible size of the set. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + //************************************************************************* + /// Checks to see if the set is empty. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Checks to see if the set is full. + //************************************************************************* + bool full() const + { + return current_size == CAPACITY; + } + + //************************************************************************* + /// Returns the capacity of the vector. + ///\return The capacity of the vector. + //************************************************************************* + size_type capacity() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + enum + { + kLeft, + kRight, + kNeither + }; + + //************************************************************************* + /// The node element in the multiset. + //************************************************************************* + struct Node + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + Node() : + weight(kNeither), + dir(kNeither) + { + } + + //*********************************************************************** + /// Marks the node as a leaf. + //*********************************************************************** + void mark_as_leaf() + { + weight = kNeither; + dir = kNeither; + parent = std::nullptr; + children[0] = std::nullptr; + children[1] = std::nullptr; + } + + Node* parent; + Node* children[2]; + uint_least8_t weight; + uint_least8_t dir; + }; + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + multiset_base(size_type max_size_) + : current_size(0) + , CAPACITY(max_size_) + , root_node(std::nullptr) + { + } + + //************************************************************************* + /// Attach the provided node to the position provided + //************************************************************************* + void attach_node(Node* parent, Node*& position, Node& node) + { + // Mark new node as leaf on attach to tree at position provided + node.mark_as_leaf(); + + // Keep track of this node's parent + node.parent = parent; + + // Add the node here + position = &node; + + // One more. + ++current_size; + } + + //************************************************************************* + /// Detach the node at the position provided + //************************************************************************* + void detach_node(Node*& position, Node*& replacement) + { + // Make temporary copy of actual nodes involved because we might lose + // their references in the process (e.g. position is the same as + // replacement or replacement is a child of position) + Node* detached = position; + Node* swap = replacement; + + // Update current position to point to swap (replacement) node first + position = swap; + + // Update replacement node to point to child in opposite direction + // otherwise we might lose the other child of the swap node + replacement = swap->children[1 - swap->dir]; + + // Point swap node to detached node's parent, children and weight + swap->parent = detached->parent; + swap->children[kLeft] = detached->children[kLeft]; + swap->children[kRight] = detached->children[kRight]; + if (swap->children[kLeft]) + { + swap->children[kLeft]->parent = swap; + } + if (swap->children[kRight]) + { + swap->children[kRight]->parent = swap; + } + swap->weight = detached->weight; + } + + //************************************************************************* + /// Balance the critical node at the position provided as needed + //************************************************************************* + void balance_node(Node*& critical_node) + { + // Step 1: Update weights for all children of the critical node up to the + // newly inserted node. This step is costly (in terms of traversing nodes + // multiple times during insertion) but doesn't require as much recursion + Node* weight_node = critical_node->children[critical_node->dir]; + while (weight_node) + { + // Keep going until we reach a terminal node (dir == kNeither) + if (kNeither != weight_node->dir) + { + // Does this insert balance the previous weight factor value? + if (weight_node->weight == 1 - weight_node->dir) + { + weight_node->weight = kNeither; + } + else + { + weight_node->weight = weight_node->dir; + } + + // Update weight factor node to point to next node + weight_node = weight_node->children[weight_node->dir]; + } + else + { + // Stop loop, terminal node found + break; + } + } // while(weight_node) + + // Step 2: Update weight for critical_node or rotate tree to balance node + if (kNeither == critical_node->weight) + { + critical_node->weight = critical_node->dir; + } + // If direction is different than weight, then it will now be balanced + else if (critical_node->dir != critical_node->weight) + { + critical_node->weight = kNeither; + } + // Rotate is required to balance the tree at the critical node + else + { + // If critical node matches child node direction then perform a two + // node rotate in the direction of the critical node + if (critical_node->weight == critical_node->children[critical_node->dir]->dir) + { + rotate_2node(critical_node, critical_node->dir); + } + // Otherwise perform a three node rotation in the direction of the + // critical node + else + { + rotate_3node(critical_node, critical_node->dir, + critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); + } + } + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* find_limit_node(Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; // find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(const Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(const Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = position->parent; + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Rotate two nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_2node(Node*& position, uint_least8_t dir) + { + // A C A B + // B C -> A E OR B C -> D A + // D E B D D E E C + // C (new position) becomes the root + // A (position) takes ownership of D as its children[kRight] child + // C (new position) takes ownership of A as its left child + // OR + // B (new position) becomes the root + // A (position) takes ownership of E as its left child + // B (new position) takes ownership of A as its right child + + // Capture new root (either B or C depending on dir) and its parent + Node* new_root = position->children[dir]; + + // Replace position's previous child with new root's other child + position->children[dir] = new_root->children[1 - dir]; + // Update new root's other child parent pointer + if (position->children[dir]) + { + position->children[dir]->parent = position; + } + + // New root's parent becomes current position's parent + new_root->parent = position->parent; + new_root->children[1 - dir] = position; + new_root->dir = 1 - dir; + + // Clear weight factor from current position + position->weight = kNeither; + // Position's parent becomes new_root + position->parent = new_root; + position = new_root; + // Clear weight factor from new root + position->weight = kNeither; + } + + //************************************************************************* + /// Rotate three nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third) + { + // __A__ __E__ __A__ __D__ + // _B_ C -> B A OR B _C_ -> A C + // D E D F G C D E B F G E + // F G F G + // E (new position) becomes the root + // B (position) takes ownership of F as its left child + // A takes ownership of G as its right child + // OR + // D (new position) becomes the root + // A (position) takes ownership of F as its right child + // C takes ownership of G as its left child + + // Capture new root (either E or D depending on dir) + Node* new_root = position->children[dir]->children[1 - dir]; + // Set weight factor for B or C based on F or G existing and being a different than dir + position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither; + + // Detach new root from its tree (replace with new roots child) + position->children[dir]->children[1 - dir] = new_root->children[dir]; + // Update new roots child parent pointer + if (new_root->children[dir]) + { + new_root->children[dir]->parent = position->children[dir]; + } + + // Attach current left tree to new root and update its parent + new_root->children[dir] = position->children[dir]; + position->children[dir]->parent = new_root; + + // Set weight factor for A based on F or G + position->weight = third != kNeither && third == dir ? 1 - dir : kNeither; + + // Move new root's right tree to current roots left tree + position->children[dir] = new_root->children[1 - dir]; + if (new_root->children[1 - dir]) + { + new_root->children[1 - dir]->parent = position; + } + + // Attach current root to new roots right tree and assume its parent + new_root->parent = position->parent; + new_root->children[1 - dir] = position; + new_root->dir = 1 - dir; + + // Update current position's parent and replace with new root + position->parent = new_root; + position = new_root; + // Clear weight factor for new current position + position->weight = kNeither; + } + + size_type current_size; ///< The number of the used nodes. + const size_type CAPACITY; ///< The maximum size of the set. + Node* root_node; ///< The node that acts as the multiset root. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// A templated base for all etl::multiset types. + ///\ingroup set + //*************************************************************************** + template <typename T, typename TCompare> + class imultiset : public etl::multiset_base + { + public: + + typedef const T key_type; + typedef const T value_type; + typedef TCompare key_compare; + typedef TCompare value_compare; + typedef value_type& const_reference; + typedef value_type* const_pointer; + typedef size_t size_type; + + //************************************************************************* + /// How to compare two key elements. + //************************************************************************* + struct key_comp + { + bool operator ()(key_type& key1, key_type& key2) const + { + return key_compare()(key1, key2); + } + }; + + //************************************************************************* + /// How to compare two value elements. + //************************************************************************* + struct value_comp + { + bool operator ()(value_type& value1, value_type& value2) const + { + return value_compare()(value1, value2); + } + }; + + protected: + + //************************************************************************* + /// The data node element in the multiset. + //************************************************************************* + struct Data_Node : public Node + { + explicit Data_Node(value_type value_) + : value(value_) + { + } + + value_type value; + }; + + /// Defines the key value parameter type + typedef typename etl::parameter_type<T>::type key_parameter_t; + + //************************************************************************* + /// How to compare node elements. + //************************************************************************* + bool node_comp(const Data_Node& node1, const Data_Node& node2) const + { + return key_compare()(node1.value, node2.value); + } + bool node_comp(const Data_Node& node, key_parameter_t key) const + { + return key_compare()(node.value, key); + } + bool node_comp(key_parameter_t key, const Data_Node& node) const + { + return key_compare()(key, node.value); + } + + private: + + /// The pool of data nodes used in the multiset. + ipool* p_node_pool; + + //************************************************************************* + /// Downcast a Node* to a Data_Node* + //************************************************************************* + static Data_Node* data_cast(Node* p_node) + { + return static_cast<Data_Node*>(p_node); + } + + //************************************************************************* + /// Downcast a Node& to a Data_Node& + //************************************************************************* + static Data_Node& data_cast(Node& node) + { + return static_cast<Data_Node&>(node); + } + + //************************************************************************* + /// Downcast a const Node* to a const Data_Node* + //************************************************************************* + static const Data_Node* data_cast(const Node* p_node) + { + return static_cast<const Data_Node*>(p_node); + } + + //************************************************************************* + /// Downcast a const Node& to a const Data_Node& + //************************************************************************* + static const Data_Node& data_cast(const Node& node) + { + return static_cast<const Data_Node&>(node); + } + + public: + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type> + { + public: + + friend class imultiset; + + iterator() + : p_multiset(std::nullptr) + , p_node(std::nullptr) + { + } + + iterator(imultiset& multiset) + : p_multiset(&multiset) + , p_node(std::nullptr) + { + } + + iterator(imultiset& multiset, Node* node) + : p_multiset(&multiset) + , p_node(node) + { + } + + iterator(const iterator& other) + : p_multiset(other.p_multiset) + , p_node(other.p_node) + { + } + + ~iterator() + { + } + + iterator& operator ++() + { + p_multiset->next_node(p_node); + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_multiset->next_node(p_node); + return temp; + } + + iterator& operator --() + { + p_multiset->prev_node(p_node); + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + p_multiset->prev_node(p_node); + return temp; + } + + iterator operator =(const iterator& other) + { + p_multiset = other.p_multiset; + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return imultiset::data_cast(p_node)->value; + } + + const_pointer operator &() const + { + return &(imultiset::data_cast(p_node)->value); + } + + const_pointer operator ->() const + { + return &(imultiset::data_cast(p_node)->value); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + // Pointer to multiset associated with this iterator + imultiset* p_multiset; + + // Pointer to the current node for this iterator + Node* p_node; + }; + friend class iterator; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> + { + public: + + friend class imultiset; + + const_iterator() + : p_multiset(std::nullptr) + , p_node(std::nullptr) + { + } + + const_iterator(const imultiset& multiset) + : p_multiset(&multiset) + , p_node(std::nullptr) + { + } + + const_iterator(const imultiset& multiset, const Node* node) + : p_multiset(&multiset) + , p_node(node) + { + } + + const_iterator(const typename imultiset::iterator& other) + : p_multiset(other.p_multiset) + , p_node(other.p_node) + { + } + + const_iterator(const const_iterator& other) + : p_multiset(other.p_multiset) + , p_node(other.p_node) + { + } + + ~const_iterator() + { + } + + const_iterator& operator ++() + { + p_multiset->next_node(p_node); + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_multiset->next_node(p_node); + return temp; + } + + const_iterator& operator --() + { + p_multiset->prev_node(p_node); + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + p_multiset->prev_node(p_node); + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_multiset = other.p_multiset; + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return imultiset::data_cast(p_node)->value; + } + + const_pointer operator &() const + { + return imultiset::data_cast(p_node)->value; + } + + const_pointer operator ->() const + { + return &(imultiset::data_cast(p_node)->value); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_multiset == rhs.p_multiset && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + // Pointer to multiset associated with this iterator + const imultiset* p_multiset; + + // Pointer to the current node for this iterator + const Node* p_node; + }; + friend class const_iterator; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + + //************************************************************************* + /// Gets the beginning of the multiset. + //************************************************************************* + iterator begin() + { + return iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the beginning of the multiset. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the end of the multiset. + //************************************************************************* + iterator end() + { + return iterator(*this); + } + + //************************************************************************* + /// Gets the end of the multiset. + //************************************************************************* + const_iterator end() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the beginning of the multiset. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the end of the multiset. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft))); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft))); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft))); + } + + //********************************************************************* + /// Assigns values to the multiset. + /// If asserts or exceptions are enabled, emits set_full if the multiset does not have enough free space. + /// If asserts or exceptions are enabled, emits set_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { + initialise(); + insert(first, last); + } + + //************************************************************************* + /// Clears the multiset. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Counts the number of elements that contain the key specified. + ///\param key The key to search for. + ///\return 1 if element was found, 0 otherwise. + //********************************************************************* + size_type count(key_parameter_t key) const + { + return count_nodes(key); + } + + //************************************************************************* + /// Returns two iterators with bounding (lower bound, upper bound) the key + /// provided + //************************************************************************* + std::pair<iterator, iterator> equal_range(const value_type& key) + { + return std::make_pair<iterator, iterator>( + iterator(*this, find_lower_node(root_node, key)), + iterator(*this, find_upper_node(root_node, key))); + } + + //************************************************************************* + /// Returns two const iterators with bounding (lower bound, upper bound) + /// the key provided. + //************************************************************************* + std::pair<const_iterator, const_iterator> equal_range(const value_type& key) const + { + return std::make_pair<const_iterator, const_iterator>( + const_iterator(*this, find_lower_node(root_node, key)), + const_iterator(*this, find_upper_node(root_node, key))); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + void erase(iterator position) + { + // Remove the node by its node specified in iterator position + (void)erase(const_iterator(position)); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase(const_iterator position) + { + // Cast const away from node to be removed. This is necessary because the + // STL definition of this method requires we provide the next node in the + // sequence as an iterator. + Node* node = const_cast<Node*>(position.p_node); + iterator next(*this, node); + ++next; + + // Remove the non-const node provided + remove_node(node); + + return next; + } + + //************************************************************************* + // Erase the key specified. + //************************************************************************* + size_type erase(key_parameter_t key_value) + { + // Number of nodes removed + size_type d = 0; + const_iterator lower(*this, find_lower_node(root_node, key_value)); + const_iterator upper(*this, find_upper_node(root_node, key_value)); + while (lower != upper) + { + // Increment count for each node removed + ++d; + // Remove node using the other erase method + (void)erase(lower++); + } + + // Return the total count erased + return d; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(iterator first, iterator last) + { + iterator next; + while (first != last) + { + next = erase(const_iterator(first++)); + } + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + iterator next; + while (first != last) + { + next = erase(first++); + } + + return next; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_parameter_t key_value) + { + return iterator(*this, find_node(root_node, key_value)); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_parameter_t key_value) const + { + return const_iterator(*this, find_node(root_node, key_value)); + } + + //********************************************************************* + /// Inserts a value to the multiset. + /// If asserts or exceptions are enabled, emits set_full if the multiset is already full. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const value_type& value) + { + // Default to no inserted node + Node* inserted_node = std::nullptr; + + ETL_ASSERT(!full(), ETL_ERROR(multiset_full)); + + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might be std::nullptr if node was a duplicate) + inserted_node = insert_node(root_node, node); + + // Insert node into tree and return iterator to new node location in tree + return iterator(*this, inserted_node); + } + + //********************************************************************* + /// Inserts a value to the multiset starting at the position recommended. + /// If asserts or exceptions are enabled, emits set_full if the multiset is already full. + ///\param position The position that would precede the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator /*position*/, const value_type& value) + { + // Ignore position provided and just do a normal insert + return insert(value); + } + + //********************************************************************* + /// Inserts a value to the multiset starting at the position recommended. + /// If asserts or exceptions are enabled, emits set_full if the multiset is already full. + ///\param position The position that would precede the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator /*position*/, const value_type& value) + { + // Ignore position provided and just do a normal insert + return insert(value); + } + + //********************************************************************* + /// Inserts a range of values to the multiset. + /// If asserts or exceptions are enabled, emits set_full if the multiset does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go before the key provided or end() + /// if all keys are considered to go before the key provided. + ///\return An iterator pointing to the element not before key or end() + //********************************************************************* + iterator lower_bound(key_parameter_t key) + { + return iterator(*this, find_lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go before the key provided + /// or end() if all keys are considered to go before the key provided. + ///\return An const_iterator pointing to the element not before key or end() + //********************************************************************* + const_iterator lower_bound(key_parameter_t key) const + { + return const_iterator(*this, find_lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go after the key provided or end() + /// if all keys are considered to go after the key provided. + ///\return An iterator pointing to the element after key or end() + //********************************************************************* + iterator upper_bound(key_parameter_t key) + { + return iterator(*this, find_upper_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go after the key provided + /// or end() if all keys are considered to go after the key provided. + ///\return An const_iterator pointing to the element after key or end() + //********************************************************************* + const_iterator upper_bound(key_parameter_t key) const + { + return const_iterator(*this, find_upper_node(root_node, key)); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + imultiset& operator = (const imultiset& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + imultiset(etl::ipool& node_pool, size_t max_size_) + : etl::multiset_base(max_size_) + , p_node_pool(&node_pool) + { + } + + //************************************************************************* + /// Initialise the multiset. + //************************************************************************* + void initialise() + { + erase(begin(), end()); + } + + private: + + //************************************************************************* + /// Allocate a Data_Node. + //************************************************************************* + Data_Node& allocate_data_node(value_type value) + { + Data_Node& node = *p_node_pool->allocate<Data_Node>(); + ::new ((void*)&node.value) value_type(value); + ++construct_count; + return node; + } + + //************************************************************************* + /// Destroy a Data_Node. + //************************************************************************* + void destroy_data_node(Data_Node& node) + { + node.value.~value_type(); + p_node_pool->release(&node); + --construct_count; + } + + //************************************************************************* + /// Count the nodes that match the key provided + //************************************************************************* + size_type count_nodes(key_parameter_t key) const + { + // Number of nodes that match the key provided result + size_type result = 0; + + // Find lower and upper nodes for the key provided + const Node* lower = find_lower_node(root_node, key); + const Node* upper = find_upper_node(root_node, key); + + // Loop from lower node to upper node and find nodes that match + while (lower != upper) + { + // Downcast found to Data_Node class for comparison and other operations + const Data_Node& data_node = imultiset::data_cast(*lower); + + if (!node_comp(key, data_node) && !node_comp(data_node, key)) + { + // This node matches the key provided + ++result; + } + + // Move on to the next node + next_node(lower); + } + + // Return the number of nodes that match + return result; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + Node* find_node(Node* position, key_parameter_t key) const + { + Node* found = std::nullptr; + while (position) + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& data_node = imultiset::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(key, data_node)) + { + // Keep searching for the node on the left + position = position->children[kLeft]; + } + else if (node_comp(data_node, key)) + { + // Keep searching for the node on the right + position = position->children[kRight]; + } + else + { + // We found one, keep looking for more on the left + found = position; + position = position->children[kLeft]; + } + } + + // Return the node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + const Node* find_node(const Node* position, key_parameter_t key) const + { + const Node* found = std::nullptr; + while (position) + { + // Downcast found to Data_Node class for comparison and other operations + const Data_Node& data_node = imultiset::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(key, data_node)) + { + // Keep searching for the node on the left + position = position->children[kLeft]; + } + else if (node_comp(data_node, key)) + { + // Keep searching for the node on the right + position = position->children[kRight]; + } + else + { + // We found one, keep looking for more on the left + found = position; + position = position->children[kLeft]; + } + } + + // Return the node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Find the node whose key is not considered to go before the key provided + //************************************************************************* + Node* find_lower_node(Node* position, key_parameter_t key) const + { + // Something at this position? keep going + Node* lower_node = std::nullptr; + while (position) + { + // Downcast lower node to Data_Node reference for key comparisons + Data_Node& data_node = imultiset::data_cast(*position); + // Compare the key value to the current lower node key value + if (node_comp(key, data_node)) + { + lower_node = position; + if (position->children[kLeft]) + { + position = position->children[kLeft]; + } + else + { + // Found lowest node + break; + } + } + else if (node_comp(data_node, key)) + { + position = position->children[kRight]; + } + else + { + // Make note of current position, but keep looking to left for more + lower_node = position; + position = position->children[kLeft]; + } + } + + // Return the lower_node position found + return lower_node; + } + + //************************************************************************* + /// Find the node whose key is considered to go after the key provided + //************************************************************************* + Node* find_upper_node(Node* position, key_parameter_t key) const + { + // Keep track of parent of last upper node + Node* upper_node = std::nullptr; + // Has an equal node been found? start with no + bool found = false; + while (position) + { + // Downcast position to Data_Node reference for key comparisons + Data_Node& data_node = imultiset::data_cast(*position); + // Compare the key value to the current upper node key value + if (node_comp(data_node, key)) + { + position = position->children[kRight]; + } + else if (node_comp(key, data_node)) + { + upper_node = position; + // If a node equal to key hasn't been found go left + if (!found && position->children[kLeft]) + { + position = position->children[kLeft]; + } + else + { + break; + } + } + else + { + // We found an equal item, break on next bigger item + found = true; + next_node(position); + } + } + + // Return the upper node position found (might be std::nullptr) + return upper_node; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + Node* insert_node(Node*& position, Data_Node& node) + { + // Find the location where the node belongs + Node* found = position; + + // Was position provided not empty? then find where the node belongs + if (position) + { + // Find the critical parent node (default to std::nullptr) + Node* critical_parent_node = std::nullptr; + Node* critical_node = root_node; + + while (found) + { + // Search for critical weight node (all nodes whose weight factor + // is set to kNeither (balanced) + if (kNeither != found->weight) + { + critical_node = found; + } + + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = imultiset::data_cast(*found); + + // Is the node provided to the left of the current position? + if (node_comp(node, found_data_node)) + { + // Update direction taken to insert new node in parent node + found->dir = kLeft; + } + // Is the node provided to the right of the current position? + else if (node_comp(found_data_node, node)) + { + // Update direction taken to insert new node in parent node + found->dir = kRight; + } + else + { + // Update direction taken to insert new node in parent (and + // duplicate) node to the right. + found->dir = kRight; + } + + // Is there a child of this parent node? + if (found->children[found->dir]) + { + // Will this node be the parent of the next critical node whose + // weight factor is set to kNeither (balanced)? + if (kNeither != found->children[found->dir]->weight) + { + critical_parent_node = found; + } + + // Keep looking for empty spot to insert new node + found = found->children[found->dir]; + } + else + { + // Attach node as a child of the parent node found + attach_node(found, found->children[found->dir], node); + + // Return newly added node + found = found->children[found->dir]; + + // Exit loop + break; + } + } + + // Was a critical node found that should be checked for balance? + if (critical_node) + { + if (critical_parent_node == std::nullptr && critical_node == root_node) + { + balance_node(root_node); + } + else if (critical_parent_node == std::nullptr && critical_node == position) + { + balance_node(position); + } + else + { + balance_node(critical_parent_node->children[critical_parent_node->dir]); + } + } + } + else + { + // Attatch node to current position (which is assumed to be root) + attach_node(std::nullptr, position, node); + + // Return newly added node at current position + found = position; + } + + // Return the node found (might be std::nullptr) + return found; + } + + //************************************************************************* + /// Remove the node specified from somewhere starting at the position + /// provided + //************************************************************************* + void remove_node(Node* node) + { + // If valid found node was provided then proceed with steps 1 through 5 + if (node) + { + // Downcast found node provided to Data_Node class + Data_Node& data_node = imultiset::data_cast(*node); + + // Keep track of node as found node + Node* found = node; + + // Step 1: Mark path from node provided back to the root node using the + // internal temporary dir member value and using the parent pointer. This + // will allow us to avoid recursion in finding the node in a tree that + //might contain duplicate keys to be found. + while (node) + { + if (node->parent) + { + // Which direction does parent use to get to this node? + node->parent->dir = + node->parent->children[kLeft] == node ? kLeft : kRight; + + // Make this nodes parent the next node + node = node->parent; + } + else + { + // Root node found - break loop + break; + } + } + + // Step 2: Follow the path provided above until we reach the node + // provided and look for the balance node to start rebalancing the tree + // from (up to the replacement node that will be found in step 3) + Node* balance = root_node; + while (node) + { + // Did we reach the node provided originally (found) then go to step 3 + if (node == found) + { + // Update the direction towards a replacement node at the found node + node->dir = node->children[kLeft] ? kLeft : kRight; + + // Exit loop and proceed with step 3 + break; + } + else + { + // If this nodes weight is kNeither or we are taking the shorter path + // to the next node and our sibling (on longer path) is balanced then + // we need to update the balance node to this node but all our + // ancestors will not require rebalancing + if ((node->weight == kNeither) || + (node->weight == (1 - node->dir) && + node->children[1 - node->dir]->weight == kNeither)) + { + // Update balance node to this node + balance = node; + } + + // Keep searching for found in the direction provided in step 1 + node = node->children[node->dir]; + } + } + // The value for node should not be std::nullptr at this point otherwise + // step 1 failed to provide the correct path to found. Step 5 will fail + // (probably subtly) if node should be std::nullptr at this point + + // Step 3: Find the node (node should be equal to found at this point) + // to replace found with (might end up equal to found) while also + // continuing to update balance the same as in step 2 above. + while (node) + { + // Replacement node found if its missing a child in the replace->dir + // value set at the end of step 2 above + if (node->children[node->dir] == std::nullptr) + { + // Exit loop once node to replace found is determined + break; + } + + // If this nodes weight is kNeither or we are taking the shorter path + // to the next node and our sibling (on longer path) is balanced then + // we need to update the balance node to this node but all our + // ancestors will not require rebalancing + if ((node->weight == kNeither) || + (node->weight == (1 - node->dir) && + node->children[1 - node->dir]->weight == kNeither)) + { + // Update balance node to this node + balance = node; + } + + // Keep searching for replacement node in the direction specified above + node = node->children[node->dir]; + + // Downcast node to Data_Node class for comparison operations + Data_Node& replace_data_node = imultiset::data_cast(*node); + + // Compare the key provided to the replace data node key + if (node_comp(data_node, replace_data_node)) + { + // Update the direction to the replace node + node->dir = kLeft; + } + else if (node_comp(replace_data_node, data_node)) + { + // Update the direction to the replace node + node->dir = kRight; + } + else + { + // Update the direction to the replace node + node->dir = node->children[kLeft] ? kLeft : kRight; + } + } // while(node) + + // Step 4: Update weights from balance to parent of node determined + // in step 3 above rotating (2 or 3 node rotations) as needed. + while (balance) + { + // Break when balance node reaches the parent of replacement node + if (balance->children[balance->dir] == std::nullptr) + { + break; + } + + // If balance node is balanced already (kNeither) then just imbalance + // the node in the opposite direction of the node being removed + if (balance->weight == kNeither) + { + balance->weight = 1 - balance->dir; + } + // If balance node is imbalanced in the opposite direction of the + // node being removed then the node now becomes balanced + else if (balance->weight == balance->dir) + { + balance->weight = kNeither; + } + // Otherwise a rotation is required at this node + else + { + int weight = balance->children[1 - balance->dir]->weight; + // Perform a 3 node rotation if weight is same as balance->dir + if (weight == balance->dir) + { + // Is the root node being rebalanced (no parent) + if (balance->parent == std::nullptr) + { + rotate_3node(root_node, 1 - balance->dir, + balance->children[1 - balance->dir]->children[balance->dir]->weight); + } + else + { + rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir, + balance->children[1 - balance->dir]->children[balance->dir]->weight); + } + } + // Already balanced, rebalance and make it heavy in opposite + // direction of the node being removed + else if (weight == kNeither) + { + // Is the root node being rebalanced (no parent) + if (balance->parent == std::nullptr) + { + rotate_2node(root_node, 1 - balance->dir); + root_node->weight = balance->dir; + } + else + { + // Balance parent might change during rotate, keep local copy + // to old parent so its weight can be updated after the 2 node + // rotate is completed + Node* old_parent = balance->parent; + rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir); + old_parent->children[old_parent->dir]->weight = balance->dir; + } + // Update balance node weight in opposite direction of node removed + balance->weight = 1 - balance->dir; + } + // Rebalance and leave it balanced + else + { + // Is the root node being rebalanced (no parent) + if (balance->parent == std::nullptr) + { + rotate_2node(root_node, 1 - balance->dir); + } + else + { + rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir); + } + } + } + + // Next balance node to consider + balance = balance->children[balance->dir]; + } // while(balance) + + // Step 5: Swap found with node (replacement) + if (found->parent) + { + // Handle traditional case + detach_node(found->parent->children[found->parent->dir], + node->parent->children[node->parent->dir]); + } + // Handle root node removal + else + { + // Valid replacement node for root node being removed? + if (node->parent) + { + detach_node(root_node, node->parent->children[node->parent->dir]); + } + else + { + // Found node and replacement node are both root node + detach_node(root_node, root_node); + } + } + + // One less. + --current_size; + + // Destroy the node detached above + destroy_data_node(data_node); + } // if(found) + } + + // Disable copy construction. + imultiset(const imultiset&); + }; + + //************************************************************************* + /// A templated multiset implementation that uses a fixed size buffer. + //************************************************************************* + template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> > + class multiset : public etl::imultiset<T, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + multiset() + : etl::imultiset<T, TCompare>(node_pool, MAX_SIZE) + { + etl::imultiset<T, TCompare>::initialise(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + multiset(const multiset& other) + : etl::imultiset<T, TCompare>(node_pool, MAX_SIZE) + { + etl::imultiset<T, TCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + multiset(TIterator first, TIterator last) + : etl::imultiset<T, TCompare>(node_pool, MAX_SIZE) + { + etl::imultiset<T, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~multiset() + { + etl::imultiset<T, TCompare>::initialise(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + multiset& operator = (const multiset& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + etl::imultiset<T, TCompare>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of data nodes used for the multiset. + etl::pool<typename etl::imultiset<T, TCompare>::Data_Node, MAX_SIZE> node_pool; + }; +} + +//*************************************************************************** +/// Equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> +///\ingroup lookup +//*************************************************************************** +template <typename T, typename TCompare> +bool operator ==(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs) +{ + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +//*************************************************************************** +/// Not equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> +///\ingroup lookup +//*************************************************************************** +template <typename T, typename TCompare> +bool operator !=(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs) +{ + return !(lhs == rhs); +} + +//************************************************************************* +/// Less than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename T, typename TCompare> +bool operator <(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); +} + +//************************************************************************* +/// Greater than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename T, typename TCompare> +bool operator >(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs) +{ + return (rhs < lhs); +} + +//************************************************************************* +/// Less than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than or equal +/// to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename T, typename TCompare> +bool operator <=(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs) +{ + return !(lhs > rhs); +} + +//************************************************************************* +/// Greater than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than or +/// equal to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename T, typename TCompare> +bool operator >=(const etl::imultiset<T, TCompare>& lhs, const etl::imultiset<T, TCompare>& rhs) +{ + return !(lhs < rhs); +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/murmur3.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,236 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_MURMUR3__ +#define __ETL_MURMUR3__ + +#include <stdint.h> + +#include "platform.h" +#include "ihash.h" +#include "binary.h" +#include "error_handler.h" + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup murmur3 Murmur3 hash calculations +///\ingroup maths + +namespace etl +{ + //*************************************************************************** + /// Calculates the murmur3 hash. + /// See https://en.wikipedia.org/wiki/MurmurHash for more details. + ///\ingroup murmur3 + //*************************************************************************** + template <typename THash> + class murmur3 + { + public: + + STATIC_ASSERT((etl::is_same<THash, uint32_t>::value || etl::is_same<THash, uint64_t>::value), "Only 32 & 64 bit types supported"); + + typedef THash value_type; + + //************************************************************************* + /// Default constructor. + /// \param seed The seed value. Default = 0. + //************************************************************************* + murmur3(value_type seed_ = 0) + : seed(seed_) + { + reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + /// \param seed The seed value. Default = 0. + //************************************************************************* + template<typename TIterator> + murmur3(TIterator begin, const TIterator end, value_type seed_ = 0) + : seed(seed_) + { + STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Incompatible type"); + + reset(); + while (begin != end) + { + block |= (*begin++) << (block_fill_count * 8); + + if (++block_fill_count == FULL_BLOCK) + { + add_block(); + block_fill_count = 0; + block = 0; + } + + ++char_count; + } + } + + //************************************************************************* + /// Resets the hash to the initial state. + //************************************************************************* + void reset() + { + hash = seed; + char_count = 0; + block = 0; + block_fill_count = 0; + is_finalised = false; + } + + //************************************************************************* + /// Adds a range. + /// \param begin + /// \param end + //************************************************************************* + template<typename TIterator> + void add(TIterator begin, const TIterator end) + { + STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Incompatible type"); + ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised)); + + while (begin != end) + { + block |= (*begin++) << (block_fill_count * 8); + + if (++block_fill_count == FULL_BLOCK) + { + add_block(); + block_fill_count = 0; + block = 0; + } + + ++char_count; + } + } + + //************************************************************************* + /// Adds a uint8_t value. + /// If the hash has already been finalised then a 'hash_finalised' error will be emitted. + /// \param value The char to add to the hash. + //************************************************************************* + void add(uint8_t value_) + { + // We can't add to a finalised hash! + ETL_ASSERT(!is_finalised, ETL_ERROR(hash_finalised)); + + block |= value_ << (block_fill_count * 8); + + if (++block_fill_count == FULL_BLOCK) + { + add_block(); + block_fill_count = 0; + block = 0; + } + + ++char_count; + } + + //************************************************************************* + /// Gets the hash value. + //************************************************************************* + value_type value() + { + finalise(); + return hash; + } + + //************************************************************************* + /// Conversion operator to value_type. + //************************************************************************* + operator value_type () + { + return value(); + } + + private: + + //************************************************************************* + /// Adds a filled block to the hash. + //************************************************************************* + void add_block() + { + block *= CONSTANT1; + block = rotate_left(block, SHIFT1); + block *= CONSTANT2; + + hash ^= block; + hash = rotate_left(hash, SHIFT2); + hash = (hash * MULTIPLY) + ADD; + } + + //************************************************************************* + /// Finalises the hash. + //************************************************************************* + void finalise() + { + if (!is_finalised) + { + block *= CONSTANT1; + block = rotate_left(block, SHIFT1); + block *= CONSTANT2; + + hash ^= block; + hash ^= char_count; + hash ^= (hash >> 16); + hash *= 0x85EBCA6B; + hash ^= (hash >> 13); + hash *= 0xC2B2AE35; + hash ^= (hash >> 16); + + is_finalised = true; + } + } + + bool is_finalised; + uint8_t block_fill_count; + size_t char_count; + value_type block; + value_type hash; + value_type seed; + + static const uint8_t FULL_BLOCK = 4; + static const value_type CONSTANT1 = 0xCC9E2D51; + static const value_type CONSTANT2 = 0x1B873593; + static const value_type SHIFT1 = 15; + static const value_type SHIFT2 = 13; + static const value_type MULTIPLY = 5; + static const value_type ADD = 0xE6546B64; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nullptr.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,97 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_NULLPTR__ +#define __ETL_NULLPTR__ + +#include "platform.h" + +///\defgroup nullptr nullptr +/// A definition of nullptr for compilers that don't support it as standard. +///\ingroup utilities + +#if (ETL_NO_NULLPTR_SUPPORT && !defined(ARDUINO)) +namespace std +{ + //***************************************************************************** + /// A null pointer type. + ///\ingroup nullptr + //***************************************************************************** + class nullptr_t + { + public: + + // Convertible to any type of null non-member pointer. + template<typename T> + operator T*() const + { + return 0; + } + + // Or any type of null member pointer. + template<typename ANYCLASS, typename T> + operator T ANYCLASS::*() const + { + return 0; + } + + private: + + // Can't take address of nullptr. + void operator&() const; + }; + + //***************************************************************************** + /// A null pointer. + ///\ingroup nullptr + //***************************************************************************** + const nullptr_t nullptr = {}; +} + +//***************************************************************************** +/// A null pointer. +///\ingroup nullptr +//***************************************************************************** +const std::nullptr_t nullptr = {}; + +#else + #include <cstddef> +#endif + +#if defined(ARDUINO) +namespace std +{ + typedef ::nullptr_t nullptr_t; +} +#endif + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numeric.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,61 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_NUMERIC__ +#define __ETL_NUMERIC__ + +#include "platform.h" + +///\defgroup numeric numeric +///\ingroup utilities + +namespace etl +{ + //*************************************************************************** + /// iota + /// Reverse engineered version of std::iota for non C++ 0x11 compilers. + /// Fills a range of elements with sequentially increasing values starting with <b>value</b>. + ///\param first An iterator to the first position to fill. + ///\param last An iterator to the last + 1 position. + ///\ingroup numeric + //*************************************************************************** + template <typename TIterator, typename T> + void iota(TIterator first, TIterator last, T value) + { + while (first != last) + { + *first++ = value++; + } + } +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/observer.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,351 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_OBSERVER__ +#define __ETL_OBSERVER__ + +//***************************************************************************** +///\defgroup observer observer +/// A templated implementation to simplify the creation of the observer pattern +/// and attempts to eliminate certain runtime errors by turning them into compile errors. +/// The pattern consists of two template classes. +/// \li <b>Observer</b><br> +/// This template may take up to eight notification types. +/// Each notification type will generate a pure virtual 'notification' +/// function. The class that inherits from this *must* define all +/// of the 'notification' function overloads otherwise the object will +/// remain 'abstract' and will not compile. +/// This ensures that no overload can be forgotten.<br> +/// +/// \li <b>observable</b><br> +/// The class derived from this will be observed by the above class. +/// It keeps a list of registered observers and will notify all +/// of them with the notifications. +///\ingroup patterns +//***************************************************************************** + +#include <algorithm> + +#include "platform.h" +#include "vector.h" +#include "exception.h" +#include "error_handler.h" + +#undef ETL_FILE +#define ETL_FILE "18" + +namespace etl +{ + //*************************************************************************** + ///\ingroup observer + /// The base class for observer exceptions. + //*************************************************************************** + class observer_exception : public exception + { + public: + + observer_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup observer + /// The exception thrown when the observer list is full. + //*************************************************************************** + class observer_list_full : public observer_exception + { + public: + + observer_list_full(string_type file_name_, numeric_type line_number_) + : observer_exception(ETL_ERROR_TEXT("observer:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //********************************************************************* + /// The object that is being observed. + ///\tparam TObserver The observer type. + ///\tparam MAX_OBSERVERS The maximum number of observers that can be accomodated. + ///\ingroup observer + //********************************************************************* + template <typename TObserver, const size_t MAX_OBSERVERS> + class observable + { + public: + + typedef size_t size_type; + + typedef etl::vector<TObserver*, MAX_OBSERVERS> Observer_List; + + //***************************************************************** + /// Add an observer to the list. + /// If asserts or exceptions are enabled then an etl::observable_observer_list_full + /// is emitted if the observer list is already full. + ///\param observer A reference to the observer. + //***************************************************************** + void add_observer(TObserver& observer) + { + // See if we already have it in our list. + typename Observer_List::const_iterator i_observer = std::find(observer_list.begin(), + observer_list.end(), + &observer); + + // Not there? + if (i_observer == observer_list.end()) + { + // Is there enough room? + ETL_ASSERT(!observer_list.full(), ETL_ERROR(etl::observer_list_full)); + + // Add it. + observer_list.push_back(&observer); + } + } + + //***************************************************************** + /// Remove a particular observer from the list. + ///\param observer A reference to the observer. + //***************************************************************** + void remove_observer(TObserver& observer) + { + // See if we have it in our list. + typename Observer_List::iterator i_observer = std::find(observer_list.begin(), + observer_list.end(), + &observer); + + // Found it? + if (i_observer != observer_list.end()) + { + // Erase it. + observer_list.erase(i_observer); + } + } + + //***************************************************************** + /// Clear all observers from the list. + //***************************************************************** + void clear_observers() + { + observer_list.clear(); + } + + //***************************************************************** + /// Returns the number of observers. + //***************************************************************** + size_type number_of_observers() const + { + return observer_list.size(); + } + + //***************************************************************** + /// Notify all of the observers, sending them the notification. + ///\tparam TNotification the notification type. + ///\param n The notification. + //***************************************************************** + template <typename TNotification> + void notify_observers(TNotification n) + { + for (size_t i = 0; i < observer_list.size(); ++i) + { + observer_list[i]->notification(n); + } + } + + private: + + /// The list of observers. + Observer_List observer_list; + }; + + //********************************************************************* + /// The observer interface for eight notification types. + ///\ingroup observer + //********************************************************************* + template <typename T1, + typename T2 = void, + typename T3 = void, + typename T4 = void, + typename T5 = void, + typename T6 = void, + typename T7 = void, + typename T8 = void> + class observer + { + public: + virtual ~observer() {} + virtual void notification(T1) = 0; + virtual void notification(T2) = 0; + virtual void notification(T3) = 0; + virtual void notification(T4) = 0; + virtual void notification(T5) = 0; + virtual void notification(T6) = 0; + virtual void notification(T7) = 0; + virtual void notification(T8) = 0; + }; + + //********************************************************************* + /// The observer interface for seven notification types. + ///\ingroup observer + //********************************************************************* + template <typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7> + class observer<T1, T2, T3, T4, T5, T6, T7> + { + public: + + virtual ~observer() {} + virtual void notification(T1) = 0; + virtual void notification(T2) = 0; + virtual void notification(T3) = 0; + virtual void notification(T4) = 0; + virtual void notification(T5) = 0; + virtual void notification(T6) = 0; + virtual void notification(T7) = 0; + }; + + //********************************************************************* + /// The observer interface for six notification types. + ///\ingroup observer + //********************************************************************* + template <typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6> + class observer<T1, T2, T3, T4, T5, T6> + { + public: + + virtual ~observer() {} + virtual void notification(T1) = 0; + virtual void notification(T2) = 0; + virtual void notification(T3) = 0; + virtual void notification(T4) = 0; + virtual void notification(T5) = 0; + virtual void notification(T6) = 0; + }; + + //********************************************************************* + /// The observer interface for five notification types. + ///\ingroup observer + //********************************************************************* + template <typename T1, + typename T2, + typename T3, + typename T4, + typename T5> + class observer<T1, T2, T3, T4, T5> + { + public: + + virtual ~observer() {} + virtual void notification(T1) = 0; + virtual void notification(T2) = 0; + virtual void notification(T3) = 0; + virtual void notification(T4) = 0; + virtual void notification(T5) = 0; + }; + + //********************************************************************* + /// The observer interface for four notification types. + ///\ingroup observer + //********************************************************************* + template <typename T1, + typename T2, + typename T3, + typename T4> + class observer<T1, T2, T3, T4> + { + public: + + virtual ~observer() {} + virtual void notification(T1) = 0; + virtual void notification(T2) = 0; + virtual void notification(T3) = 0; + virtual void notification(T4) = 0; + }; + + //********************************************************************* + /// The observer interface for three notification types. + ///\ingroup observer + //********************************************************************* + template <typename T1, + typename T2, + typename T3> + class observer<T1, T2, T3> + { + public: + + virtual ~observer() {} + virtual void notification(T1) = 0; + virtual void notification(T2) = 0; + virtual void notification(T3) = 0; + }; + + //********************************************************************* + /// The observer interface for two notification types. + ///\ingroup observer + //********************************************************************* + template <typename T1, + typename T2> + class observer<T1, T2> + { + public: + + virtual ~observer() {} + virtual void notification(T1) = 0; + virtual void notification(T2) = 0; + }; + + //********************************************************************* + /// The observer interface for one notification type. + ///\ingroup observer + //********************************************************************* + template <typename T1> + class observer<T1> + { + public: + + virtual ~observer() {} + virtual void notification(T1) = 0; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/optional.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,444 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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_OPTIONAL__ +#define __ETL_OPTIONAL__ + +#include "platform.h" +#include "alignment.h" +#include "type_traits.h" +#include "exception.h" +#include "error_handler.h" + +namespace etl +{ + //***************************************************************************** + /// A null option type. + ///\ingroup utilities + //***************************************************************************** + class nullopt_t + { + public: + + // Convertible to any type of null non-member pointer. + template<class T> + operator T*() const + { + return 0; + } + + private: + + // Can't take address of nullopt. + void operator&() const; + }; + + //***************************************************************************** + /// A null option. + ///\ingroup utilities + //***************************************************************************** + const nullopt_t nullopt = {}; + + //*************************************************************************** + /// Exception for optional. + ///\ingroup list + //*************************************************************************** + class optional_exception : public exception + { + public: + + optional_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Invalid exception for optional. + ///\ingroup list + //*************************************************************************** + class optional_invalid : public optional_exception + { + public: + + optional_invalid(string_type file_name_, numeric_type line_number_) + : optional_exception("optional: invalid", file_name_, line_number_) + { + } + }; + + //***************************************************************************** + /// An optional type. + /// If the optional type is not initialised then a type is not constructed. + ///\tparam The type to store. + ///\ingroup utilities + //***************************************************************************** + template <typename T> + class optional + { + public: + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + optional() + : valid(false) + { + } + + //*************************************************************************** + /// Constructor with nullopt. + //*************************************************************************** + optional(etl::nullopt_t) + : valid(false) + { + } + + //*************************************************************************** + /// Copy constructor. + //*************************************************************************** + optional(const optional& other) + : valid(bool(other)) + { + if (valid) + { + ::new (storage.template get_address<T>()) T(other.value()); + } + } + + //*************************************************************************** + /// Constructor from value type. + //*************************************************************************** + optional(const T& value_) + { + ::new (storage.template get_address<T>()) T(value_); + valid = true; + } + + //*************************************************************************** + /// Destructor. + //*************************************************************************** + ~optional() + { + if (valid) + { + storage.template get_reference<T>().~T(); + } + } + + //*************************************************************************** + /// Assignment operator from nullopt. + //*************************************************************************** + optional& operator =(etl::nullopt_t) + { + if (valid) + { + storage.template get_reference<T>().~T(); + valid = false; + } + + return *this; + } + + //*************************************************************************** + /// Assignment operator from optional. + //*************************************************************************** + optional& operator =(const optional& other) + { + if (this != &other) + { + if (valid && !bool(other)) + { + storage.template get_reference<T>().~T(); + valid = false; + } + else if (bool(other)) + { + if (valid) + { + storage.template get_reference<T>() = other.value(); + } + else + { + ::new (storage.template get_address<T>()) T(other.value()); + valid = true; + } + } + } + + return *this; + } + + //*************************************************************************** + /// Assignment operator from value type. + //*************************************************************************** + optional& operator =(const T& value_) + { + if (valid) + { + storage.template get_reference<T>() = value_; + } + else + { + ::new (storage.template get_address<T>()) T(value_); + valid = true; + } + + return *this; + } + + //*************************************************************************** + /// Pointer operator. + //*************************************************************************** + T* operator ->() + { +#if defined(ETL_DEBUG) + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage.template get_address<T>(); + } + + //*************************************************************************** + /// Pointer operator. + //*************************************************************************** + const T* operator ->() const + { +#if defined(ETL_DEBUG) + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage.template get_address<T>(); + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + T& operator *() + { +#if defined(ETL_DEBUG) + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage.template get_reference<T>(); + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + const T& operator *() const + { +#if defined(ETL_DEBUG) + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage.template get_reference<T>(); + } + + //*************************************************************************** + /// Bool conversion operator. + //*************************************************************************** + explicit operator bool() const + { + return valid; + } + + //*************************************************************************** + /// Get a reference to the value. + //*************************************************************************** + T& value() + { +#if defined(ETL_DEBUG) + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage.template get_reference<T>(); + } + + //*************************************************************************** + /// Get a const reference to the value. + //*************************************************************************** + const T& value() const + { +#if defined(ETL_DEBUG) + ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); +#endif + + return storage.template get_reference<T>(); + } + + //*************************************************************************** + /// Gets the value or a default if no valid. + //*************************************************************************** + T value_or(T default_value) const + { + return valid ? value() : default_value; + } + + //*************************************************************************** + /// Swaps this value with another. + //*************************************************************************** + void swap(optional& other) + { + optional temp(*this); + *this = other; + other = temp; + } + + private: + + typename etl::aligned_storage_as<sizeof(T), T>::type storage; + bool valid; + }; +} + +//************************************************************************* +/// Swaps the values. +//************************************************************************* +template <typename T> +void swap(etl::optional<T>& lhs, etl::optional<T>& rhs) +{ + lhs.swap(rhs); +} + +//*************************************************************************** +/// Equality operator. +//*************************************************************************** +template <typename T> +bool operator ==(const etl::optional<T>& lhs, const etl::optional<T>& rhs) +{ + if (bool(lhs) != bool(rhs)) + { + return false; + } + else if (!bool(lhs) && !bool(rhs)) + { + return true; + } + else + { + return lhs.value() == rhs.value(); + } +} + +//*************************************************************************** +/// Less than operator. +//*************************************************************************** +template <typename T> +bool operator <(const etl::optional<T>& lhs, const etl::optional<T>& rhs) +{ + if (!bool(rhs)) + { + return false; + } + else if (!bool(lhs)) + { + return true; + } + else + { + return lhs.value() < rhs.value(); + } +} + +//*************************************************************************** +/// Equality operator. +//*************************************************************************** +template <typename T> +bool operator ==(const etl::optional<T>& lhs, etl::nullopt_t) +{ + return !bool(lhs); +} + +//*************************************************************************** +/// Equality operator. +//*************************************************************************** +template <typename T> +bool operator ==(etl::nullopt_t, const etl::optional<T>& rhs) +{ + return false; +} + +//*************************************************************************** +/// Less than operator. +//*************************************************************************** +template <typename T> +bool operator <(const etl::optional<T>& lhs, etl::nullopt_t) +{ + return !bool(lhs); +} + +//*************************************************************************** +/// Less than operator. +//*************************************************************************** +template <typename T> +bool operator <(etl::nullopt_t, const etl::optional<T>& rhs) +{ + return bool(rhs); +} + +//*************************************************************************** +/// Equality operator. +//************************************************************************** +template <typename T> +bool operator ==(const etl::optional<T>& lhs, const T& rhs) +{ + return bool(lhs) ? lhs.value() == rhs : false; +} + +//*************************************************************************** +/// Equality operator. +//************************************************************************** +template <typename T> +bool operator ==(const T& value, const etl::optional<T>& rhs) +{ + return bool(rhs) ? rhs.value() == value : false; +} + +//*************************************************************************** +/// Less than operator. +//*************************************************************************** +template <typename T> +bool operator <(const etl::optional<T>& lhs, const T& rhs) +{ + return bool(lhs) ? lhs.value() < rhs : true; +} + +//*************************************************************************** +/// Make an optional. +//*************************************************************************** +template <typename T> +etl::optional<typename etl::decay<T>::type> make_optional(T& value) +{ + return etl::optional<typename etl::decay<T>::type>(value); +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/packet.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,129 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_PACKET__ +#define __ETL_PACKET__ + +#include "platform.h" +#include "static_assert.h" +#include "alignment.h" + +#undef ETL_FILE +#define ETL_FILE "38" + +//***************************************************************************** +///\defgroup packet packet +/// A class that can contain one a several related types. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// A template class that can store any types derived from TBase that conform + /// to the size and alignment requirements. + ///\ingroup packet + //*************************************************************************** + template <typename TBase, size_t SIZE, size_t ALIGNMENT> + class packet + { + public: + + //*************************************************************************** + /// Constructor that static asserts any types that do not conform to the max size and alignment. + //*************************************************************************** + template <typename T> + explicit packet(const T& value) + { + STATIC_ASSERT((etl::is_base_of<TBase, T>::value), "Unsupported type"); + STATIC_ASSERT(sizeof(T) <= SIZE, "Unsupported size"); + STATIC_ASSERT(etl::alignment_of<T>::value <= ALIGNMENT, "Unsupported alignment"); + + ::new (static_cast<T*>(data)) T(value); + } + + //*************************************************************************** + /// Destructor + //*************************************************************************** + ~packet() + { + static_cast<TBase*>(data)->~TBase(); + } + + //*************************************************************************** + /// Assignment operator for type. + ///\param value The value to assign. + //*************************************************************************** + template <typename T> + packet& operator =(const T& value) + { + STATIC_ASSERT((etl::is_base_of<TBase, T>::value), "Unsupported type"); + STATIC_ASSERT(sizeof(T) <= SIZE, "Unsupported size"); + STATIC_ASSERT(etl::alignment_of<T>::value <= ALIGNMENT, "Unsupported alignment"); + + static_cast<TBase*>(data)->~TBase(); + ::new (static_cast<T*>(data)) T(value); + + return *this; + } + + //*************************************************************************** + /// Get access to the contained object. + //*************************************************************************** + TBase& get() + { + return *static_cast<TBase*>(data); + } + + //*************************************************************************** + /// Get access to the contained object. + //*************************************************************************** + const TBase& get() const + { + return *static_cast<const TBase*>(data); + } + + private: + + packet(const packet& other); + packet& operator =(const packet& other); + + //*************************************************************************** + /// The internal storage. + /// Aligned on a suitable boundary, which should be good for all types. + //*************************************************************************** + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parameter_type.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,53 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_PARAMETER__ +#define __ETL_PARAMETER__ + +#include "platform.h" +#include "type_traits.h" + +namespace etl +{ + //************************************************************************* + /// Determine how to pass parameters. + //************************************************************************* + template <typename T> + struct parameter_type + { + /// By default fundamental and pointer types are passed by value. + typedef typename etl::conditional<is_fundamental<T>::value || is_pointer<T>::value, + T, + const T&>::type type; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pearson.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,64 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove + +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. +******************************************************************************/ + +#include <stdint.h> + +#include "platform.h" +#include "static_assert.h" + +STATIC_ASSERT(ETL_8BIT_SUPPORT, "This file does not currently support targets with no 8bit type"); + +namespace etl +{ + //*************************************************************************** + /// Pearson lookup table + /// \ingroup pearson + //*************************************************************************** + extern const uint8_t PEARSON_LOOKUP[] = + { + 228, 39, 61, 95, 227, 187, 0, 197, 31, 189, 161, 222, 34, 15, 221, 246, + 19, 234, 6, 50, 113, 3, 91, 63, 77, 245, 144, 2, 183, 196, 25, 226, + 97, 126, 48, 59, 217, 4, 100, 145, 12, 88, 203, 149, 80, 154, 38, 27, + 224, 218, 158, 115, 202, 79, 53, 83, 242, 36, 139, 131, 136, 191, 42, 170, + 23, 99, 156, 51, 143, 60, 233, 206, 62, 108, 17, 67, 81, 71, 93, 195, + 26, 231, 247, 96, 24, 200, 176, 209, 152, 212, 138, 165, 75, 185, 130, 248, + 125, 110, 10, 116, 201, 90, 69, 204, 85, 251, 78, 157, 47, 184, 169, 141, + 134, 230, 89, 21, 146, 46, 55, 128, 148, 207, 216, 11, 114, 199, 103, 102, + 166, 244, 5, 104, 225, 160, 132, 28, 172, 65, 121, 140, 153, 119, 198, 210, + 58, 87, 117, 177, 33, 22, 13, 37, 49, 174, 109, 40, 73, 211, 18, 167, + 164, 252, 168, 74, 30, 173, 35, 98, 66, 193, 94, 175, 86, 54, 179, 122, + 220, 151, 192, 29, 133, 254, 155, 127, 240, 232, 190, 180, 8, 68, 236, 20, + 137, 92, 219, 208, 52, 250, 147, 142, 111, 112, 120, 45, 135, 255, 123, 229, + 57, 182, 243, 124, 186, 253, 7, 237, 9, 16, 70, 171, 235, 107, 223, 118, + 215, 178, 194, 181, 43, 188, 106, 105, 64, 241, 84, 238, 159, 44, 32, 76, + 213, 163, 150, 101, 129, 14, 249, 205, 214, 1, 41, 56, 162, 72, 239, 82 + } ; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pearson.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,167 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_PEARSON__ +#define __ETL_PEARSON__ + +#include <stdint.h> + +#include "platform.h" +#include "static_assert.h" +#include "type_traits.h" +#include "ihash.h" +#include "array.h" +#include "container.h" + +STATIC_ASSERT(ETL_8BIT_SUPPORT, "This file does not currently support targets with no 8bit type"); + +#if defined(ETL_COMPILER_KEIL) +#pragma diag_suppress 1300 +#endif + +///\defgroup pearson Pearson hash calculation +///\ingroup pearson + +namespace etl +{ + //*************************************************************************** + /// Pearson lookup table + /// \ingroup pearson + //*************************************************************************** + extern const uint8_t PEARSON_LOOKUP[]; + + //*************************************************************************** + /// Calculates a Pearson hash + ///\tparam HASH_LENGTH The number of elements in the hash. + /// \ingroup pearson + //*************************************************************************** + template <const size_t HASH_LENGTH> + class pearson + { + public: + + typedef etl::array<uint8_t, HASH_LENGTH> value_type; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + pearson() + : first(true) + { + reset(); + } + + //************************************************************************* + /// Constructor from range. + /// \param begin Start of the range. + /// \param end End of the range. + //************************************************************************* + template<typename TIterator> + pearson(TIterator begin, const TIterator end) + : first(true) + { + STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported"); + + reset(); + add(begin, end); + } + + //************************************************************************* + /// Resets the hash to the initial state. + //************************************************************************* + void reset() + { + hash.fill(0); + } + + //************************************************************************* + /// Adds a range. + /// \param begin + /// \param end + //************************************************************************* + template<typename TIterator> + void add(TIterator begin, const TIterator end) + { + STATIC_ASSERT(sizeof(typename std::iterator_traits<TIterator>::value_type) == 1, "Type not supported"); + + while (begin != end) + { + add(*begin++); + } + } + + //************************************************************************* + /// \param value The char to add to the hash. + //************************************************************************* + void add(uint8_t value_) + { + if (first) + { + for (size_t i = 0; i < HASH_LENGTH; ++i) + { + hash[i] = PEARSON_LOOKUP[(uint32_t(value_) + i) % 256]; + } + + first = false; + } + else + { + for (size_t i = 0; i < HASH_LENGTH; ++i) + { + hash[i] = PEARSON_LOOKUP[hash[i] ^ value_]; + } + } + } + + //************************************************************************* + /// Gets the hash value. + //************************************************************************* + value_type value() const + { + return hash; + } + + //************************************************************************* + /// Conversion operator to value_type. + //************************************************************************* + operator value_type () const + { + return value(); + } + + private: + + bool first; + value_type hash; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,57 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_PLATFORM__ +#define __ETL_PLATFORM__ + +// Some targets do not support 8bit types. +#define ETL_8BIT_SUPPORT (CHAR_BIT == 8) + +#if defined(_DEBUG) || defined(DEBUG) + #define ETL_DEBUG +#endif + +#undef ETL_CPP11_SUPPORTED +#undef ETL_CPP14_SUPPORTED +#undef ETL_NO_NULLPTR_SUPPORT +#undef ETL_NO_LARGE_CHAR_SUPPORT +#undef ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED +#undef ETL_ATOMIC_SUPPORTED + +#include "etl_profile.h" + +#if ETL_CPP11_SUPPORTED + #define ETL_CONSTEXPR constexpr +#else + #define ETL_CONSTEXPR +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pool.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,439 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_POOL__ +#define __ETL_POOL__ + +#include "platform.h" +#include "alignment.h" +#include "array.h" +#include "container.h" +#include "integral_limits.h" +#include "nullptr.h" +#include "alignment.h" +#include "error_handler.h" +#include "static_assert.h" + +#include <iterator> +#include <algorithm> + +#undef ETL_FILE +#define ETL_FILE "11" + +//***************************************************************************** +///\defgroup pool pool +/// A fixed capacity pool. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// The base class for pool exceptions. + ///\ingroup pool + //*************************************************************************** + class pool_exception : public exception + { + public: + + pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// The exception thrown when the pool has no more free items. + ///\ingroup pool + //*************************************************************************** + class pool_no_allocation : public pool_exception + { + public: + + explicit pool_no_allocation(string_type file_name_, numeric_type line_number_) + : pool_exception(ETL_ERROR_TEXT("pool:allocation", ETL_FILE"A"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// The exception thrown when an object is released which does not belong to the pool. + ///\ingroup pool + //*************************************************************************** + class pool_object_not_in_pool : public pool_exception + { + public: + + pool_object_not_in_pool(string_type file_name_, numeric_type line_number_) + : pool_exception(ETL_ERROR_TEXT("pool:not in pool", ETL_FILE"B"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// The exception thrown when an the type requested is larger than the element size. + ///\ingroup pool + //*************************************************************************** + class pool_element_size : public pool_exception + { + public: + + pool_element_size(string_type file_name_, numeric_type line_number_) + : pool_exception(ETL_ERROR_TEXT("pool:element size", ETL_FILE"C"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + ///\ingroup pool + //*************************************************************************** + class ipool + { + public: + + typedef size_t size_type; + + //************************************************************************* + /// Allocate an object from the pool. + /// Uses the default constructor. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template <typename T> + T* allocate() + { + if (sizeof(T) > ITEM_SIZE) + { + ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size)); + } + + return reinterpret_cast<T*>(allocate_item()); + } + + //************************************************************************* + /// Release an object in the pool. + /// If asserts or exceptions are enabled and the object does not belong to this + /// pool then an etl::pool_object_not_in_pool is thrown. + /// \param p_object A pointer to the object to be released. + //************************************************************************* + void release(const void* p_object) + { + release_item((char*)p_object); + } + + //************************************************************************* + /// Release all objects in the pool. + //************************************************************************* + void release_all() + { + items_allocated = 0; + items_initialised = 0; + p_next = p_buffer; + } + + //************************************************************************* + /// Check to see if the object belongs to the pool. + /// \param p_object A pointer to the object to be checked. + /// \return <b>true<\b> if it does, otherwise <b>false</b> + //************************************************************************* + //template <typename T> + bool is_in_pool(const void* p_object) const + { + return is_item_in_pool((const char*)p_object); + } + + //************************************************************************* + /// Returns the maximum number of items in the pool. + //************************************************************************* + size_t max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns the number of free items in the pool. + //************************************************************************* + size_t available() const + { + return MAX_SIZE - items_allocated; + } + + //************************************************************************* + /// Returns the number of allocated items in the pool. + //************************************************************************* + size_t size() const + { + return items_allocated; + } + + //************************************************************************* + /// Checks to see if there are no allocated items in the pool. + /// \return <b>true</b> if there are none allocated. + //************************************************************************* + bool empty() const + { + return items_allocated == 0; + } + + //************************************************************************* + /// Checks to see if there are no free items in the pool. + /// \return <b>true</b> if there are none free. + //************************************************************************* + bool full() const + { + return items_allocated == MAX_SIZE; + } + + protected: + + //************************************************************************* + /// Constructor + //************************************************************************* + ipool(char* p_buffer_, uint32_t item_size_, uint32_t max_size_) + : p_buffer(p_buffer_), + p_next(p_buffer_), + items_allocated(0), + items_initialised(0), + ITEM_SIZE(item_size_), + MAX_SIZE(max_size_) + { + } + + private: + + //************************************************************************* + /// Allocate an item from the pool. + //************************************************************************* + char* allocate_item() + { + char* p_value = std::nullptr; + + // Any free space left? + if (items_allocated < MAX_SIZE) + { + // Initialise another one if necessary. + if (items_initialised < MAX_SIZE) + { + uintptr_t p = reinterpret_cast<uintptr_t>(p_buffer + (items_initialised * ITEM_SIZE)); + *reinterpret_cast<uintptr_t*>(p) = p + ITEM_SIZE; + ++items_initialised; + } + + // Get the address of new allocated item. + p_value = p_next; + + ++items_allocated; + if (items_allocated != MAX_SIZE) + { + // Set up the pointer to the next free item + p_next = *reinterpret_cast<char**>(p_next); + } + else + { + // No more left! + p_next = std::nullptr; + } + } + else + { + ETL_ASSERT(false, ETL_ERROR(etl::pool_no_allocation)); + } + + return p_value; + } + + //************************************************************************* + /// Release an item back to the pool. + //************************************************************************* + void release_item(char* p_value) + { + // Does it belong to us? + ETL_ASSERT(is_item_in_pool(p_value), ETL_ERROR(pool_object_not_in_pool)); + + if (p_next != std::nullptr) + { + // Point it to the current free item. + *(uintptr_t*)p_value = reinterpret_cast<uintptr_t>(p_next); + } + else + { + // This is the only free item. + *((uintptr_t*)p_value) = 0; + } + + p_next = p_value; + + --items_allocated; + } + + //************************************************************************* + /// Check if the item belongs to this pool. + //************************************************************************* + bool is_item_in_pool(const char* p) const + { + // Within the range of the buffer? + intptr_t distance = p - p_buffer; + bool is_within_range = (distance >= 0) && (distance <= intptr_t((ITEM_SIZE * MAX_SIZE) - ITEM_SIZE)); + + // Modulus and division can be slow on some architectures, so only do this in debug. +#if defined(ETL_DEBUG) + // Is the address on a valid object boundary? + bool is_valid_address = ((distance % ITEM_SIZE) == 0); +#else + bool is_valid_address = true; +#endif + + return is_within_range && is_valid_address; + } + + // Disable copy construction and assignment. + ipool(const ipool&); + ipool& operator =(const ipool&); + + char* p_buffer; + char* p_next; + + uint32_t items_allocated; ///< The number of items allocated. + uint32_t items_initialised; ///< The number of items initialised. + + const uint32_t ITEM_SIZE; ///< The size of allocated items. + const uint32_t MAX_SIZE; ///< The maximum number of objects that can be allocated. + }; + + //************************************************************************* + /// A templated pool implementation that uses a fixed size pool. + ///\ingroup pool + //************************************************************************* + template <typename T, const size_t SIZE_> + class pool : public etl::ipool + { + public: + + static const size_t SIZE = SIZE_; + + //************************************************************************* + /// Constructor + //************************************************************************* + pool() + : etl::ipool(reinterpret_cast<char*>(&buffer[0]), ELEMENT_SIZE, SIZE) + { + } + + //************************************************************************* + /// Allocate an object from the pool. + /// Uses the default constructor. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + /// Static asserts if the specified type is too large for the pool. + //************************************************************************* + template <typename U> + U* allocate() + { + STATIC_ASSERT(sizeof(U) <= ELEMENT_SIZE, "Type too large for pool"); + return ipool::allocate<U>(); + } + + private: + + // The pool element. + union Element + { + uintptr_t next; ///< Pointer to the next free element. + char value[sizeof(T)]; ///< Storage for value type. + typename etl::type_with_alignment<etl::alignment_of<T>::value>::type dummy; ///< Dummy item to get correct alignment. + }; + + ///< The memory for the pool of objects. + typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::value>::type buffer[SIZE]; + + static const uint32_t ELEMENT_SIZE = sizeof(Element); + + // Should not be copied. + pool(const pool&); + pool& operator =(const pool&); + }; + + //************************************************************************* + /// A templated abstract pool implementation that uses a fixed size pool. + ///\ingroup pool + //************************************************************************* + template <const size_t TYPE_SIZE_, const size_t ALIGNMENT_, const size_t SIZE_> + class generic_pool : public etl::ipool + { + public: + + static const size_t SIZE = SIZE_; + static const size_t ALIGNMENT = ALIGNMENT_; + static const size_t TYPE_SIZE = TYPE_SIZE_; + + //************************************************************************* + /// Constructor + //************************************************************************* + generic_pool() + : etl::ipool(reinterpret_cast<char*>(&buffer[0]), ELEMENT_SIZE, SIZE) + { + } + + //************************************************************************* + /// Allocate an object from the pool. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + /// Static asserts if the specified type is too large for the pool. + //************************************************************************* + template <typename U> + U* allocate() + { + STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= ELEMENT_SIZE, "Type too large for pool"); + return ipool::allocate<U>(); + } + + private: + + // The pool element. + union Element + { + uintptr_t next; ///< Pointer to the next free element. + char value[TYPE_SIZE_]; ///< Storage for value type. + typename etl::type_with_alignment<ALIGNMENT_>::type dummy; ///< Dummy item to get correct alignment. + }; + + ///< The memory for the pool of objects. + typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::value>::type buffer[SIZE]; + + static const uint32_t ELEMENT_SIZE = sizeof(Element); + + // Should not be copied. + generic_pool(const generic_pool&); + generic_pool& operator =(const generic_pool&); + }; +} + +#undef ETL_FILE + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/power.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,184 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_POW__ +#define __ETL_POW__ + +#include <stddef.h> +#include <stdint.h> + +#include "platform.h" +#include "log.h" + +///\defgroup power power +/// power<N, POWER> : Calculates N to the power POWER. +///\ingroup maths + +namespace etl +{ + //*************************************************************************** + ///\ingroup power + /// Calculates powers. + ///\note Only supports positive N. + //*************************************************************************** + template <const size_t NV, const size_t POWER> + struct power + { + static const uint64_t value = NV * power<NV, POWER - 1>::value; + }; + + //*************************************************************************** + /// Calculates powers. + ///\note Only supports positive N. + /// Specialisation for POWER == 0. + //*************************************************************************** + template <const size_t NV> + struct power<NV, 0> + { + static const uint64_t value = 1; + }; + + //*************************************************************************** + ///\ingroup power + /// Calculates the rounded up power of 2. + //*************************************************************************** + template <const size_t NV> + struct power_of_2_round_up + { + enum value_type + { + value = 1 << (etl::log2<NV - 1>::value + 1) + }; + }; + + //*************************************************************************** + ///\ingroup power + /// Calculates the rounded up power of 2. + /// Specialisation for 0. + //*************************************************************************** + template <> + struct power_of_2_round_up<0> + { + enum value_type + { + value = 2 + }; + }; + + //*************************************************************************** + ///\ingroup power + /// Calculates the rounded down power of 2. + //*************************************************************************** + template <const size_t NV> + struct power_of_2_round_down + { + enum value_type + { + value = 1 << (etl::log2<NV - 1>::value) + }; + }; + + //*************************************************************************** + ///\ingroup power + /// Calculates the rounded down power of 2. + /// Specialisation for 0. + //*************************************************************************** + template <> + struct power_of_2_round_down<0> + { + enum value_type + { + value = 2 + }; + }; + + //*************************************************************************** + ///\ingroup power + /// Calculates the rounded down power of 2. + /// Specialisation for 1. + //*************************************************************************** + template <> + struct power_of_2_round_down<1> + { + enum value_type + { + value = 2 + }; + }; + + //*************************************************************************** + ///\ingroup power + /// Calculates the rounded down power of 2. + /// Specialisation for 2. + //*************************************************************************** + template <> + struct power_of_2_round_down<2> + { + enum value_type + { + value = 2 + }; + }; + + //*************************************************************************** + ///\ingroup power + /// Checks if N is a power of 2. + //*************************************************************************** + template <const size_t NV> + struct is_power_of_2 + { + static const bool value = (NV & (NV - 1)) == 0; + }; + + //*************************************************************************** + ///\ingroup power + /// Checks if N is a power of 2. + /// Specialisation for 0. + //*************************************************************************** + template <> + struct is_power_of_2<0> + { + static const bool value = false; + }; + + //*************************************************************************** + ///\ingroup power + /// Checks if N is a power of 2. + /// Specialisation for 1. + //*************************************************************************** + template <> + struct is_power_of_2<1> + { + static const bool value = false; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/priority_queue.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,429 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2015 jwellbelove, rlindeman + +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_PRIORITY_QUEUE__ +#define __ETL_PRIORITY_QUEUE__ + +#include <stddef.h> +#include <functional> +#include <algorithm> + +#include "platform.h" +#include "container.h" +#include "vector.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "error_handler.h" +#include "exception.h" + +#undef ETL_FILE +#define ETL_FILE "12" + +//***************************************************************************** +///\defgroup queue queue +/// A priority queue with the capacity defined at compile time, +/// written in the STL style. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// The base class for priority_queue exceptions. + ///\ingroup queue + //*************************************************************************** + class priority_queue_exception : public exception + { + public: + + priority_queue_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The exception thrown when the queue is full. + ///\ingroup queue + //*************************************************************************** + class priority_queue_full : public etl::priority_queue_exception + { + public: + + priority_queue_full(string_type file_name_, numeric_type line_number_) + : priority_queue_exception(ETL_ERROR_TEXT("priority_queue:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The priority queue iterator exception on reversed iterators + ///\ingroup queue + //*************************************************************************** + class priority_queue_iterator : public etl::priority_queue_exception + { + public: + + priority_queue_iterator(string_type file_name_, numeric_type line_number_) + : priority_queue_exception(ETL_ERROR_TEXT("priority_queue:iterator", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup queue + ///\brief This is the base for all priority queues that contain a particular type. + ///\details Normally a reference to this type will be taken from a derived queue. + /// The TContainer specified must provide the front, push_back, pop_back, and + /// assign methods to work correctly with priority_queue. + ///\code + /// etl::priority_queue<int, 10> myPriorityQueue; + /// etl::ipriority_queue<int>& iQueue = myPriorityQueue; + ///\endcode + /// \warning This priority queue cannot be used for concurrent access from + /// multiple threads. + /// \tparam T The type of value that the queue holds. + /// \tparam TContainer to hold the T queue values + /// \tparam TCompare to use in comparing T values + //*************************************************************************** + template <typename T, typename TContainer, typename TCompare> + class ipriority_queue + { + public: + + typedef T value_type; ///< The type stored in the queue. + typedef TContainer container_type; ///< The container type used for priority queue. + typedef TCompare compare_type; ///< The comparison type. + typedef T& reference; ///< A reference to the type used in the queue. + typedef const T& const_reference; ///< A const reference to the type used in the queue. + typedef typename TContainer::size_type size_type; ///< The type used for determining the size of the queue. + typedef typename std::iterator_traits<typename TContainer::iterator>::difference_type difference_type; + + private: + + typedef typename etl::parameter_type<T>::type parameter_t; + + public: + + //************************************************************************* + /// Gets a reference to the highest priority value in the priority queue.<br> + /// \return A reference to the highest priority value in the priority queue. + //************************************************************************* + reference top() + { + return container.front(); + } + + //************************************************************************* + /// Gets a const reference to the highest priority value in the priority queue.<br> + /// \return A const reference to the highest priority value in the priority queue. + //************************************************************************* + const_reference top() const + { + return container.front(); + } + + //************************************************************************* + /// Adds a value to the queue. + /// If asserts or exceptions are enabled, throws an etl::priority_queue_full + /// is the priority queue is already full. + ///\param value The value to push to the queue. + //************************************************************************* + void push(parameter_t value) + { + ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full)); + + // Put element at end + container.push_back(value); + // Make elements in container into heap + std::push_heap(container.begin(), container.end(), TCompare()); + } + + //************************************************************************* + /// Emplaces a value to the queue. + /// If asserts or exceptions are enabled, throws an etl::priority_queue_full + /// is the priority queue is already full. + ///\param value The value to push to the queue. + //************************************************************************* + template <typename T1> + void emplace(const T1& value1) + { + ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full)); + + // Put element at end + container.emplace_back(value1); + // Make elements in container into heap + std::push_heap(container.begin(), container.end(), TCompare()); + } + + //************************************************************************* + /// Emplaces a value to the queue. + /// If asserts or exceptions are enabled, throws an etl::priority_queue_full + /// is the priority queue is already full. + ///\param value The value to push to the queue. + //************************************************************************* + template <typename T1, typename T2> + void emplace(const T1& value1, const T2& value2) + { + ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full)); + + // Put element at end + container.emplace_back(value1, value2); + // Make elements in container into heap + std::push_heap(container.begin(), container.end(), TCompare()); + } + + //************************************************************************* + /// Emplaces a value to the queue. + /// If asserts or exceptions are enabled, throws an etl::priority_queue_full + /// is the priority queue is already full. + ///\param value The value to push to the queue. + //************************************************************************* + template <typename T1, typename T2, typename T3> + void emplace(const T1& value1, const T2& value2, const T3& value3) + { + ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full)); + + // Put element at end + container.emplace_back(value1, value2, value3); + // Make elements in container into heap + std::push_heap(container.begin(), container.end(), TCompare()); + } + + //************************************************************************* + /// Emplaces a value to the queue. + /// If asserts or exceptions are enabled, throws an etl::priority_queue_full + /// is the priority queue is already full. + ///\param value The value to push to the queue. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + void emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + ETL_ASSERT(!full(), ETL_ERROR(etl::priority_queue_full)); + + // Put element at end + container.emplace_back(value1, value2, value3, value4); + // Make elements in container into heap + std::push_heap(container.begin(), container.end(), TCompare()); + } + + //************************************************************************* + /// Assigns values to the priority queue. + /// If asserts or exceptions are enabled, emits priority_queue_full if + /// priority queue does not have enough free space. + /// If asserts or exceptions are enabled, emits priority_iterator if the + /// iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d >= 0, ETL_ERROR(etl::priority_queue_iterator)); + ETL_ASSERT(static_cast<size_t>(d) <= max_size(), ETL_ERROR(etl::priority_queue_full)); +#endif + + clear(); + container.assign(first, last); + std::make_heap(container.begin(), container.end(), TCompare()); + } + + //************************************************************************* + /// Removes the oldest value from the back of the priority queue. + /// Does nothing if the priority queue is already empty. + //************************************************************************* + void pop() + { + // Move largest element to end + std::pop_heap(container.begin(), container.end(), TCompare()); + // Actually remove largest element at end + container.pop_back(); + } + + //************************************************************************* + /// Gets the highest priority value in the priority queue + /// and assigns it to destination and removes it from the queue. + //************************************************************************* + void pop_into(reference destination) + { + destination = top(); + pop(); + } + + //************************************************************************* + /// Returns the current number of items in the priority queue. + //************************************************************************* + size_type size() const + { + return container.size(); + } + + //************************************************************************* + /// Returns the maximum number of items that can be queued. + //************************************************************************* + size_type max_size() const + { + return container.max_size(); + } + + //************************************************************************* + /// Checks to see if the priority queue is empty. + /// \return <b>true</b> if the queue is empty, otherwise <b>false</b> + //************************************************************************* + bool empty() const + { + return container.empty(); + } + + //************************************************************************* + /// Checks to see if the priority queue is full. + /// \return <b>true</b> if the priority queue is full, otherwise <b>false</b> + //************************************************************************* + bool full() const + { + return container.size() == container.max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return container.max_size() - container.size(); + } + + //************************************************************************* + /// Clears the queue to the empty state. + //************************************************************************* + void clear() + { + container.clear(); + } + + protected: + + //************************************************************************* + /// Make this a clone of the supplied priority queue + //************************************************************************* + void clone(const ipriority_queue& other) + { + assign(other.container.cbegin(), other.container.cend()); + } + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + ipriority_queue() + { + } + + private: + + // Disable copy construction. + ipriority_queue(const ipriority_queue&); + + /// The container specified at instantiation of the priority_queue + TContainer container; + }; + + //*************************************************************************** + ///\ingroup priority_queue + /// A fixed capacity priority queue. + /// This queue does not support concurrent access by different threads. + /// \tparam T The type this queue should support. + /// \tparam SIZE The maximum capacity of the queue. + //*************************************************************************** + template <typename T, const size_t SIZE, typename TContainer = etl::vector<T, SIZE>, typename TCompare = std::less<typename TContainer::value_type> > + class priority_queue : public etl::ipriority_queue<T, TContainer, TCompare> + { + public: + + static const size_t MAX_SIZE = SIZE; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + priority_queue() + : etl::ipriority_queue<T, TContainer, TCompare>() + { + } + + //************************************************************************* + /// Copy constructor + //************************************************************************* + priority_queue(const priority_queue& rhs) + : etl::ipriority_queue<T, TContainer, TCompare>() + { + etl::ipriority_queue<T, TContainer, TCompare>::clone(rhs); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + priority_queue(TIterator first, TIterator last) + : etl::ipriority_queue<T, TContainer, TCompare>() + { + etl::ipriority_queue<T, TContainer, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~priority_queue() + { + etl::ipriority_queue<T, TContainer, TCompare>::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + priority_queue& operator = (const priority_queue& rhs) + { + if (&rhs != this) + { + etl::ipriority_queue<T, TContainer, TCompare>::clone(rhs); + } + + return *this; + } + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/private/ivectorpointer.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,562 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_IVECTOR_POINTER__ +#define __ETL_IVECTOR_POINTER__ + +#ifndef __ETL_IN_VECTOR_H__ +#error This header is a private element of etl::ivector +#endif + +#include "pvoidvector.h" + +namespace etl +{ + //*************************************************************************** + /// The base class for specifically sized vectors. + /// Can be used as a reference type for all vectors containing a specific pointer type. + ///\ingroup vector + //*************************************************************************** + template <typename T> + class ivector<T*> : public pvoidvector + { + public: + + typedef T* value_type; + typedef T*& reference; + typedef const T* const & const_reference; + typedef T** pointer; + typedef const T* const * const_pointer; + typedef T** iterator; + typedef const T* const * const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef size_t size_type; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + protected: + + typedef value_type parameter_t; + + private: + + typedef pvoidvector base_t; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the vector. + ///\return An iterator to the beginning of the vector. + //********************************************************************* + iterator begin() + { + return iterator(base_t::begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the vector. + ///\return A const iterator to the beginning of the vector. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(base_t::begin()); + } + + //********************************************************************* + /// Returns an iterator to the end of the vector. + ///\return An iterator to the end of the vector. + //********************************************************************* + iterator end() + { + return iterator(base_t::end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the vector. + ///\return A const iterator to the end of the vector. + //********************************************************************* + const_iterator end() const + { + return const_iterator(base_t::end()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the vector. + ///\return A const iterator to the beginning of the vector. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(base_t::cbegin()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the vector. + ///\return A const iterator to the end of the vector. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(base_t::cend()); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the vector. + ///\return Iterator to the reverse beginning of the vector. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(iterator(base_t::end())); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the vector. + ///\return Const iterator to the reverse beginning of the vector. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(const_iterator(base_t::end())); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the vector. + ///\return Reverse iterator to the end + 1 of the vector. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(iterator(base_t::begin())); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the vector. + ///\return Const reverse iterator to the end + 1 of the vector. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(const_iterator(base_t::begin())); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the vector. + ///\return Const reverse iterator to the reverse beginning of the vector. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(const_iterator(base_t::cend())); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the vector. + ///\return Const reverse iterator to the end + 1 of the vector. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(const_iterator(base_t::cbegin())); + } + + //********************************************************************* + /// Resizes the vector. + /// If asserts or exceptions are enabled and the new size is larger than the + /// maximum then a vector_full is thrown. + ///\param new_size The new size. + //********************************************************************* + void resize(size_t new_size) + { + base_t::resize(new_size); + } + + //********************************************************************* + /// Resizes the vector. + /// If asserts or exceptions are enabled and the new size is larger than the + /// maximum then a vector_full is thrown. + ///\param new_size The new size. + ///\param value The value to fill new elements with. Default = default constructed value. + //********************************************************************* + void resize(size_t new_size, value_type value) + { + base_t::resize(new_size, value); + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference operator [](size_t i) + { + return reference(base_t::operator[](i)); + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference operator [](size_t i) const + { + return const_reference(base_t::operator[](i)); + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference at(size_t i) + { + return reference(base_t::at(i)); + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference at(size_t i) const + { + return const_reference(base_t::at(i)); + } + + //********************************************************************* + /// Returns a reference to the first element. + ///\return A reference to the first element. + //********************************************************************* + reference front() + { + return reference(base_t::front()); + } + + //********************************************************************* + /// Returns a const reference to the first element. + ///\return A const reference to the first element. + //********************************************************************* + const_reference front() const + { + return const_reference(base_t::front()); + } + + //********************************************************************* + /// Returns a reference to the last element. + ///\return A reference to the last element. + //********************************************************************* + reference back() + { + return reference(base_t::back()); + } + + //********************************************************************* + /// Returns a const reference to the last element. + ///\return A const reference to the last element. + //********************************************************************* + const_reference back() const + { + return const_reference(base_t::back()); + } + + //********************************************************************* + /// Returns a pointer to the beginning of the vector data. + ///\return A pointer to the beginning of the vector data. + //********************************************************************* + pointer data() + { + return pointer(base_t::data()); + } + + //********************************************************************* + /// Returns a const pointer to the beginning of the vector data. + ///\return A const pointer to the beginning of the vector data. + //********************************************************************* + const_pointer data() const + { + return const_pointer(base_t::data()); + } + + //********************************************************************* + /// Assigns values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + /// If asserts or exceptions are enabled, emits vector_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { + base_t::initialise(); + + while (first != last) + { + *p_end++ = (void*)*first++; + } + } + + //********************************************************************* + /// Assigns values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + ///\param n The number of elements to add. + ///\param value The value to insert for each element. + //********************************************************************* + void assign(size_t n, parameter_t value) + { + base_t::assign(n, value); + } + + //************************************************************************* + /// Clears the vector. + //************************************************************************* + void clear() + { + base_t::clear(); + } + + //************************************************************************* + /// Increases the size of the vector by one, but does not initialise the new element. + /// If asserts or exceptions are enabled, throws a vector_full if the vector is already full. + //************************************************************************* + void push_back() + { + base_t::push_back(); + } + + //********************************************************************* + /// Inserts a value at the end of the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param value The value to add. + //********************************************************************* + void push_back(parameter_t value) + { + base_t::push_back(value); + } + + //************************************************************************* + /// Removes an element from the end of the vector. + /// Does nothing if the vector is empty. + //************************************************************************* + void pop_back() + { + base_t::pop_back(); + } + + //********************************************************************* + /// Inserts a value to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param position The position to insert before. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, parameter_t value) + { + return iterator(base_t::insert(base_t::iterator(position), value)); + } + + //********************************************************************* + /// Inserts 'n' values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + ///\param position The position to insert before. + ///\param n The number of elements to add. + ///\param value The value to insert. + //********************************************************************* + void insert(iterator position, size_t n, parameter_t value) + { + base_t::insert(base_t::iterator(position), n, value); + } + + //********************************************************************* + /// Inserts a range of values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + ///\param position The position to insert before. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(iterator position, TIterator first, TIterator last) + { + base_t::insert(base_t::iterator(position), first, last); + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(iterator i_element) + { + return iterator(base_t::erase(base_t::iterator(i_element))); + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(iterator first, iterator last) + { + return iterator(base_t::erase(base_t::iterator(first), base_t::iterator(last))); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + ivector& operator = (const ivector& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + ivector(T** p_buffer_, size_t MAX_SIZE_) + : pvoidvector(reinterpret_cast<void**>(p_buffer_), MAX_SIZE_) + { + } + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator ==(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs) + { + return pvoidvector_equal(lhs, rhs); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator !=(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs) + { + return pvoidvector_not_equal(lhs, rhs); + } + + //*************************************************************************** + /// Less than operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically less than the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator <(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs) + { + return pvoidvector_less_than(lhs, rhs); + } + + //*************************************************************************** + /// Greater than operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically greater than the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator >(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs) + { + return pvoidvector_greater_than(lhs, rhs); + } + + //*************************************************************************** + /// Less than or equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexigraphically less than or equal to the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator <=(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs) + { + return pvoidvector_less_than_equal(lhs, rhs); + } + + //*************************************************************************** + /// Greater than or equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexigraphically greater than or equal to the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator >=(const etl::ivector<T*>& lhs, const etl::ivector<T*>& rhs) + { + return pvoidvector_greater_than_equal(lhs, rhs); + } + + //*************************************************************************** + // Helper functions + //*************************************************************************** + inline bool pvoidvector_equal(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return operator ==(lhs, rhs); + } + + inline bool pvoidvector_not_equal(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return operator !=(lhs, rhs); + } + + inline bool pvoidvector_less_than(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return operator <(lhs, rhs); + } + + inline bool pvoidvector_greater_than(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return operator >(lhs, rhs); + } + + inline bool pvoidvector_less_than_equal(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return operator <=(lhs, rhs); + } + + inline bool pvoidvector_greater_than_equal(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return operator >=(lhs, rhs); + } +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/private/pvoidvector.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,109 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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. +******************************************************************************/ + +#include "../platform.h" +#include "pvoidvector.h" + +namespace etl +{ + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + bool operator ==(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + bool operator !=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Less than operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically less than the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + inline bool operator <(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //*************************************************************************** + /// Greater than operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically greater than the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + bool operator >(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return (rhs < lhs); + } + + //*************************************************************************** + /// Less than or equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically less than or equal to the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + bool operator <=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return !(lhs > rhs); + } + + //*************************************************************************** + /// Greater than or equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically greater than or equal to the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + bool operator >=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs) + { + return !(lhs < rhs); + } +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/private/pvoidvector.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,604 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_PVOIDVECTOR__ +#define __ETL_PVOIDVECTOR__ + +#define __ETL_IN_PVOIDVECTOR__ + +#include <iterator> +#include <algorithm> +#include <functional> +#include <stddef.h> + +#include "../platform.h" +#include "../algorithm.h" +#include "vector_base.h" +#include "../type_traits.h" +#include "../error_handler.h" + +#ifdef ETL_COMPILER_GCC +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +namespace etl +{ + //*************************************************************************** + /// The base class for void* vectors. + ///\ingroup vector + //*************************************************************************** + class pvoidvector : public vector_base + { + public: + + typedef void* value_type; + typedef void*& reference; + typedef const void*& const_reference; + typedef void** pointer; + typedef const void** const_pointer; + typedef void** iterator; + typedef const void** const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef size_t size_type; + typedef std::iterator_traits<iterator>::difference_type difference_type; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the vector. + ///\return An iterator to the beginning of the vector. + //********************************************************************* + iterator begin() + { + return p_buffer; + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the vector. + ///\return A const iterator to the beginning of the vector. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(p_buffer); + } + + //********************************************************************* + /// Returns an iterator to the end of the vector. + ///\return An iterator to the end of the vector. + //********************************************************************* + iterator end() + { + return p_end; + } + + //********************************************************************* + /// Returns a const_iterator to the end of the vector. + ///\return A const iterator to the end of the vector. + //********************************************************************* + const_iterator end() const + { + return const_iterator(p_end); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the vector. + ///\return A const iterator to the beginning of the vector. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(p_buffer); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the vector. + ///\return A const iterator to the end of the vector. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(p_end); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the vector. + ///\return Iterator to the reverse beginning of the vector. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the vector. + ///\return Const iterator to the reverse beginning of the vector. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the vector. + ///\return Reverse iterator to the end + 1 of the vector. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the vector. + ///\return Const reverse iterator to the end + 1 of the vector. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the vector. + ///\return Const reverse iterator to the reverse beginning of the vector. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the vector. + ///\return Const reverse iterator to the end + 1 of the vector. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + //********************************************************************* + /// Resizes the vector. + /// If asserts or exceptions are enabled and the new size is larger than the + /// maximum then a vector_full is thrown. + ///\param new_size The new size. + //********************************************************************* + void resize(size_t new_size) + { + ETL_ASSERT(new_size <= CAPACITY, ETL_ERROR(vector_full)); + + p_end = p_buffer + new_size; + } + + //********************************************************************* + /// Resizes the vector. + /// If asserts or exceptions are enabled and the new size is larger than the + /// maximum then a vector_full is thrown. + ///\param new_size The new size. + ///\param value The value to fill new elements with. Default = default constructed value. + //********************************************************************* + void resize(size_t new_size, value_type value) + { + ETL_ASSERT(new_size <= CAPACITY, ETL_ERROR(vector_full)); + + pointer p_new_end = p_buffer + new_size; + + // Size up if necessary. + if (p_end < p_new_end) + { + std::fill(p_end, p_new_end, value); + } + + p_end = p_new_end; + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference operator [](size_t i) + { + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference operator [](size_t i) const + { + return const_reference(p_buffer[i]); + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference at(size_t i) + { + ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds)); + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference at(size_t i) const + { + ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds)); + return const_reference(p_buffer[i]); + } + + //********************************************************************* + /// Returns a reference to the first element. + ///\return A reference to the first element. + //********************************************************************* + reference front() + { + return p_buffer[0]; + } + + //********************************************************************* + /// Returns a const reference to the first element. + ///\return A const reference to the first element. + //********************************************************************* + const_reference front() const + { + return const_reference(p_buffer[0]); + } + + //********************************************************************* + /// Returns a reference to the last element. + ///\return A reference to the last element. + //********************************************************************* + reference back() + { + return *(p_end -1); + } + + //********************************************************************* + /// Returns a const reference to the last element. + ///\return A const reference to the last element. + //********************************************************************* + const_reference back() const + { + return const_reference(*(p_end - 1)); + } + + //********************************************************************* + /// Returns a pointer to the beginning of the vector data. + ///\return A pointer to the beginning of the vector data. + //********************************************************************* + pointer data() + { + return p_buffer; + } + + //********************************************************************* + /// Returns a const pointer to the beginning of the vector data. + ///\return A const pointer to the beginning of the vector data. + //********************************************************************* + const_pointer data() const + { + return const_pointer(p_buffer); + } + + //********************************************************************* + /// Assigns values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + /// If asserts or exceptions are enabled, emits vector_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(static_cast<size_t>(d) <= CAPACITY, ETL_ERROR(vector_full)); +#endif + + initialise(); + + while (first != last) + { + *p_end++ = const_cast<void*>(*first++); + } + } + + //********************************************************************* + /// Assigns values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + ///\param n The number of elements to add. + ///\param value The value to insert for each element. + //********************************************************************* + void assign(size_t n, value_type value) + { + initialise(); + + ETL_ASSERT(n <= CAPACITY, ETL_ERROR(vector_full)); + + for (size_t current_size = 0; current_size < n; ++current_size) + { + *p_end++ = value; + } + } + + //************************************************************************* + /// Clears the vector. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + /// Increases the size of the vector by one, but does not initialise the new element. + /// If asserts or exceptions are enabled, throws a vector_full if the vector is already full. + //************************************************************************* + void push_back() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); +#endif + + ++p_end; + } + + //********************************************************************* + /// Inserts a value at the end of the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param value The value to add. + //********************************************************************* + void push_back(value_type value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); +#endif + *p_end++ = value; + } + + //************************************************************************* + /// Removes an element from the end of the vector. + /// Does nothing if the vector is empty. + //************************************************************************* + void pop_back() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() > 0, ETL_ERROR(vector_empty)); +#endif + --p_end; + } + + //********************************************************************* + /// Inserts a value to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param position The position to insert before. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, value_type value) + { + ETL_ASSERT(size() + 1 <= CAPACITY, ETL_ERROR(vector_full)); + + if (position != end()) + { + ++p_end; + std::copy_backward(position, end() - 1, end()); + *position = value; + } + else + { + *p_end++ = value; + } + + return position; + } + + //********************************************************************* + /// Inserts 'n' values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + ///\param position The position to insert before. + ///\param n The number of elements to add. + ///\param value The value to insert. + //********************************************************************* + void insert(iterator position, size_t n, value_type value) + { + ETL_ASSERT((size() + 1) <= CAPACITY, ETL_ERROR(vector_full)); + + std::copy_backward(position, p_end, p_end + n); + std::fill_n(position, n, value); + + p_end += n; + } + + //********************************************************************* + /// Inserts a range of values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + /// For fundamental and pointer types. + ///\param position The position to insert before. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <typename TIterator> + void insert(iterator position, TIterator first, TIterator last) + { + size_t count = std::distance(first, last); + + ETL_ASSERT((size() + count) <= CAPACITY, ETL_ERROR(vector_full)); + + std::copy_backward(position, p_end, p_end + count); + std::copy(first, last, position); + p_end += count; + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(iterator i_element) + { + std::copy(i_element + 1, end(), i_element); + --p_end; + + return i_element; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(iterator first, iterator last) + { + std::copy(last, end(), first); + size_t n_delete = std::distance(first, last); + + // Just adjust the count. + p_end -= n_delete; + + return first; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + pvoidvector& operator = (const pvoidvector& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Gets the current size of the vector. + ///\return The current size of the vector. + //************************************************************************* + size_type size() const + { + return size_t(p_end - p_buffer); + } + + //************************************************************************* + /// Checks the 'empty' state of the vector. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return (p_end == p_buffer); + } + + //************************************************************************* + /// Checks the 'full' state of the vector. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return size() == CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + pvoidvector(void** p_buffer_, size_t MAX_SIZE) + : vector_base(MAX_SIZE), + p_buffer(p_buffer_), + p_end(p_buffer_) + { + } + + //********************************************************************* + /// Initialise the vector. + //********************************************************************* + void initialise() + { + p_end = p_buffer; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair(void** p_buffer_) + { + uintptr_t length = p_end - p_buffer; + + p_buffer = p_buffer_; + p_end = p_buffer_ + length; + } + + void** p_buffer; + void** p_end; + + private: + + // Disable copy construction. + pvoidvector(const pvoidvector&); + }; + + bool operator ==(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs); + bool operator !=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs); + bool operator <(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs); + bool operator >(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs); + bool operator <=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs); + bool operator >=(const etl::pvoidvector& lhs, const etl::pvoidvector& rhs); +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef __ETL_IN_PVOIDVECTOR__ + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/private/vector_base.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,165 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#if !defined(__ETL_IN_VECTOR_H__) && !defined(__ETL_IN_PVOIDVECTOR__) +#error This header is a private element of etl::vector & etl::pvoidvector +#endif + +#ifndef __ETL_VECTOR_BASE__ +#define __ETL_VECTOR_BASE__ + +#include <stddef.h> + +#include "../platform.h" +#include "../exception.h" +#include "../error_handler.h" +#include "../debug_count.h" + +#define ETL_FILE "17" + +namespace etl +{ + //*************************************************************************** + ///\ingroup vector + /// Exception base for vectors + //*************************************************************************** + class vector_exception : public exception + { + public: + + vector_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup vector + /// Vector full exception. + //*************************************************************************** + class vector_full : public vector_exception + { + public: + + vector_full(string_type file_name_, numeric_type line_number_) + : vector_exception(ETL_ERROR_TEXT("vector:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup vector + /// Vector empty exception. + //*************************************************************************** + class vector_empty : public vector_exception + { + public: + + vector_empty(string_type file_name_, numeric_type line_number_) + : vector_exception(ETL_ERROR_TEXT("vector:empty", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup vector + /// Vector out of bounds exception. + //*************************************************************************** + class vector_out_of_bounds : public vector_exception + { + public: + + vector_out_of_bounds(string_type file_name_, numeric_type line_number_) + : vector_exception(ETL_ERROR_TEXT("vector:bounds", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup vector + /// Vector incompatible type exception. + //*************************************************************************** + class vector_incompatible_type : public vector_exception + { + public: + + vector_incompatible_type(string_type file_name_, numeric_type line_number_) + : vector_exception(ETL_ERROR_TEXT("vector:type", ETL_FILE"D"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup vector + /// The base class for all templated vector types. + //*************************************************************************** + class vector_base + { + public: + + typedef size_t size_type; + + //************************************************************************* + /// Returns the capacity of the vector. + ///\return The capacity of the vector. + //************************************************************************* + size_type capacity() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the maximum possible size of the vector. + ///\return The maximum size of the vector. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + vector_base(size_type max_size_) + : CAPACITY(max_size_) + { + } + + const size_type CAPACITY; ///<The maximum number of elements in the vector. + etl::debug_count construct_count; ///< Internal debugging. + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/arduino_arm.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ARDUINO__ +#define __ETL_ARDUINO__ + +//***************************************************************************** +// Arduino +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_ARM +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GCC +#define ETL_CPP11_SUPPORTED 0 +#define ETL_CPP14_SUPPORTED 0 +#define ETL_NO_NULLPTR_SUPPORT 1 +#define ETL_NO_LARGE_CHAR_SUPPORT 1 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_ATOMIC_SUPPORTED 0 + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/armv5.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ARMV5__ +#define __ETL_ARMV5__ + +//***************************************************************************** +// ARM Compiler Version 5 +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_ARM +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_ARM +#define ETL_CPP11_SUPPORTED 0 +#define ETL_CPP14_SUPPORTED 0 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 1 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_ATOMIC_SUPPORTED 0 + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/armv6.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_ARMV6__ +#define __ETL_ARMV6__ + +//***************************************************************************** +// ARM Compiler Version 6 +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_ARM +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_LLVM +#undef ETL_CPP11_SUPPORTED +#undef ETL_CPP14_SUPPORTED +#define ETL_NO_NULLPTR_SUPPORT 1 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_ATOMIC_SUPPORTED 1 + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/cpp03.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_CPP03__ +#define __ETL_CPP03__ + +//***************************************************************************** +// Generic C++03 +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 0 +#define ETL_CPP14_SUPPORTED 0 +#define ETL_NO_NULLPTR_SUPPORT 1 +#define ETL_NO_LARGE_CHAR_SUPPORT 1 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_ATOMIC_SUPPORTED 0 + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/cpp11.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_CPP11__ +#define __ETL_CPP11__ + +//***************************************************************************** +// Generic C++11 +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 0 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1 +#define ETL_ATOMIC_SUPPORTED 1 + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/cpp14.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_CPP14__ +#define __ETL_CPP14__ + +//***************************************************************************** +// Generic C++14 +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GENERIC +#define ETL_CPP11_SUPPORTED 1 +#define ETL_CPP14_SUPPORTED 1 +#define ETL_NO_NULLPTR_SUPPORT 0 +#define ETL_NO_LARGE_CHAR_SUPPORT 0 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 1 +#define ETL_ATOMIC_SUPPORTED 1 + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/gcc_generic.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,53 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_GCC__ +#define __ETL_GCC__ + +//***************************************************************************** +// GCC +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_GCC + + #define ETL_CPP11_SUPPORTED 0 + #define ETL_CPP14_SUPPORTED 0 + +#define ETL_NO_NULLPTR_SUPPORT !ETL_CPP11_SUPPORTED +#define ETL_NO_LARGE_CHAR_SUPPORT !ETL_CPP11_SUPPORTED +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED +#define ETL_ATOMIC_SUPPORTED ETL_CPP11_SUPPORTED + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/gcc_linux_x86.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,56 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_GCC__ +#define __ETL_GCC__ + +//***************************************************************************** +// GCC +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_X86 +#define ETL_TARGET_OS_LINUX +#define ETL_COMPILER_GCC +#ifdef __cplusplus + #define ETL_CPP11_SUPPORTED (__cplusplus >= 201103L) + #define ETL_CPP14_SUPPORTED (__cplusplus >= 201402L) +#else + #define ETL_CPP11_SUPPORTED 0 + #define ETL_CPP14_SUPPORTED 0 +#endif +#define ETL_NO_NULLPTR_SUPPORT !ETL_CPP11_SUPPORTED +#define ETL_NO_LARGE_CHAR_SUPPORT !ETL_CPP11_SUPPORTED +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED +#define ETL_ATOMIC_SUPPORTED ETL_CPP11_SUPPORTED + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/gcc_windows_x86.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,56 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_GCC__ +#define __ETL_GCC__ + +//***************************************************************************** +// GCC +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_X86 +#define ETL_TARGET_OS_WINDOWS +#define ETL_COMPILER_GCC +#ifdef __cplusplus + #define ETL_CPP11_SUPPORTED (__cplusplus >= 201103L) + #define ETL_CPP14_SUPPORTED (__cplusplus >= 201402L) +#else + #define ETL_CPP11_SUPPORTED 0 + #define ETL_CPP14_SUPPORTED 0 +#endif +#define ETL_NO_NULLPTR_SUPPORT !ETL_CPP11_SUPPORTED +#define ETL_NO_LARGE_CHAR_SUPPORT !ETL_CPP11_SUPPORTED +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED +#define ETL_ATOMIC_SUPPORTED ETL_CPP11_SUPPORTED + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/msvc_x86.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_MSVC__ +#define __ETL_MSVC__ + +//***************************************************************************** +// Microsoft Visual Studio +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_X86 +#define ETL_TARGET_OS_WINDOWS +#define ETL_COMPILER_MICROSOFT +#define ETL_CPP11_SUPPORTED (_MSC_VER >= 1600) +#define ETL_CPP14_SUPPORTED (_MSC_VER >= 1900) +#define ETL_NO_NULLPTR_SUPPORT !ETL_CPP11_SUPPORTED +#define ETL_NO_LARGE_CHAR_SUPPORT !ETL_CPP11_SUPPORTED +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_CPP14_SUPPORTED +#define ETL_ATOMIC_SUPPORTED ETL_CPP11_SUPPORTED + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/ticc.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,51 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_TICC__ +#define __ETL_TICC__ + +//***************************************************************************** +// Texas Instruments Code Composer +//***************************************************************************** + +#include <limits.h> + +#define ETL_TARGET_DEVICE_GENERIC +#define ETL_TARGET_OS_NONE +#define ETL_COMPILER_TI +#define ETL_CPP11_SUPPORTED 0 +#define ETL_CPP14_SUPPORTED 0 +#define ETL_NO_NULLPTR_SUPPORT 1 +#define ETL_NO_LARGE_CHAR_SUPPORT 1 +#define ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED 0 +#define ETL_ATOMIC_SUPPORTED 0 + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/queue.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,523 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove, Mark Kitson + +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_QUEUE__ +#define __ETL_QUEUE__ + +#include <stddef.h> +#include <stdint.h> + +#include "platform.h" +#include "container.h" +#include "alignment.h" +#include "array.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "type_traits.h" +#include "parameter_type.h" + +#undef ETL_FILE +#define ETL_FILE "13" + +//***************************************************************************** +///\defgroup queue queue +/// A First-in / first-out queue with the capacity defined at compile time, +/// written in the STL style. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// The base class for queue exceptions. + ///\ingroup queue + //*************************************************************************** + class queue_exception : public exception + { + public: + + queue_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The exception thrown when the queue is full. + ///\ingroup queue + //*************************************************************************** + class queue_full : public queue_exception + { + public: + + queue_full(string_type file_name_, numeric_type line_number_) + : queue_exception(ETL_ERROR_TEXT("queue:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The exception thrown when the queue is empty. + ///\ingroup queue + //*************************************************************************** + class queue_empty : public queue_exception + { + public: + + queue_empty(string_type file_name_, numeric_type line_number_) + : queue_exception(ETL_ERROR_TEXT("queue:empty", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for all queues. + ///\ingroup queue + //*************************************************************************** + class queue_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of queue. + + //************************************************************************* + /// Returns the current number of items in the queue. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Returns the maximum number of items that can be queued. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + //************************************************************************* + /// Checks to see if the queue is empty. + /// \return <b>true</b> if the queue is empty, otherwise <b>false</b> + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Checks to see if the queue is full. + /// \return <b>true</b> if the queue is full, otherwise <b>false</b> + //************************************************************************* + bool full() const + { + return current_size == CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + queue_base(size_type max_size_) + : in(0), + out(0), + current_size(0), + CAPACITY(max_size_) + { + } + + //************************************************************************* + /// Increments (and wraps) the 'in' index value to record a queue addition. + //************************************************************************* + void add_in() + { + if (++in == CAPACITY) + { + in = 0; + } + + ++current_size; + ++construct_count; + } + + //************************************************************************* + /// Decrements (and wraps) the 'out' index value to record a queue deletion. + //************************************************************************* + void del_out() + { + if (++out == CAPACITY) + { + out = 0; + } + --current_size; + --construct_count; + } + + size_type in; ///< Where to input new data. + size_type out; ///< Where to get the oldest data. + size_type current_size; ///< The number of items in the queue. + const size_type CAPACITY; ///< The maximum number of items in the queue. + etl::debug_count construct_count; ///< For internal debugging purposes. + }; + + //*************************************************************************** + ///\ingroup queue + ///\brief This is the base for all queues that contain a particular type. + ///\details Normally a reference to this type will be taken from a derived queue. + ///\code + /// etl::queue<int, 10> myQueue; + /// etl::iqueue<int>& iQueue = myQueue; + ///\endcode + /// \warning This queue cannot be used for concurrent access from multiple threads. + /// \tparam T The type of value that the queue holds. + //*************************************************************************** + template <typename T> + class iqueue : public etl::queue_base + { + public: + + typedef T value_type; ///< The type stored in the queue. + typedef T& reference; ///< A reference to the type used in the queue. + typedef const T& const_reference; ///< A const reference to the type used in the queue. + typedef T* pointer; ///< A pointer to the type used in the queue. + typedef const T* const_pointer; ///< A const pointer to the type used in the queue. + typedef queue_base::size_type size_type; ///< The type used for determining the size of the queue. + + private: + + typedef typename etl::parameter_type<T>::type parameter_t; + typedef typename etl::queue_base base_t; + + public: + + //************************************************************************* + /// Gets a reference to the value at the front of the queue.<br> + /// \return A reference to the value at the front of the queue. + //************************************************************************* + reference front() + { + return p_buffer[out]; + } + + //************************************************************************* + /// Gets a const reference to the value at the front of the queue.<br> + /// \return A const reference to the value at the front of the queue. + //************************************************************************* + const_reference front() const + { + return p_buffer[out]; + } + + //************************************************************************* + /// Gets a reference to the value at the back of the queue.<br> + /// \return A reference to the value at the back of the queue. + //************************************************************************* + reference back() + { + return p_buffer[in == 0 ? CAPACITY - 1 : in - 1]; + } + + //************************************************************************* + /// Gets a const reference to the value at the back of the queue.<br> + /// \return A const reference to the value at the back of the queue. + //************************************************************************* + const_reference back() const + { + return p_buffer[in == 0 ? CAPACITY - 1 : in - 1]; + } + + //************************************************************************* + /// Adds a value to the queue. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + ///\param value The value to push to the queue. + //************************************************************************* + void push(parameter_t value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(queue_full)); +#endif + ::new (&p_buffer[in]) T(value); + base_t::add_in(); + } + + //************************************************************************* + /// Allows a possibly more efficient 'push' by moving to the next input value + /// and returning a reference to it. + /// This may eliminate a copy by allowing direct construction in-place.<br> + /// If asserts or exceptions are enabled, throws an etl::queue_full is the queue is already full. + /// \return A reference to the position to 'push' to. + //************************************************************************* + reference push() + { + const size_type next = in; + +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(queue_full)); +#endif + base_t::add_in(); + + return p_buffer[next]; + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + ///\param value The value to use to construct the item to push to the queue. + //************************************************************************* + template <typename T1> + void emplace(const T1& value1) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(queue_full)); +#endif + ::new (&p_buffer[in]) T(value1); + base_t::add_in(); + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + ///\param value The value to use to construct the item to push to the queue. + //************************************************************************* + template <typename T1, typename T2> + void emplace(const T1& value1, const T2& value2) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(queue_full)); +#endif + ::new (&p_buffer[in]) T(value1, value2); + base_t::add_in(); + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + ///\param value The value to use to construct the item to push to the queue. + //************************************************************************* + template <typename T1, typename T2, typename T3> + void emplace(const T1& value1, const T2& value2, const T3& value3) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(queue_full)); +#endif + ::new (&p_buffer[in]) T(value1, value2, value3); + base_t::add_in(); + } + + //************************************************************************* + /// Constructs a value in the queue 'in place'. + /// If asserts or exceptions are enabled, throws an etl::queue_full if the queue if already full. + ///\param value The value to use to construct the item to push to the queue. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + void emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(queue_full)); +#endif + ::new (&p_buffer[in]) T(value1, value2, value3, value4); + base_t::add_in(); + } + + //************************************************************************* + /// Clears the queue to the empty state. + //************************************************************************* + void clear() + { + while (current_size > 0) + { + p_buffer[out].~T(); + base_t::del_out(); + } + + in = 0; + out = 0; + } + + //************************************************************************* + /// Removes the oldest value from the back of the queue. + /// Does nothing if the queue is already empty. + /// If asserts or exceptions are enabled, throws an etl::queue_empty if the queue is empty. + //************************************************************************* + void pop() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(queue_empty)); +#endif + p_buffer[out].~T(); + base_t::del_out(); + } + + //************************************************************************* + /// Gets the oldest value and removes it from the front of the queue. + /// If asserts or exceptions are enabled, throws an etl::queue_empty if the queue is empty. + //************************************************************************* + void pop_into(reference destination) + { + destination = front(); + pop(); + } + + //************************************************************************* + /// Gets the oldest value and removes it from the front of the queue and + /// pushes it to the destination container. + /// If asserts or exceptions are enabled, throws an etl::queue_empty if the queue is empty. + /// NOTE: The destination must support a push(T) member function. + //************************************************************************* + template <typename TContainer> + void pop_into(TContainer& destination) + { + destination.push(front()); + pop(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iqueue& operator = (const iqueue& rhs) + { + if (&rhs != this) + { + clear(); + clone(rhs); + } + + return *this; + } + + protected: + + //************************************************************************* + /// Make this a clone of the supplied queue + //************************************************************************* + void clone(const iqueue& other) + { + clear(); + + size_t index = other.out; + + for (size_t i = 0; i < other.size(); ++i) + { + push(other.p_buffer[index]); + index = (index == (CAPACITY - 1)) ? 0 : index + 1; + } + } + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + iqueue(T* p_buffer_, size_type max_size_) + : queue_base(max_size_), + p_buffer(p_buffer_) + { + } + + private: + + // Disable copy construction. + iqueue(const iqueue&); + + T* p_buffer; ///< The internal buffer. + }; + + //*************************************************************************** + ///\ingroup queue + /// A fixed capacity queue. + /// This queue does not support concurrent access by different threads. + /// \tparam T The type this queue should support. + /// \tparam SIZE The maximum capacity of the queue. + //*************************************************************************** + template <typename T, const size_t SIZE> + class queue : public etl::iqueue<T> + { + public: + + static const size_t MAX_SIZE = SIZE; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + queue() + : etl::iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE) + { + } + + //************************************************************************* + /// Copy constructor + //************************************************************************* + queue(const queue& rhs) + : etl::iqueue<T>(reinterpret_cast<T*>(&buffer[0]), SIZE) + { + etl::iqueue<T>::clone(rhs); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~queue() + { + etl::iqueue<T>::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + queue& operator = (const queue& rhs) + { + if (&rhs != this) + { + etl::iqueue<T>::clone(rhs); + } + + return *this; + } + + private: + + /// The uninitialised buffer of T used in the stack. + typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE]; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radix.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,68 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_RADIX__ +#define __ETL_RADIX__ + +#include <stdint.h> + +#include "platform.h" +#include "enum_type.h" + +///\defgroup radix radix +/// Radix constants for binary, octal, decimal and hex. +///\ingroup etl + +namespace etl +{ + /// \ingroup radix + struct radix + { + enum enum_type + { + undefined = 0, + binary = 2, + octal = 8, + decimal = 10, + hex = 16 + }; + + ETL_DECLARE_ENUM_TYPE(radix, uint_least8_t) + ETL_ENUM_TYPE(undefined, "undefined") + ETL_ENUM_TYPE(binary, "binary") + ETL_ENUM_TYPE(octal, "octal") + ETL_ENUM_TYPE(decimal, "decimal") + ETL_ENUM_TYPE(hex, "hex") + ETL_END_ENUM_TYPE + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/random.cpp Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,353 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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. +******************************************************************************/ + +#include "platform.h" +#include "random.h" + +namespace etl +{ + //*************************************************************************** + // XOR Shift + //*************************************************************************** + + //*************************************************************************** + /// Default constructor. + /// Attempts to come up with a unique non-zero seed. + //*************************************************************************** + random_xorshift::random_xorshift() + { + // An attempt to come up with a unique non-zero seed, + // based on the address of the instance. + uintptr_t n = reinterpret_cast<uintptr_t>(this); + uint32_t seed = static_cast<uint32_t>(n); + initialise(seed); + } + + //*************************************************************************** + /// Constructor with seed value. + ///\param seed The new seed value. + //*************************************************************************** + random_xorshift::random_xorshift(uint32_t seed) + { + initialise(seed); + } + + //*************************************************************************** + /// Initialises the sequence with a new seed value. + ///\param seed The new seed value. + //*************************************************************************** + void random_xorshift::initialise(uint32_t seed) + { + // Add the first four primes to ensure that the seed isn't zero. + state[0] = seed + 3; + state[1] = seed + 5; + state[2] = seed + 7; + state[3] = seed + 11; + } + + //*************************************************************************** + /// Get the next random_xorshift number. + //*************************************************************************** + uint32_t random_xorshift::operator()() + { + uint32_t n = state[3]; + n ^= n << 11; + n ^= n >> 8; + state[3] = state[2]; + state[2] = state[1]; + state[1] = state[0]; + n ^= state[0]; + n ^= state[0] >> 19; + state[0] = n; + + return n; + } + + //*************************************************************************** + /// Get the next random_xorshift number in a specified inclusive range. + //*************************************************************************** + uint32_t random_xorshift::range(uint32_t low, uint32_t high) + { + uint32_t r = high - low + 1; + uint32_t n = operator()(); + n %= r; + n += low; + + return n; + } + + //*************************************************************************** + // Linear Congruential Generator + //*************************************************************************** + + //*************************************************************************** + /// Default constructor. + /// Attempts to come up with a unique non-zero seed. + //*************************************************************************** + random_lcg::random_lcg() + { + // An attempt to come up with a unique non-zero seed, + // based on the address of the instance. + uintptr_t n = reinterpret_cast<uintptr_t>(this); + uint32_t seed = static_cast<uint32_t>(n); + initialise(seed); + } + + //*************************************************************************** + /// Constructor with seed value. + ///\param seed The new seed value. + //*************************************************************************** + random_lcg::random_lcg(uint32_t seed) + { + initialise(seed); + } + + //*************************************************************************** + /// Initialises the sequence with a new seed value. + ///\param seed The new seed value. + //*************************************************************************** + void random_lcg::initialise(uint32_t seed) + { + seed = (seed == 0) ? 1 : seed; + value = (seed > m) ? m : seed; + } + + //*************************************************************************** + /// Get the next random_clcg number. + //*************************************************************************** + uint32_t random_lcg::operator()() + { + value = (a * value) % m; + + return value; + } + + //*************************************************************************** + /// Get the next random_clcg number in a specified inclusive range. + //*************************************************************************** + uint32_t random_lcg::range(uint32_t low, uint32_t high) + { + uint32_t r = high - low + 1; + uint32_t n = operator()(); + n %= r; + n += low; + + return n; + } + + //*************************************************************************** + // Combined Linear Congruential Generator + //*************************************************************************** + + //*************************************************************************** + /// Default constructor. + /// Attempts to come up with a unique non-zero seed. + //*************************************************************************** + random_clcg::random_clcg() + { + // An attempt to come up with a unique non-zero seed, + // based on the address of the instance. + uintptr_t n = reinterpret_cast<uintptr_t>(this); + uint32_t seed = static_cast<uint32_t>(n); + initialise(seed); + } + + //*************************************************************************** + /// Constructor with seed value. + ///\param seed The new seed value. + //*************************************************************************** + random_clcg::random_clcg(uint32_t seed) + { + initialise(seed); + } + + //*************************************************************************** + /// Initialises the sequence with a new seed value. + ///\param seed The new seed value. + //*************************************************************************** + void random_clcg::initialise(uint32_t seed) + { + seed = (seed == 0) ? 1 : seed; + value1 = (seed > m1) ? m1 : seed; + value2 = (seed > m1) ? m1 : seed; + } + + //*************************************************************************** + /// Get the next random_clcg number. + //*************************************************************************** + uint32_t random_clcg::operator()() + { + static const uint32_t m = ((m1 > m2) ? m1 : m2); + + value1 = (a1 * value1) % m1; + value2 = (a2 * value2) % m2; + + return (value1 + value2) % m; + } + + //*************************************************************************** + /// Get the next random_clcg number in a specified inclusive range. + //*************************************************************************** + uint32_t random_clcg::range(uint32_t low, uint32_t high) + { + uint32_t r = high - low + 1; + uint32_t n = operator()(); + n %= r; + n += low; + + return n; + } + + //*************************************************************************** + // Linear Shift Feedback Register + //*************************************************************************** + + //*************************************************************************** + /// Default constructor. + /// Attempts to come up with a unique non-zero seed. + //*************************************************************************** + random_lsfr::random_lsfr() + { + // An attempt to come up with a unique non-zero seed, + // based on the address of the instance. + uintptr_t n = reinterpret_cast<uintptr_t>(this); + uint32_t seed = static_cast<uint32_t>(n); + initialise(seed); + } + + //*************************************************************************** + /// Constructor with seed value. + ///\param seed The new seed value. + //*************************************************************************** + random_lsfr::random_lsfr(uint32_t seed) + { + initialise(seed); + } + + //*************************************************************************** + /// Initialises the sequence with a new seed value. + ///\param seed The new seed value. + //*************************************************************************** + void random_lsfr::initialise(uint32_t seed) + { + value = seed; + } + + //*************************************************************************** + /// Get the next random_lsfr number. + //*************************************************************************** + uint32_t random_lsfr::operator()() + { + static const uint32_t polynomial = 0x80200003; + + value >>= 1; + + if ((value & 1) == 1) + { + value ^= polynomial; + } + + return value; + } + + //*************************************************************************** + /// Get the next random_lsfr number in a specified inclusive range. + //*************************************************************************** + uint32_t random_lsfr::range(uint32_t low, uint32_t high) + { + uint32_t r = high - low + 1; + uint32_t n = operator()(); + n %= r; + n += low; + + return n; + } + + //*************************************************************************** + // Multiply with carry random number generator. + //*************************************************************************** + + //*************************************************************************** + /// Default constructor. + /// Attempts to come up with a unique non-zero seed. + //*************************************************************************** + random_mwc::random_mwc() + { + // An attempt to come up with a unique non-zero seed, + // based on the address of the instance. + uintptr_t n = reinterpret_cast<uintptr_t>(this); + uint32_t seed = static_cast<uint32_t>(n); + initialise(seed); + } + + //*************************************************************************** + /// Constructor with seed value. + ///\param seed The new seed value. + //*************************************************************************** + random_mwc::random_mwc(uint32_t seed) + { + initialise(seed); + } + + //*************************************************************************** + /// Initialises the sequence with a new seed value. + ///\param seed The new seed value. + //*************************************************************************** + void random_mwc::initialise(uint32_t seed) + { + value1 = seed; + value2 = seed; + } + + //*************************************************************************** + /// Get the next random_lsfr number. + //*************************************************************************** + uint32_t random_mwc::operator()() + { + value1 = 36969 * (value1 & 0xFFFF) + (value1 >> 16); + value2 = 18000 * (value2 & 0xFFFF) + (value2 >> 16); + + return (value1 << 16) + value2; + } + + //*************************************************************************** + /// Get the next random_lsfr number in a specified inclusive range. + //*************************************************************************** + uint32_t random_mwc::range(uint32_t low, uint32_t high) + { + uint32_t r = high - low + 1; + uint32_t n = operator()(); + n %= r; + n += low; + + return n; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/random.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,168 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_RANDOM__ +#define __ETL_RANDOM__ + +#include <stdint.h> + +#include "platform.h" + +namespace etl +{ + //*************************************************************************** + /// The base for all 32 bit random number generators. + //*************************************************************************** + class random + { + public: + + virtual ~random() + { + } + + virtual void initialise(uint32_t seed) = 0; + virtual uint32_t operator()() = 0; + virtual uint32_t range(uint32_t low, uint32_t high) = 0; + }; + + //*************************************************************************** + /// A 32 bit random number generator. + /// Uses a 128 bit XOR shift algorithm. + /// https://en.wikipedia.org/wiki/Xorshift + //*************************************************************************** + class random_xorshift : public random + { + public: + + random_xorshift(); + explicit random_xorshift(uint32_t seed); + void initialise(uint32_t seed); + uint32_t operator()(); + uint32_t range(uint32_t low, uint32_t high); + + private: + + uint32_t state[4]; + }; + + //*************************************************************************** + /// A 32 bit random number generator. + /// Uses a linear congruential generator. + /// https://cs.adelaide.edu.au/~paulc/teaching/montecarlo/node107.html + //*************************************************************************** + class random_lcg : public random + { + public: + + random_lcg(); + explicit random_lcg(uint32_t seed); + void initialise(uint32_t seed); + uint32_t operator()(); + uint32_t range(uint32_t low, uint32_t high); + + private: + + static const uint32_t a = 40014; + static const uint32_t m = 2147483563; + + uint32_t value; + }; + + //*************************************************************************** + /// A 32 bit random number generator. + /// Uses a combined linear congruential generator. + /// https://cs.adelaide.edu.au/~paulc/teaching/montecarlo/node107.html + //*************************************************************************** + class random_clcg : public random + { + public: + + random_clcg(); + explicit random_clcg(uint32_t seed); + void initialise(uint32_t seed); + uint32_t operator()(); + uint32_t range(uint32_t low, uint32_t high); + + private: + + static const uint32_t a1 = 40014; + static const uint32_t m1 = 2147483563; + + static const uint32_t a2 = 40692; + static const uint32_t m2 = 2147483399; + + uint32_t value1; + uint32_t value2; + }; + + //*************************************************************************** + /// A 32 bit random number generator. + /// Uses a linear shift feedback register. + /// https://en.wikipedia.org/wiki/Linear-feedback_shift_register + //*************************************************************************** + class random_lsfr : public random + { + public: + + random_lsfr(); + explicit random_lsfr(uint32_t seed); + void initialise(uint32_t seed); + uint32_t operator()(); + uint32_t range(uint32_t low, uint32_t high); + + private: + + uint32_t value; + }; + + //*************************************************************************** + /// A 32 bit random number generator. + /// Uses a multiply with carry calculation. + //*************************************************************************** + class random_mwc : public random + { + public: + + random_mwc(); + explicit random_mwc(uint32_t seed); + void initialise(uint32_t seed); + uint32_t operator()(); + uint32_t range(uint32_t low, uint32_t high); + + private: + + uint32_t value1; + uint32_t value2; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ratio.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,95 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_RATIO__ +#define __ETL_RATIO__ + +#include <stdint.h> + +///\defgroup ratio ratio +///\ingroup utilities + +namespace etl +{ + template <const size_t NUM, const size_t DEN = 1> + struct ratio + { + static const std::intmax_t num = NUM; + static const std::intmax_t den = DEN; + }; + + #if INT_MAX > INT32_MAX + typedef ratio<1, 1000000000000000000000000> yocto; + typedef ratio<1, 1000000000000000000000> zepto; + typedef ratio<1, 1000000000000000000> atto + typedef ratio<1, 1000000000000000> femto + typedef ratio<1, 1000000000000> pico; + #endif + + #if (INT_MAX >= INT32_MAX) + typedef ratio<1, 1000000000> nano; + typedef ratio<1, 1000000> micro; + #endif + + #if (INT_MAX >= INT16_MAX) + typedef ratio<1, 1000> milli; + typedef ratio<1, 100> centi; + typedef ratio<1, 10> deci; + typedef ratio<10, 1> deca; + typedef ratio<100, 1> hecto + typedef ratio<1000, 1> kilo + #endif + + #if (INT_MAX >= INT32_MAX) + typedef ratio<1000000, 1> mega; + typedef ratio<1000000000, 1> giga; + #endif + + #if INT_MAX > INT32_MAX + typedef ratio<1000000000000, 1> tera; + typedef ratio<1000000000000000, 1> peta; + typedef ratio<1000000000000000000, 1> exa; + typedef ratio<1000000000000000000000, 1> zetta; + typedef ratio<1000000000000000000000000, 1> yotta; + #endif + + /// An approximation of PI to 6 digits. + typedef ratio<355, 113> ratio_pi; + + /// An approximation of root 2. + typedef ratio<239, 169> ratio_root2; + + /// An approximation of e. + typedef ratio<326, 120> ratio_e; +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/reference_flat_map.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,957 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_REFERENCE_FLAT_MAP__ +#define __ETL_REFERENCE_FLAT_MAP__ + +#include <stddef.h> + +#include "platform.h" +#include "vector.h" +#include "error_handler.h" +#include "debug_count.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "exception.h" +#include "static_assert.h" + +#undef ETL_FILE +#define ETL_FILE "30" + +//***************************************************************************** +///\defgroup reference_flat_map reference_flat_map +/// An reference_flat_map with the capacity defined at compile time. +/// Has insertion of O(N) and search of O(logN) +/// Duplicate entries are not allowed. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + ///\ingroup reference_flat_map + /// Exception base for reference_flat_maps + //*************************************************************************** + class flat_map_exception : public etl::exception + { + public: + + flat_map_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup reference_flat_map + /// Vector full exception. + //*************************************************************************** + class flat_map_full : public etl::flat_map_exception + { + public: + + flat_map_full(string_type file_name_, numeric_type line_number_) + : flat_map_exception(ETL_ERROR_TEXT("flat_map: full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup reference_flat_map + /// Vector out of bounds exception. + //*************************************************************************** + class flat_map_out_of_bounds : public etl::flat_map_exception + { + public: + + flat_map_out_of_bounds(string_type file_name_, numeric_type line_number_) + : flat_map_exception(ETL_ERROR_TEXT("flat_map:bounds", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized reference_flat_maps. + /// Can be used as a reference type for all reference_flat_maps containing a specific type. + ///\ingroup reference_flat_map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> > + class ireference_flat_map + { + public: + + typedef std::pair<const TKey, TMapped> value_type; + + protected: + + typedef etl::ivector<value_type*> lookup_t; + + public: + + typedef TKey key_type; + typedef TMapped mapped_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type> + { + public: + + friend class ireference_flat_map; + + iterator() + { + } + + iterator(typename lookup_t::iterator ilookup_) + : ilookup(ilookup_) + { + } + + iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + iterator& operator ++() + { + ++ilookup; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + ++ilookup; + return temp; + } + + iterator& operator --() + { + --ilookup; + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return &(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::iterator ilookup; + }; + + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> + { + public: + + friend class ireference_flat_map; + + const_iterator() + { + } + + const_iterator(typename lookup_t::const_iterator ilookup_) + : ilookup(ilookup_) + { + } + + const_iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator(const const_iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator =(const const_iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator ++() + { + ++ilookup; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + ++ilookup; + return temp; + } + + const_iterator& operator --() + { + --ilookup; + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + --ilookup; + return temp; + } + + const_reference operator *() const + { + return *(*ilookup); + } + + const_pointer operator &() const + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::const_iterator ilookup; + }; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + protected: + + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + private: + + //********************************************************************* + /// How to compare elements and keys. + //********************************************************************* + class compare + { + public: + + bool operator ()(const value_type& element, key_type key) const + { + return key_compare()(element.first, key); + } + + bool operator ()(key_type key, const value_type& element) const + { + return key_compare()(key, element.first); + } + }; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the reference_flat_map. + ///\return An iterator to the beginning of the reference_flat_map. + //********************************************************************* + iterator begin() + { + return iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the reference_flat_map. + ///\return A const iterator to the beginning of the reference_flat_map. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns an iterator to the end of the reference_flat_map. + ///\return An iterator to the end of the reference_flat_map. + //********************************************************************* + iterator end() + { + return iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the reference_flat_map. + ///\return A const iterator to the end of the reference_flat_map. + //********************************************************************* + const_iterator end() const + { + return const_iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the reference_flat_map. + ///\return A const iterator to the beginning of the reference_flat_map. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(lookup.cbegin()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the reference_flat_map. + ///\return A const iterator to the end of the reference_flat_map. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(lookup.cend()); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the reference_flat_map. + ///\return Iterator to the reverse beginning of the reference_flat_map. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the reference_flat_map. + ///\return Const iterator to the reverse beginning of the reference_flat_map. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the reference_flat_map. + ///\return Reverse iterator to the end + 1 of the reference_flat_map. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the reference_flat_map. + ///\return Const reverse iterator to the end + 1 of the reference_flat_map. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the reference_flat_map. + ///\return Const reverse iterator to the reverse beginning of the reference_flat_map. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(lookup.crbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the reference_flat_map. + ///\return Const reverse iterator to the end + 1 of the reference_flat_map. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(lookup.crend()); + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& operator [](key_parameter_t key) + { + iterator i_element = lower_bound(key); + + ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'key' + ///\param i The index. + ///\return A const reference to the value at index 'key' + //********************************************************************* + const mapped_type& operator [](key_parameter_t key) const + { + iterator i_element = lower_bound(key); + + ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& at(key_parameter_t key) + { + iterator i_element = lower_bound(key); + + ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::flat_map_out_of_bounds if the key is not in the range. + ///\param i The index. + ///\return A const reference to the value at index 'key' + //********************************************************************* + const mapped_type& at(key_parameter_t key) const + { + const_iterator i_element = lower_bound(key); + + ETL_ASSERT(i_element != end(), ETL_ERROR(flat_map_out_of_bounds)); + + return i_element->second; + } + + //********************************************************************* + /// Assigns values to the reference_flat_map. + /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined, emits flat_map_full if the reference_flat_map does not have enough free space. + /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined, emits flat_map_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { + STATIC_ASSERT((etl::is_same<value_type, typename std::iterator_traits<TIterator>::value_type>::value), "Incompatible data for assign"); + +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_map_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the reference_flat_map. + /// If asserts or exceptions are enabled, emits flat_map_full if the reference_flat_map is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(reference value) + { + iterator i_element = lower_bound(value.first); + + return insert_at(i_element, value); + } + + //********************************************************************* + /// Inserts a value to the reference_flat_map. + /// If asserts or exceptions are enabled, emits flat_map_full if the reference_flat_map is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, reference value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the reference_flat_map. + /// If asserts or exceptions are enabled, emits flat_map_full if the reference_flat_map does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(key_parameter_t key) + { + iterator i_element = find(key); + + if (i_element == end()) + { + return 0; + } + else + { + lookup.erase(i_element.ilookup); + return 1; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + lookup.erase(i_element.ilookup); + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + lookup.erase(first.ilookup, last.ilookup); + } + + //************************************************************************* + /// Clears the reference_flat_map. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_parameter_t key) + { + iterator itr = lower_bound(key); + + if (itr != end()) + { + if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + const_iterator itr = lower_bound(key); + + if (itr != end()) + { + if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_parameter_t key) const + { + return (find(key) == end()) ? 0 : 1; + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(key_parameter_t key) + { + return std::lower_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(key_parameter_t key) const + { + return std::lower_bound(cbegin(), cend(), key, compare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(key_parameter_t key) + { + return std::upper_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(key_parameter_t key) const + { + return std::upper_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + iterator i_lower = std::lower_bound(begin(), end(), key, compare()); + + return std::make_pair(i_lower, std::upper_bound(i_lower, end(), key, compare())); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + const_iterator i_lower = std::lower_bound(cbegin(), cend(), key, compare()); + + return std::make_pair(i_lower, std::upper_bound(i_lower, cend(), key, compare())); + } + + //************************************************************************* + /// Gets the current size of the reference_flat_map. + ///\return The current size of the reference_flat_map. + //************************************************************************* + size_type size() const + { + return lookup.size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the reference_flat_map. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return lookup.empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the reference_flat_map. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return lookup.full(); + } + + //************************************************************************* + /// Returns the capacity of the reference_flat_map. + ///\return The capacity of the reference_flat_map. + //************************************************************************* + size_type capacity() const + { + return lookup.capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the reference_flat_map. + ///\return The maximum size of the reference_flat_map. + //************************************************************************* + size_type max_size() const + { + return lookup.max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return lookup.available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + ireference_flat_map(lookup_t& lookup_) + : lookup(lookup_) + { + } + + //********************************************************************* + /// Inserts a value to the reference_flat_map. + ///\param i_element The place to insert. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert_at(iterator i_element, value_type& value) + { + std::pair<iterator, bool> result(end(), false); + + if (i_element == end()) + { + // At the end. + ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_map_full)); + + lookup.push_back(&value); + result.first = --end(); + result.second = true; + } + else + { + // Not at the end. + result.first = i_element; + + // Existing element? + if (value.first != i_element->first) + { + // A new one. + ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_map_full)); + lookup.insert(i_element.ilookup, &value); + result.second = true; + } + } + + return result; + } + + private: + + // Disable copy construction and assignment. + ireference_flat_map(const ireference_flat_map&); + ireference_flat_map& operator = (const ireference_flat_map&); + + lookup_t& lookup; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first reference_flat_map. + ///\param rhs Reference to the second reference_flat_map. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup reference_flat_map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator ==(const etl::ireference_flat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::ireference_flat_map<TKey, TMapped, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first reference_flat_map. + ///\param rhs Reference to the second reference_flat_map. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup reference_flat_map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator !=(const etl::ireference_flat_map<TKey, TMapped, TKeyCompare>& lhs, const etl::ireference_flat_map<TKey, TMapped, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// A reference_flat_map implementation that uses a fixed size buffer. + ///\tparam TKey The key type. + ///\tparam TValue The value type. + ///\tparam TCompare The type to compare keys. Default = std::less<TKey> + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup reference_flat_map + //*************************************************************************** + template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> > + class reference_flat_map : public ireference_flat_map<TKey, TValue, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + reference_flat_map() + : ireference_flat_map<TKey, TValue, TCompare>(lookup) + { + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + reference_flat_map(TIterator first, TIterator last) + : ireference_flat_map<TKey, TValue, TCompare>(lookup) + { + ireference_flat_map<TKey, TValue, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~reference_flat_map() + { + ireference_flat_map<TKey, TValue, TCompare>::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + reference_flat_map& operator = (const reference_flat_map& rhs) + { + if (&rhs != this) + { + ireference_flat_map<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + reference_flat_map(const reference_flat_map&); + + typedef typename ireference_flat_map<TKey, TValue, TCompare>::value_type node_t; + + // The vector that stores pointers to the nodes. + etl::vector<node_t*, MAX_SIZE> lookup; + }; + +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/reference_flat_multimap.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,863 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_REFERENCE_FLAT_MULTIMAP_BASE__ +#define __ETL_REFERENCE_FLAT_MULTIMAP_BASE__ + +#include <stddef.h> + +#include "platform.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "vector.h" + +#undef ETL_FILE +#define ETL_FILE "31" + +namespace etl +{ + //*************************************************************************** + ///\ingroup reference_flat_multimap + /// Exception base for reference_flat_multimaps + //*************************************************************************** + class flat_multimap_exception : public exception + { + public: + + flat_multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup reference_flat_multimap + /// Vector full exception. + //*************************************************************************** + class flat_multimap_full : public flat_multimap_exception + { + public: + + flat_multimap_full(string_type file_name_, numeric_type line_number_) + : flat_multimap_exception(ETL_ERROR_TEXT("flat_multimap:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized reference_flat_multimaps. + /// Can be used as a reference type for all reference_flat_multimaps containing a specific type. + ///\ingroup reference_flat_multimap + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare = std::less<TKey> > + class ireference_flat_multimap + { + public: + + typedef std::pair<const TKey, TMapped> value_type; + + protected: + + typedef etl::ivector<value_type*> lookup_t; + + public: + + typedef TKey key_type; + typedef TMapped mapped_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type> + { + public: + + friend class ireference_flat_multimap; + + iterator() + { + } + + iterator(typename lookup_t::iterator ilookup_) + : ilookup(ilookup_) + { + } + + iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + iterator& operator ++() + { + ++ilookup; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + ++ilookup; + return temp; + } + + iterator& operator --() + { + --ilookup; + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return &(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::iterator ilookup; + }; + + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> + { + public: + + friend class ireference_flat_multimap; + + const_iterator() + { + } + + const_iterator(typename lookup_t::const_iterator ilookup_) + : ilookup(ilookup_) + { + } + + const_iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator(const const_iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator =(const const_iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator ++() + { + ++ilookup; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + ++ilookup; + return temp; + } + + const_iterator& operator --() + { + --ilookup; + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + --ilookup; + return temp; + } + + const_reference operator *() const + { + return *(*ilookup); + } + + const_pointer operator &() const + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::const_iterator ilookup; + }; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + protected: + + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + private: + + //********************************************************************* + /// How to compare elements and keys. + //********************************************************************* + class compare + { + public: + + bool operator ()(const value_type& element, key_type key) const + { + return key_compare()(element.first, key); + } + + bool operator ()(key_type key, const value_type& element) const + { + return key_compare()(key, element.first); + } + }; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the reference_flat_multimap. + ///\return An iterator to the beginning of the reference_flat_multimap. + //********************************************************************* + iterator begin() + { + return iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the reference_flat_multimap. + ///\return A const iterator to the beginning of the reference_flat_multimap. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns an iterator to the end of the reference_flat_multimap. + ///\return An iterator to the end of the reference_flat_multimap. + //********************************************************************* + iterator end() + { + return iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the reference_flat_multimap. + ///\return A const iterator to the end of the reference_flat_multimap. + //********************************************************************* + const_iterator end() const + { + return const_iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the reference_flat_multimap. + ///\return A const iterator to the beginning of the reference_flat_multimap. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(lookup.cbegin()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the reference_flat_multimap. + ///\return A const iterator to the end of the reference_flat_multimap. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(lookup.cend()); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the reference_flat_multimap. + ///\return Iterator to the reverse beginning of the reference_flat_multimap. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the reference_flat_multimap. + ///\return Const iterator to the reverse beginning of the reference_flat_multimap. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the reference_flat_multimap. + ///\return Reverse iterator to the end + 1 of the reference_flat_multimap. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the reference_flat_multimap. + ///\return Const reverse iterator to the end + 1 of the reference_flat_multimap. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the reference_flat_multimap. + ///\return Const reverse iterator to the reverse beginning of the reference_flat_multimap. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(lookup.crbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the reference_flat_multimap. + ///\return Const reverse iterator to the end + 1 of the reference_flat_multimap. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(lookup.crend()); + } + + //********************************************************************* + /// Assigns values to the reference_flat_multimap. + /// If asserts or exceptions are enabled, emits reference_flat_multimap_full if the reference_flat_multimap does not have enough free space. + /// If asserts or exceptions are enabled, emits reference_flat_multimap_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_multimap_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the reference_flat_multimap. + /// If asserts or exceptions are enabled, emits reference_flat_multimap_full if the reference_flat_multimap is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(value_type& value) + { + ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_multimap_full)); + + std::pair<iterator, bool> result(end(), false); + + iterator i_element = lower_bound(value.first); + + return insert_at(i_element, value); + } + + //********************************************************************* + /// Inserts a value to the flast_multi. + /// If asserts or exceptions are enabled, emits flat_map_full if the flat_map is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, const value_type& value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the reference_flat_multimap. + /// If asserts or exceptions are enabled, emits reference_flat_multimap_full if the reference_flat_multimap does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(key_parameter_t key) + { + std::pair<iterator, iterator> range = equal_range(key); + + if (range.first == end()) + { + return 0; + } + else + { + size_t d = std::distance(range.first, range.second); + erase(range.first, range.second); + return d; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + lookup.erase(i_element.ilookup); + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + lookup.erase(first.ilookup, last.ilookup); + } + + //************************************************************************* + /// Clears the reference_flat_multimap. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_parameter_t key) + { + iterator itr = lower_bound(key); + + if (itr != end()) + { + if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + const_iterator itr = lower_bound(key); + + if (itr != end()) + { + if (!key_compare()(itr->first, key) && !key_compare()(key, itr->first)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_parameter_t key) const + { + std::pair<const_iterator, const_iterator> range = equal_range(key); + + return std::distance(range.first, range.second); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(key_parameter_t key) + { + return std::lower_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(key_parameter_t key) const + { + return std::lower_bound(cbegin(), cend(), key, compare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(key_parameter_t key) + { + return std::upper_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(key_parameter_t key) const + { + return std::upper_bound(begin(), end(), key, compare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + iterator i_lower = std::lower_bound(begin(), end(), key, compare()); + + return std::make_pair(i_lower, std::upper_bound(i_lower, end(), key, compare())); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + const_iterator i_lower = std::lower_bound(cbegin(), cend(), key, compare()); + + return std::make_pair(i_lower, std::upper_bound(i_lower, cend(), key, compare())); + } + + //************************************************************************* + /// Gets the current size of the flat_multiset. + ///\return The current size of the flat_multiset. + //************************************************************************* + size_type size() const + { + return lookup.size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the flat_multiset. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return lookup.empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the flat_multiset. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return lookup.full(); + } + + //************************************************************************* + /// Returns the capacity of the flat_multiset. + ///\return The capacity of the flat_multiset. + //************************************************************************* + size_type capacity() const + { + return lookup.capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the flat_multiset. + ///\return The maximum size of the flat_multiset. + //************************************************************************* + size_type max_size() const + { + return lookup.max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return lookup.available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + ireference_flat_multimap(lookup_t& lookup_) + : lookup(lookup_) + { + } + + //********************************************************************* + /// Inserts a value to the reference_flat_multimap. + ///\param i_element The place to insert. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert_at(iterator i_element, value_type& value) + { + std::pair<iterator, bool> result(end(), false); + + if (i_element == end()) + { + // At the end. + lookup.push_back(&value); + result.first = --end(); + result.second = true; + } + else + { + // Not at the end. + lookup.insert(i_element.ilookup, &value); + result.first = i_element; + result.second = true; + } + + return result; + } + + private: + + // Disable copy construction and assignment. + ireference_flat_multimap(const ireference_flat_multimap&); + ireference_flat_multimap& operator = (const ireference_flat_multimap&); + + lookup_t& lookup; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first reference_flat_multimap. + ///\param rhs Reference to the second reference_flat_multimap. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup reference_flat_multimap + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator ==(const etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first reference_flat_multimap. + ///\param rhs Reference to the second reference_flat_multimap. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup reference_flat_multimap + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator !=(const etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::ireference_flat_multimap<TKey, TMapped, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> > + //*************************************************************************** + /// A reference_flat_multimap implementation that uses a fixed size buffer. + ///\tparam TKey The key type. + ///\tparam TValue The value type. + ///\tparam TCompare The type to compare keys. Default = std::less<TKey> + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup reference_flat_multimap + //*************************************************************************** + class reference_flat_multimap : public ireference_flat_multimap<TKey, TValue, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + reference_flat_multimap() + : ireference_flat_multimap<TKey, TValue, TCompare>(lookup) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + reference_flat_multimap(const reference_flat_multimap& other) + : ireference_flat_multimap<TKey, TValue, TCompare>(lookup) + { + ireference_flat_multimap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + reference_flat_multimap(TIterator first, TIterator last) + : ireference_flat_multimap<TKey, TValue, TCompare>(lookup) + { + ireference_flat_multimap<TKey, TValue, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~reference_flat_multimap() + { + ireference_flat_multimap<TKey, TValue, TCompare>::clear(); + } + + private: + + typedef typename ireference_flat_multimap<TKey, TValue, TCompare>::value_type node_t; + + // The vector that stores pointers to the nodes. + etl::vector<node_t*, MAX_SIZE> lookup; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/reference_flat_multiset.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,871 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_REFERENCE_FLAT_MULTISET__ +#define __ETL_REFERENCE_FLAT_MULTISET__ + +#include <iterator> +#include <algorithm> +#include <functional> +#include <utility> +#include <stddef.h> + +#include "platform.h" +#include "type_traits.h" +#include "vector.h" +#include "pool.h" +#include "error_handler.h" +#include "exception.h" + +#undef ETL_FILE +#define ETL_FILE "33" + +namespace etl +{ + //*************************************************************************** + ///\ingroup reference_flat_multiset + /// Exception base for reference_flat_multisets + //*************************************************************************** + class flat_multiset_exception : public exception + { + public: + + flat_multiset_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup reference_flat_multiset + /// Vector full exception. + //*************************************************************************** + class flat_multiset_full : public flat_multiset_exception + { + public: + + flat_multiset_full(string_type file_name_, numeric_type line_number_) + : flat_multiset_exception(ETL_ERROR_TEXT("flat_multiset:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup reference_flat_multiset + /// Vector iterator exception. + //*************************************************************************** + class flat_multiset_iterator : public flat_multiset_exception + { + public: + + flat_multiset_iterator(string_type file_name_, numeric_type line_number_) + : flat_multiset_exception(ETL_ERROR_TEXT("flat_multiset:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized reference_flat_multisets. + /// Can be used as a reference type for all reference_flat_multisets containing a specific type. + ///\ingroup reference_flat_multiset + //*************************************************************************** + template <typename T, typename TKeyCompare = std::less<T> > + class ireference_flat_multiset + { + public: + + typedef T key_type; + typedef T value_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + protected: + + typedef etl::ivector<value_type*> lookup_t; + + public: + + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type> + { + public: + + friend class ireference_flat_multiset; + + iterator() + { + } + + iterator(typename lookup_t::iterator ilookup_) + : ilookup(ilookup_) + { + } + + iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + iterator& operator ++() + { + ++ilookup; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + ++ilookup; + return temp; + } + + iterator& operator --() + { + --ilookup; + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return &(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::iterator ilookup; + }; + + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> + { + public: + + friend class ireference_flat_multiset; + + const_iterator() + { + } + + const_iterator(typename lookup_t::const_iterator ilookup_) + : ilookup(ilookup_) + { + } + + const_iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator(const const_iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator =(const const_iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator ++() + { + ++ilookup; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + ++ilookup; + return temp; + } + + const_iterator& operator --() + { + --ilookup; + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + --ilookup; + return temp; + } + + const_reference operator *() const + { + return *(*ilookup); + } + + const_pointer operator &() const + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::const_iterator ilookup; + }; + + protected: + + typedef typename etl::parameter_type<T>::type parameter_t; + + public: + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the reference_flat_multiset. + ///\return An iterator to the beginning of the reference_flat_multiset. + //********************************************************************* + iterator begin() + { + return iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the reference_flat_multiset. + ///\return A const iterator to the beginning of the reference_flat_multiset. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns an iterator to the end of the reference_flat_multiset. + ///\return An iterator to the end of the reference_flat_multiset. + //********************************************************************* + iterator end() + { + return iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the reference_flat_multiset. + ///\return A const iterator to the end of the reference_flat_multiset. + //********************************************************************* + const_iterator end() const + { + return const_iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the reference_flat_multiset. + ///\return A const iterator to the beginning of the reference_flat_multiset. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(lookup.cbegin()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the reference_flat_multiset. + ///\return A const iterator to the end of the reference_flat_multiset. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(lookup.cend()); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the reference_flat_multiset. + ///\return Iterator to the reverse beginning of the reference_flat_multiset. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the reference_flat_multiset. + ///\return Const iterator to the reverse beginning of the reference_flat_multiset. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the reference_flat_multiset. + ///\return Reverse iterator to the end + 1 of the reference_flat_multiset. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the reference_flat_multiset. + ///\return Const reverse iterator to the end + 1 of the reference_flat_multiset. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the reference_flat_multiset. + ///\return Const reverse iterator to the reverse beginning of the reference_flat_multiset. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(lookup.crbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the reference_flat_multiset. + ///\return Const reverse iterator to the end + 1 of the reference_flat_multiset. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(lookup.crend()); + } + + //********************************************************************* + /// Assigns values to the reference_flat_multiset. + /// If asserts or exceptions are enabled, emits reference_flat_multiset_full if the reference_flat_multiset does not have enough free space. + /// If asserts or exceptions are enabled, emits reference_flat_multiset_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_multiset_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the reference_flat_multiset. + /// If asserts or exceptions are enabled, emits reference_flat_multiset_full if the reference_flat_multiset is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(value_type& value) + { + std::pair<iterator, bool> result(end(), false); + + ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_multiset_full)); + + iterator i_element = std::lower_bound(begin(), end(), value, TKeyCompare()); + + if (i_element == end()) + { + // At the end. Doesn't exist. + lookup.push_back(&value); + result.first = --end(); + result.second = true; + } + else + { + // Not at the end. + lookup.insert(i_element.ilookup, &value); + result.first = i_element; + result.second = true; + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the reference_flat_multiset. + /// If asserts or exceptions are enabled, emits reference_flat_multiset_full if the reference_flat_multiset is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, value_type& value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the reference_flat_multiset. + /// If asserts or exceptions are enabled, emits reference_flat_multiset_full if the reference_flat_multiset does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(parameter_t key) + { + std::pair<iterator, iterator> range = equal_range(key); + + if (range.first == end()) + { + return 0; + } + else + { + size_t d = std::distance(range.first, range.second); + erase(range.first, range.second); + return d; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + lookup.erase(i_element.ilookup); + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + lookup.erase(first.ilookup, last.ilookup);; + } + + //************************************************************************* + /// Clears the reference_flat_multiset. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(parameter_t key) + { + iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare()); + + if (itr != end()) + { + if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(parameter_t key) const + { + const_iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare()); + + if (itr != end()) + { + if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(parameter_t key) const + { + std::pair<const_iterator, const_iterator> range = equal_range(key); + + return std::distance(range.first, range.second); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(parameter_t key) + { + return std::lower_bound(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(parameter_t key) const + { + return std::lower_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(parameter_t key) + { + return std::upper_bound(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(parameter_t key) const + { + return std::upper_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<iterator, iterator> equal_range(parameter_t key) + { + return std::equal_range(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const + { + return std::equal_range(begin(), end(), key, TKeyCompare()); + } + + //************************************************************************* + /// Gets the current size of the reference_flat_multiset. + ///\return The current size of the reference_flat_multiset. + //************************************************************************* + size_type size() const + { + return lookup.size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the reference_flat_multiset. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return lookup.empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the reference_flat_multiset. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return lookup.full(); + } + + //************************************************************************* + /// Returns the capacity of the reference_flat_multiset. + ///\return The capacity of the reference_flat_multiset. + //************************************************************************* + size_type capacity() const + { + return lookup.capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the reference_flat_multiset. + ///\return The maximum size of the reference_flat_multiset. + //************************************************************************* + size_type max_size() const + { + return lookup.max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return lookup.available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + ireference_flat_multiset(lookup_t& lookup_) + : lookup(lookup_) + { + } + + //********************************************************************* + /// Inserts a value to the reference_flat_set. + ///\param i_element The place to insert. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert_at(iterator i_element, reference value) + { + std::pair<iterator, bool> result(end(), false); + + if (i_element == end()) + { + // At the end. + ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_multiset_full)); + + lookup.push_back(&value); + result.first = --end(); + result.second = true; + } + else + { + // Not at the end. + result.first = i_element; + + // A new one. + ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_multiset_full)); + lookup.insert(i_element.ilookup, &value); + result.second = true; + } + + return result; + } + + private: + + // Disable copy construction. + ireference_flat_multiset(const ireference_flat_multiset&); + ireference_flat_multiset& operator =(const ireference_flat_multiset&); + + lookup_t& lookup; + }; + + //*************************************************************************** + /// An reference flat set + ///\ingroup reference_flat_multiset + //*************************************************************************** + template <typename TKey, const size_t MAX_SIZE_, typename TKeyCompare = std::less<TKey> > + class reference_flat_multiset : public ireference_flat_multiset<TKey, TKeyCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + reference_flat_multiset() + : ireference_flat_multiset<TKey, TKeyCompare>(lookup) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + reference_flat_multiset(const reference_flat_multiset& other) + : ireference_flat_multiset<TKey, TKeyCompare>(lookup) + { + ireference_flat_multiset<TKey, TKeyCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + reference_flat_multiset(TIterator first, TIterator last) + : ireference_flat_multiset<TKey, TKeyCompare>(lookup) + { + ireference_flat_multiset<TKey, TKeyCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~reference_flat_multiset() + { + ireference_flat_multiset<TKey, TKeyCompare>::clear(); + } + + private: + + typedef TKey value_type; + + // The vector that stores pointers to the nodes. + etl::vector<value_type*, MAX_SIZE> lookup; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first reference_flat_multiset. + ///\param rhs Reference to the second reference_flat_multiset. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup reference_flat_multiset + //*************************************************************************** + template <typename T, typename TKeyCompare> + bool operator ==(const etl::ireference_flat_multiset<T, TKeyCompare>& lhs, const etl::ireference_flat_multiset<T, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first reference_flat_multiset. + ///\param rhs Reference to the second reference_flat_multiset. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup reference_flat_multiset + //*************************************************************************** + template <typename T, typename TKeyCompare> + bool operator !=(const etl::ireference_flat_multiset<T, TKeyCompare>& lhs, const etl::ireference_flat_multiset<T, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } +} + +#undef ETL_FILE +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/reference_flat_set.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,853 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_REFERENCE_FLAT_SET__ +#define __ETL_REFERENCE_FLAT_SET__ + +#include <iterator> +#include <algorithm> +#include <functional> +#include <utility> +#include <stddef.h> + +#include "platform.h" +#include "type_traits.h" +#include "pool.h" +#include "error_handler.h" +#include "exception.h" +#include "vector.h" + +#undef ETL_FILE +#define ETL_FILE "32" + +namespace etl +{ + //*************************************************************************** + ///\ingroup reference_flat_set + /// Exception base for flat_sets + //*************************************************************************** + class flat_set_exception : public exception + { + public: + + flat_set_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup reference_flat_set + /// Vector full exception. + //*************************************************************************** + class flat_set_full : public flat_set_exception + { + public: + + flat_set_full(string_type file_name_, numeric_type line_number_) + : flat_set_exception(ETL_ERROR_TEXT("flat_set:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup reference_flat_set + /// Vector iterator exception. + //*************************************************************************** + class flat_set_iterator : public flat_set_exception + { + public: + + flat_set_iterator(string_type file_name_, numeric_type line_number_) + : flat_set_exception(ETL_ERROR_TEXT("flat_set:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized reference_flat_sets. + /// Can be used as a reference type for all reference_flat_sets containing a specific type. + ///\ingroup reference_flat_set + //*************************************************************************** + template <typename T, typename TKeyCompare = std::less<T> > + class ireference_flat_set + { + public: + + typedef T key_type; + typedef T value_type; + typedef TKeyCompare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + protected: + + typedef etl::ivector<value_type*> lookup_t; + + public: + + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type> + { + public: + + friend class ireference_flat_set; + + iterator() + { + } + + iterator(typename lookup_t::iterator ilookup_) + : ilookup(ilookup_) + { + } + + iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + iterator& operator ++() + { + ++ilookup; + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + ++ilookup; + return temp; + } + + iterator& operator --() + { + --ilookup; + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + --ilookup; + return temp; + } + + reference operator *() + { + return *(*ilookup); + } + + const_reference operator *() const + { + return *(*ilookup); + } + + pointer operator &() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator &() const + { + return &(*(*ilookup)); + } + + pointer operator ->() + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::iterator ilookup; + }; + + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> + { + public: + + friend class ireference_flat_set; + + const_iterator() + { + } + + const_iterator(typename lookup_t::const_iterator ilookup_) + : ilookup(ilookup_) + { + } + + const_iterator(const iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator(const const_iterator& other) + : ilookup(other.ilookup) + { + } + + const_iterator& operator =(const iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator =(const const_iterator& other) + { + ilookup = other.ilookup; + return *this; + } + + const_iterator& operator ++() + { + ++ilookup; + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + ++ilookup; + return temp; + } + + const_iterator& operator --() + { + --ilookup; + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + --ilookup; + return temp; + } + + const_reference operator *() const + { + return *(*ilookup); + } + + const_pointer operator &() const + { + return etl::addressof(*(*ilookup)); + } + + const_pointer operator ->() const + { + return etl::addressof(*(*ilookup)); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.ilookup == rhs.ilookup; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + typename lookup_t::const_iterator ilookup; + }; + + protected: + + typedef typename etl::parameter_type<T>::type parameter_t; + + public: + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the reference_flat_set. + ///\return An iterator to the beginning of the reference_flat_set. + //********************************************************************* + iterator begin() + { + return iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the reference_flat_set. + ///\return A const iterator to the beginning of the reference_flat_set. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(lookup.begin()); + } + + //********************************************************************* + /// Returns an iterator to the end of the reference_flat_set. + ///\return An iterator to the end of the reference_flat_set. + //********************************************************************* + iterator end() + { + return iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the reference_flat_set. + ///\return A const iterator to the end of the reference_flat_set. + //********************************************************************* + const_iterator end() const + { + return const_iterator(lookup.end()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the reference_flat_set. + ///\return A const iterator to the beginning of the reference_flat_set. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(lookup.cbegin()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the reference_flat_set. + ///\return A const iterator to the end of the reference_flat_set. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(lookup.cend()); + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the reference_flat_set. + ///\return Iterator to the reverse beginning of the reference_flat_set. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the reference_flat_set. + ///\return Const iterator to the reverse beginning of the reference_flat_set. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(lookup.rbegin()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the reference_flat_set. + ///\return Reverse iterator to the end + 1 of the reference_flat_set. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the reference_flat_set. + ///\return Const reverse iterator to the end + 1 of the reference_flat_set. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(lookup.rend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the reference_flat_set. + ///\return Const reverse iterator to the reverse beginning of the reference_flat_set. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(lookup.crbegin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the reference_flat_set. + ///\return Const reverse iterator to the end + 1 of the reference_flat_set. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(lookup.crend()); + } + + //********************************************************************* + /// Assigns values to the reference_flat_set. + /// If asserts or exceptions are enabled, emits reference_flat_set_full if the reference_flat_set does not have enough free space. + /// If asserts or exceptions are enabled, emits reference_flat_set_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(d <= difference_type(capacity()), ETL_ERROR(flat_set_full)); +#endif + + clear(); + + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Inserts a value to the reference_flat_set. + /// If asserts or exceptions are enabled, emits reference_flat_set_full if the reference_flat_set is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(reference value) + { + iterator i_element = lower_bound(value); + + return insert_at(i_element, value); + } + + //********************************************************************* + /// Inserts a value to the reference_flat_set. + /// If asserts or exceptions are enabled, emits reference_flat_set_full if the reference_flat_set is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, reference value) + { + return insert(value).first; + } + + //********************************************************************* + /// Inserts a range of values to the reference_flat_set. + /// If asserts or exceptions are enabled, emits reference_flat_set_full if the reference_flat_set does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(parameter_t key) + { + iterator i_element = find(key); + + if (i_element == end()) + { + return 0; + } + else + { + lookup.erase(i_element.ilookup); + return 1; + } + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + //********************************************************************* + void erase(iterator i_element) + { + lookup.erase(i_element.ilookup); + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + void erase(iterator first, iterator last) + { + lookup.erase(first.ilookup, last.ilookup);; + } + + //************************************************************************* + /// Clears the reference_flat_set. + //************************************************************************* + void clear() + { + erase(begin(), end()); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(parameter_t key) + { + iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare()); + + if (itr != end()) + { + if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(parameter_t key) const + { + const_iterator itr = std::lower_bound(begin(), end(), key, TKeyCompare()); + + if (itr != end()) + { + if (!key_compare()(*itr, key) && !key_compare()(key, *itr)) + { + return itr; + } + else + { + return end(); + } + } + + return end(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(parameter_t key) const + { + return (find(key) == end()) ? 0 : 1; + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator lower_bound(parameter_t key) + { + return std::lower_bound(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the lower bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator lower_bound(parameter_t key) const + { + return std::lower_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + iterator upper_bound(parameter_t key) + { + return std::upper_bound(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the upper bound of a key + ///\param key The key to search for. + ///\return An iterator. + //********************************************************************* + const_iterator upper_bound(parameter_t key) const + { + return std::upper_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<iterator, iterator> equal_range(parameter_t key) + { + return std::equal_range(begin(), end(), key, TKeyCompare()); + } + + //********************************************************************* + /// Finds the range of equal elements of a key + ///\param key The key to search for. + ///\return An iterator pair. + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(parameter_t key) const + { + return std::upper_bound(cbegin(), cend(), key, TKeyCompare()); + } + + //************************************************************************* + /// Gets the current size of the reference_flat_set. + ///\return The current size of the reference_flat_set. + //************************************************************************* + size_type size() const + { + return lookup.size(); + } + + //************************************************************************* + /// Checks the 'empty' state of the reference_flat_set. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return lookup.empty(); + } + + //************************************************************************* + /// Checks the 'full' state of the reference_flat_set. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return lookup.full(); + } + + //************************************************************************* + /// Returns the capacity of the reference_flat_set. + ///\return The capacity of the reference_flat_set. + //************************************************************************* + size_type capacity() const + { + return lookup.capacity(); + } + + //************************************************************************* + /// Returns the maximum possible size of the reference_flat_set. + ///\return The maximum size of the reference_flat_set. + //************************************************************************* + size_type max_size() const + { + return lookup.max_size(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return lookup.available(); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + ireference_flat_set(lookup_t& lookup_) + : lookup(lookup_) + { + } + + //********************************************************************* + /// Inserts a value to the reference_flat_set. + ///\param i_element The place to insert. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert_at(iterator i_element, reference value) + { + std::pair<iterator, bool> result(end(), false); + + if (i_element == end()) + { + // At the end. + ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_set_full)); + + lookup.push_back(&value); + result.first = --end(); + result.second = true; + } + else + { + // Not at the end. + result.first = i_element; + + // Existing element? + if (value != *i_element) + { + // A new one. + ETL_ASSERT(!lookup.full(), ETL_ERROR(flat_set_full)); + lookup.insert(i_element.ilookup, &value); + result.second = true; + } + } + + return result; + } + + private: + + // Disable copy construction. + ireference_flat_set(const ireference_flat_set&); + ireference_flat_set& operator =(const ireference_flat_set&); + + lookup_t& lookup; + }; + + //*************************************************************************** + /// An reference flat set + ///\ingroup reference_flat_set + //*************************************************************************** + template <typename TKey, const size_t MAX_SIZE_, typename TKeyCompare = std::less<TKey> > + class reference_flat_set : public ireference_flat_set<TKey, TKeyCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + reference_flat_set() + : ireference_flat_set<TKey, TKeyCompare>(lookup) + { + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + reference_flat_set(const reference_flat_set& other) + : ireference_flat_set<TKey, TKeyCompare>(lookup) + { + ireference_flat_set<TKey, TKeyCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + reference_flat_set(TIterator first, TIterator last) + : ireference_flat_set<TKey, TKeyCompare>(lookup) + { + ireference_flat_set<TKey, TKeyCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~reference_flat_set() + { + ireference_flat_set<TKey, TKeyCompare>::clear(); + } + + private: + + typedef TKey value_type; + + // The vector that stores pointers to the nodes. + etl::vector<value_type*, MAX_SIZE> lookup; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first reference_flat_set. + ///\param rhs Reference to the second reference_flat_set. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup reference_flat_set + //*************************************************************************** + template <typename T, typename TKeyCompare> + bool operator ==(const etl::ireference_flat_set<T, TKeyCompare>& lhs, const etl::ireference_flat_set<T, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first reference_flat_set. + ///\param rhs Reference to the second reference_flat_set. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup reference_flat_set + //*************************************************************************** + template <typename T, typename TKeyCompare> + bool operator !=(const etl::ireference_flat_set<T, TKeyCompare>& lhs, const etl::ireference_flat_set<T, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } +} + +#undef ETL_FILE +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scheduler.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,412 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_SCHEDULER__ +#define __ETL_SCHEDULER__ + +#include <stdint.h> + +#include "platform.h" +#include "vector.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "task.h" +#include "type_traits.h" +#include "function.h" + +#undef ETL_FILE +#define ETL_FILE "36" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for scheduler. + //*************************************************************************** + class scheduler_exception : public etl::exception + { + public: + + scheduler_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// 'No tasks' exception. + //*************************************************************************** + class scheduler_no_tasks_exception : public etl::scheduler_exception + { + public: + + scheduler_no_tasks_exception(string_type file_name_, numeric_type line_number_) + : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:no tasks", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// 'Null tasks' exception. + //*************************************************************************** + class scheduler_null_task_exception : public etl::scheduler_exception + { + public: + + scheduler_null_task_exception(string_type file_name_, numeric_type line_number_) + : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:null task", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// 'Too many tasks' exception. + //*************************************************************************** + class scheduler_too_many_tasks_exception : public etl::scheduler_exception + { + public: + + scheduler_too_many_tasks_exception(string_type file_name_, numeric_type line_number_) + : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:too many tasks", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Sequencial Single. + /// A policy the scheduler can use to decide what to do next. + /// Only calls the task to process work once, if it has work to do. + //*************************************************************************** + struct scheduler_policy_sequencial_single + { + bool schedule_tasks(etl::ivector<etl::task*>& task_list) + { + bool idle = true; + + for (size_t index = 0; index < task_list.size(); ++index) + { + etl::task& task = *(task_list[index]); + + if (task.task_request_work() > 0) + { + task.task_process_work(); + idle = false; + } + } + + return idle; + } + }; + + //*************************************************************************** + /// Sequencial Multiple. + /// A policy the scheduler can use to decide what to do next. + /// Calls the task to process work until it reports that it has no more. + //*************************************************************************** + struct scheduler_policy_sequencial_multiple + { + bool schedule_tasks(etl::ivector<etl::task*>& task_list) + { + bool idle = true; + + for (size_t index = 0; index < task_list.size(); ++index) + { + etl::task& task = *(task_list[index]); + + while (task.task_request_work() > 0) + { + task.task_process_work(); + idle = false; + } + } + + return idle; + } + }; + + //*************************************************************************** + /// Highest Priority. + /// A policy the scheduler can use to decide what to do next. + /// Calls the highest priority task that has work. + //*************************************************************************** + struct scheduler_policy_highest_priority + { + bool schedule_tasks(etl::ivector<etl::task*>& task_list) + { + bool idle = true; + + size_t index = 0; + while (index < task_list.size()) + { + etl::task& task = *(task_list[index]); + + if (task.task_request_work() > 0) + { + task.task_process_work(); + idle = false; + break; + } + else + { + ++index; + } + } + + return idle; + } + }; + + //*************************************************************************** + /// Most Work. + /// A policy the scheduler can use to decide what to do next. + /// Calls the task that has the most work. + /// Starts looking from the task with the highest priority. + //*************************************************************************** + struct scheduler_policy_most_work + { + bool schedule_tasks(etl::ivector<etl::task*>& task_list) + { + bool idle = true; + + size_t most_index = 0; + uint_least8_t most_work = 0; + + for (size_t index = 0; index < task_list.size(); ++index) + { + etl::task& task = *(task_list[index]); + + uint_least8_t n_work = task.task_request_work(); + + if (n_work > most_work) + { + most_index = index; + most_work = n_work; + idle = false; + } + } + + if (!idle) + { + task_list[most_index]->task_process_work(); + } + + return idle; + } + }; + + //*************************************************************************** + /// Scheduler base. + //*************************************************************************** + class ischeduler + { + public: + + //******************************************* + // Virtuals. + //******************************************* + virtual void start() = 0; + + virtual ~ischeduler() + { + } + + //******************************************* + /// Set the idle callback. + //******************************************* + void set_idle_callback(etl::ifunction<void>& callback) + { + p_idle_callback = &callback; + } + + //******************************************* + /// Set the watchdog callback. + //******************************************* + void set_watchdog_callback(etl::ifunction<void>& callback) + { + p_watchdog_callback = &callback; + } + + //******************************************* + /// Set the running state for the scheduler. + //******************************************* + void set_scheduler_running(bool scheduler_running_) + { + scheduler_running = scheduler_running_; + } + + //******************************************* + /// Get the running state for the scheduler. + //******************************************* + bool scheduler_is_running() const + { + return scheduler_running; + } + + //******************************************* + /// Force the scheduler to exit. + //******************************************* + void exit_scheduler() + { + scheduler_exit = true; + } + + //******************************************* + /// Add a task. + /// Add to the task list in priority order. + //******************************************* + void add_task(etl::task& task) + { + ETL_ASSERT(!task_list.full(), ETL_ERROR(etl::scheduler_too_many_tasks_exception)) + + if (!task_list.full()) + { + typename task_list_t::iterator itask = std::upper_bound(task_list.begin(), + task_list.end(), + task.get_task_priority(), + compare_priority()); + + task_list.insert(itask, &task); + } + } + + //******************************************* + /// Add a task list. + /// Adds to the tasks to the internal task list in priority order. + /// Input order is ignored. + //******************************************* + template <typename TSize> + void add_task_list(etl::task** p_tasks, TSize size) + { + for (TSize i = 0; i < size; ++i) + { + ETL_ASSERT((p_tasks[i] != std::nullptr), ETL_ERROR(etl::scheduler_null_task_exception)); + add_task(*(p_tasks[i])); + } + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ischeduler(etl::ivector<etl::task*>& task_list_) + : scheduler_running(false), + scheduler_exit(false), + p_idle_callback(std::nullptr), + p_watchdog_callback(std::nullptr), + task_list(task_list_) + { + } + + bool scheduler_running; + bool scheduler_exit; + etl::ifunction<void>* p_idle_callback; + etl::ifunction<void>* p_watchdog_callback; + + private: + + //******************************************* + // Used to order tasks in descending priority. + //******************************************* + struct compare_priority + { + bool operator()(etl::task* ptask, etl::task_priority_t priority) const + { + return ptask->get_task_priority() > priority; + } + + bool operator()(etl::task_priority_t priority, etl::task* ptask) const + { + return priority > ptask->get_task_priority(); + } + }; + + typedef etl::ivector<etl::task*> task_list_t; + task_list_t& task_list; + }; + + //*************************************************************************** + /// Scheduler. + //*************************************************************************** + template <typename TSchedulerPolicy, size_t MAX_TASKS_> + class scheduler : public etl::ischeduler, protected TSchedulerPolicy + { + public: + + enum + { + MAX_TASKS = MAX_TASKS_, + }; + + scheduler() + : ischeduler(task_list) + { + } + + //******************************************* + /// Start the scheduler. SEQUENCIAL_SINGLE + /// Only calls the task to process work once, if it has work to do. + //******************************************* + void start() + { + ETL_ASSERT(task_list.size() > 0, ETL_ERROR(etl::scheduler_no_tasks_exception)); + + const size_t task_list_size = task_list.size(); + + scheduler_running = true; + + while (!scheduler_exit) + { + if (scheduler_running) + { + bool idle = TSchedulerPolicy::schedule_tasks(task_list); + + if (p_watchdog_callback) + { + (*p_watchdog_callback)(); + } + + if (idle && p_idle_callback) + { + (*p_idle_callback)(); + } + } + } + } + + private: + + typedef etl::vector<etl::task*, MAX_TASKS> task_list_t; + task_list_t task_list; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/set.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,2082 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove, rlindeman + +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_SET__ +#define __ETL_SET__ + +#include <stddef.h> +#include <iterator> +#include <algorithm> +#include <functional> + +#include "platform.h" +#include "container.h" +#include "pool.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "nullptr.h" +#include "type_traits.h" +#include "parameter_type.h" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#endif + +#undef ETL_FILE +#define ETL_FILE "14" + +//***************************************************************************** +///\defgroup set set +/// A set with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the set. + ///\ingroup set + //*************************************************************************** + class set_exception : public etl::exception + { + public: + + set_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the set. + ///\ingroup set + //*************************************************************************** + class set_full : public etl::set_exception + { + public: + + set_full(string_type file_name_, numeric_type line_number_) + : etl::set_exception(ETL_ERROR_TEXT("set:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Map out of bounds exception. + ///\ingroup set + //*************************************************************************** + class set_out_of_bounds : public etl::set_exception + { + public: + + set_out_of_bounds(string_type file_name_, numeric_type line_number_) + : etl::set_exception(ETL_ERROR_TEXT("set:bounds", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Iterator exception for the set. + ///\ingroup set + //*************************************************************************** + class set_iterator : public etl::set_exception + { + public: + + set_iterator(string_type file_name_, numeric_type line_number_) + : etl::set_exception(ETL_ERROR_TEXT("set:iterator problem", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for all sets. + ///\ingroup set + //*************************************************************************** + class set_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of set. + + //************************************************************************* + /// Gets the size of the set. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Gets the maximum possible size of the set. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + //************************************************************************* + /// Checks to see if the set is empty. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Checks to see if the set is full. + //************************************************************************* + bool full() const + { + return current_size == CAPACITY; + } + + //************************************************************************* + /// Returns the capacity of the vector. + ///\return The capacity of the vector. + //************************************************************************* + size_type capacity() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + enum + { + kLeft = 0, + kRight = 1, + kNeither = 2 + }; + + //************************************************************************* + /// The node element in the set. + //************************************************************************* + struct Node + { + //*********************************************************************** + /// Constructor + //*********************************************************************** + Node() : + weight(kNeither), + dir(kNeither) + { + } + + //*********************************************************************** + /// Marks the node as a leaf. + //*********************************************************************** + void mark_as_leaf() + { + weight = kNeither; + dir = kNeither; + children[0] =std::nullptr; + children[1] =std::nullptr; + } + + Node* children[2]; + uint_least8_t weight; + uint_least8_t dir; + }; + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + set_base(size_type max_size_) + : current_size(0) + , CAPACITY(max_size_) + , root_node(std::nullptr) + + { + } + + //************************************************************************* + /// Attach the provided node to the position provided + //************************************************************************* + void attach_node(Node*& position, Node& node) + { + // Mark new node as leaf on attach to tree at position provided + node.mark_as_leaf(); + + // Add the node here + position = &node; + + // One more. + ++current_size; + } + + //************************************************************************* + /// Detach the node at the position provided + //************************************************************************* + void detach_node(Node*& position, Node*& replacement) + { + // Make temporary copy of actual nodes involved because we might lose + // their references in the process (e.g. position is the same as + // replacement or replacement is a child of position) + Node* detached = position; + Node* swap = replacement; + + // Update current position to point to swap (replacement) node first + position = swap; + + // Update replacement node to point to child in opposite direction + // otherwise we might lose the other child of the swap node + replacement = swap->children[1 - swap->dir]; + + // Point swap node to detached node's children and weight + swap->children[kLeft] = detached->children[kLeft]; + swap->children[kRight] = detached->children[kRight]; + swap->weight = detached->weight; + } + + //************************************************************************* + /// Balance the critical node at the position provided as needed + //************************************************************************* + void balance_node(Node*& critical_node) + { + // Step 1: Update weights for all children of the critical node up to the + // newly inserted node. This step is costly (in terms of traversing nodes + // multiple times during insertion) but doesn't require as much recursion + Node* weight_node = critical_node->children[critical_node->dir]; + while (weight_node) + { + // Keep going until we reach a terminal node (dir == kNeither) + if (uint_least8_t(kNeither) != weight_node->dir) + { + // Does this insert balance the previous weight factor value? + if (weight_node->weight == 1 - weight_node->dir) + { + weight_node->weight = uint_least8_t(kNeither); + } + else + { + weight_node->weight = weight_node->dir; + } + + // Update weight factor node to point to next node + weight_node = weight_node->children[weight_node->dir]; + } + else + { + // Stop loop, terminal node found + break; + } + } // while(weight_node) + + // Step 2: Update weight for critical_node or rotate tree to balance node + if (uint_least8_t(kNeither) == critical_node->weight) + { + critical_node->weight = critical_node->dir; + } + // If direction is different than weight, then it will now be balanced + else if (critical_node->dir != critical_node->weight) + { + critical_node->weight = uint_least8_t(kNeither); + } + // Rotate is required to balance the tree at the critical node + else + { + // If critical node matches child node direction then perform a two + // node rotate in the direction of the critical node + if (critical_node->weight == critical_node->children[critical_node->dir]->dir) + { + rotate_2node(critical_node, critical_node->dir); + } + // Otherwise perform a three node rotation in the direction of the + // critical node + else + { + rotate_3node(critical_node, critical_node->dir, + critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir); + } + } + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + Node* find_limit_node(Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Find the node whose key would go before all the other keys from the + /// position provided + //************************************************************************* + const Node* find_limit_node(const Node* position, const int8_t dir) const + { + // Something at this position and in the direction specified? keep going + const Node* limit_node = position; + while (limit_node && limit_node->children[dir]) + { + limit_node = limit_node->children[dir]; + } + + // Return the limit node position found + return limit_node; + } + + //************************************************************************* + /// Rotate two nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_2node(Node*& position, uint_least8_t dir) + { + // A C A B + // B C -> A E OR B C -> D A + // D E B D D E E C + // C (new position) becomes the root + // A (position) takes ownership of D as its children[kRight] child + // C (new position) takes ownership of A as its left child + // OR + // B (new position) becomes the root + // A (position) takes ownership of E as its left child + // B (new position) takes ownership of A as its right child + + // Capture new root + Node* new_root = position->children[dir]; + // Replace position's previous child with new root's other child + position->children[dir] = new_root->children[1 - dir]; + // New root now becomes parent of current position + new_root->children[1 - dir] = position; + // Clear weight factor from current position + position->weight = uint_least8_t(kNeither); + // Newly detached right now becomes current position + position = new_root; + // Clear weight factor from new root + position->weight = uint_least8_t(kNeither); + } + + //************************************************************************* + /// Rotate three nodes at the position provided the to balance the tree + //************************************************************************* + void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third) + { + // __A__ __E__ __A__ __D__ + // _B_ C -> B A OR B _C_ -> A C + // D E D F G C D E B F G E + // F G F G + // E (new position) becomes the root + // B (position) takes ownership of F as its left child + // A takes ownership of G as its right child + // OR + // D (new position) becomes the root + // A (position) takes ownership of F as its right child + // C takes ownership of G as its left child + + // Capture new root (either E or D depending on dir) + Node* new_root = position->children[dir]->children[1 - dir]; + // Set weight factor for B or C based on F or G existing and being a different than dir + position->children[dir]->weight = third != uint_least8_t(kNeither) && third != dir ? dir : uint_least8_t(kNeither); + + // Detach new root from its tree (replace with new roots child) + position->children[dir]->children[1 - dir] = + new_root->children[dir]; + // Attach current left tree to new root + new_root->children[dir] = position->children[dir]; + // Set weight factor for A based on F or G + position->weight = third != uint_least8_t(kNeither) && third == dir ? 1 - dir : uint_least8_t(kNeither); + + // Move new root's right tree to current roots left tree + position->children[dir] = new_root->children[1 - dir]; + // Attach current root to new roots right tree + new_root->children[1 - dir] = position; + // Replace current position with new root + position = new_root; + // Clear weight factor for new current position + position->weight = uint_least8_t(kNeither); + } + + size_type current_size; ///< The number of the used nodes. + const size_type CAPACITY; ///< The maximum size of the set. + Node* root_node; ///< The node that acts as the set root. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// A templated base for all etl::set types. + ///\ingroup set + //*************************************************************************** + template <typename T, typename TCompare> + class iset : public etl::set_base + { + public: + + typedef const T key_type; + typedef const T value_type; + typedef TCompare key_compare; + typedef TCompare value_compare; + typedef value_type& const_reference; + typedef value_type* const_pointer; + typedef size_t size_type; + + //************************************************************************* + /// How to compare two key elements. + //************************************************************************* + struct key_comp + { + bool operator ()(key_type& key1, key_type& key2) const + { + return key_compare()(key1, key2); + } + }; + + //************************************************************************* + /// How to compare two value elements. + //************************************************************************* + struct value_comp + { + bool operator ()(value_type& value1, value_type& value2) const + { + return value_compare()(value1, value2); + } + }; + + protected: + + //************************************************************************* + /// The data node element in the set. + //************************************************************************* + struct Data_Node : public Node + { + explicit Data_Node(value_type value_) + : value(value_) + { + } + + value_type value; + }; + + /// Defines the key value parameter type + typedef typename etl::parameter_type<T>::type key_parameter_t; + + //************************************************************************* + /// How to compare node elements. + //************************************************************************* + bool node_comp(const Data_Node& node1, const Data_Node& node2) const + { + return key_compare()(node1.value, node2.value); + } + + bool node_comp(const Data_Node& node, key_parameter_t key) const + { + return key_compare()(node.value, key); + } + bool node_comp(key_parameter_t key, const Data_Node& node) const + + { + return key_compare()(key, node.value); + } + + private: + + /// The pool of data nodes used in the set. + etl::ipool* p_node_pool; + + //************************************************************************* + /// Downcast a Node* to a Data_Node* + //************************************************************************* + static Data_Node* data_cast(Node* p_node) + { + return static_cast<Data_Node*>(p_node); + } + + //************************************************************************* + /// Downcast a Node& to a Data_Node& + //************************************************************************* + static Data_Node& data_cast(Node& node) + { + return static_cast<Data_Node&>(node); + } + + //************************************************************************* + /// Downcast a const Node* to a const Data_Node* + //************************************************************************* + static const Data_Node* data_cast(const Node* p_node) + { + return static_cast<const Data_Node*>(p_node); + } + + //************************************************************************* + /// Downcast a const Node& to a const Data_Node& + //************************************************************************* + static const Data_Node& data_cast(const Node& node) + { + return static_cast<const Data_Node&>(node); + } + + public: + //************************************************************************* + /// iterator. + //************************************************************************* + class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type> + { + public: + + friend class iset; + + iterator() + : p_set(std::nullptr) + , p_node(std::nullptr) + { + } + + iterator(iset& set) + : p_set(&set) + , p_node(std::nullptr) + { + } + + iterator(iset& set, Node* node) + : p_set(&set) + , p_node(node) + { + } + + iterator(const iterator& other) + : p_set(other.p_set) + , p_node(other.p_node) + { + } + + ~iterator() + { + } + + iterator& operator ++() + { + p_set->next_node(p_node); + return *this; + } + + iterator operator ++(int) + { + iterator temp(*this); + p_set->next_node(p_node); + return temp; + } + + iterator& operator --() + { + p_set->prev_node(p_node); + return *this; + } + + iterator operator --(int) + { + iterator temp(*this); + p_set->prev_node(p_node); + return temp; + } + + iterator operator =(const iterator& other) + { + p_set = other.p_set; + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return iset::data_cast(p_node)->value; + } + + const_pointer operator &() const + { + return &(iset::data_cast(p_node)->value); + } + + const_pointer operator ->() const + { + return &(iset::data_cast(p_node)->value); + } + + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.p_set == rhs.p_set && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + // Pointer to set associated with this iterator + iset* p_set; + + // Pointer to the current node for this iterator + Node* p_node; + }; + friend class iterator; + + //************************************************************************* + /// const_iterator + //************************************************************************* + class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type> + { + public: + + friend class iset; + + const_iterator() + : p_set(nullptr) + , p_node(nullptr) + { + } + + const_iterator(const iset& set) + : p_set(&set) + , p_node(nullptr) + { + } + + const_iterator(const iset& set, const Node* node) + : p_set(&set) + , p_node(node) + { + } + + const_iterator(const typename iset::iterator& other) + : p_set(other.p_set) + , p_node(other.p_node) + { + } + + const_iterator(const const_iterator& other) + : p_set(other.p_set) + , p_node(other.p_node) + { + } + + ~const_iterator() + { + } + + const_iterator& operator ++() + { + p_set->next_node(p_node); + return *this; + } + + const_iterator operator ++(int) + { + const_iterator temp(*this); + p_set->next_node(p_node); + return temp; + } + + const_iterator& operator --() + { + p_set->prev_node(p_node); + return *this; + } + + const_iterator operator --(int) + { + const_iterator temp(*this); + p_set->prev_node(p_node); + return temp; + } + + const_iterator operator =(const const_iterator& other) + { + p_set = other.p_set; + p_node = other.p_node; + return *this; + } + + const_reference operator *() const + { + return iset::data_cast(p_node)->value; + } + + const_pointer operator &() const + { + return iset::data_cast(p_node)->value; + } + + const_pointer operator ->() const + { + return &(iset::data_cast(p_node)->value); + } + + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.p_set == rhs.p_set && lhs.p_node == rhs.p_node; + } + + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + // Pointer to set associated with this iterator + const iset* p_set; + + // Pointer to the current node for this iterator + const Node* p_node; + }; + friend class const_iterator; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iset& operator = (const iset& rhs) + { + if (this != &rhs) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Gets the beginning of the set. + //************************************************************************* + iterator begin() + { + return iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the beginning of the set. + //************************************************************************* + const_iterator begin() const + { + return const_iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the end of the set. + //************************************************************************* + iterator end() + { + return iterator(*this); + } + + //************************************************************************* + /// Gets the end of the set. + //************************************************************************* + const_iterator end() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the beginning of the set. + //************************************************************************* + const_iterator cbegin() const + { + return const_iterator(*this, find_limit_node(root_node, kLeft)); + } + + //************************************************************************* + /// Gets the end of the set. + //************************************************************************* + const_iterator cend() const + { + return const_iterator(*this); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft))); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft))); + } + + //************************************************************************* + /// Gets the reverse beginning of the list. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(const_iterator(*this)); + } + + //************************************************************************* + /// Gets the reverse end of the list. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft))); + } + + //********************************************************************* + /// Assigns values to the set. + /// If asserts or exceptions are enabled, emits set_full if the set does not have enough free space. + /// If asserts or exceptions are enabled, emits set_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { + initialise(); + insert(first, last); + } + + //************************************************************************* + /// Clears the set. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Counts the number of elements that contain the key specified. + ///\param key The key to search for. + ///\return 1 if element was found, 0 otherwise. + //********************************************************************* + size_type count(key_parameter_t key) const + { + return find_node(root_node, key) ? 1 : 0; + } + + //************************************************************************* + /// Returns two iterators with bounding (lower bound, upper bound) the + /// value provided + //************************************************************************* + std::pair<iterator, iterator> equal_range(const value_type& value) + { + return std::make_pair<iterator, iterator>( + iterator(*this, find_lower_node(root_node, value)), + iterator(*this, find_upper_node(root_node, value))); + } + + //************************************************************************* + /// Returns two const iterators with bounding (lower bound, upper bound) + /// the value provided. + //************************************************************************* + std::pair<const_iterator, const_iterator> equal_range(const value_type& value) const + { + return std::make_pair<const_iterator, const_iterator>( + const_iterator(*this, find_lower_node(root_node, value)), + const_iterator(*this, find_upper_node(root_node, value))); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + void erase(iterator position) + { + // Remove the node by its key + erase((*position)); + } + + //************************************************************************* + /// Erases the value at the specified position. + //************************************************************************* + iterator erase(const_iterator position) + { + // Find the parent node to be removed + Node*& reference_node = find_node(root_node, position.p_node); + iterator next(*this, reference_node); + ++next; + + remove_node(root_node, (*position)); + + return next; + } + + //************************************************************************* + // Erase the key specified. + //************************************************************************* + size_type erase(key_parameter_t key_value) + { + // Return 1 if key value was found and removed + return remove_node(root_node, key_value) ? 1 : 0; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(iterator first, iterator last) + { + iterator next; + while (first != last) + { + next = erase(const_iterator(first++)); + } + + return next; + } + + //************************************************************************* + /// Erases a range of elements. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + iterator next; + while (first != last) + { + next = erase(first++); + } + + return next; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + iterator find(key_parameter_t key_value) + { + return iterator(*this, find_node(root_node, key_value)); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator pointing to the element or end() if not found. + //********************************************************************* + const_iterator find(key_parameter_t key_value) const + { + return const_iterator(*this, find_node(root_node, key_value)); + } + + //********************************************************************* + /// Inserts a value to the set. + /// If asserts or exceptions are enabled, emits set_full if the set is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(value_type& value) + { + // Default to no inserted node + Node* inserted_node =std::nullptr; + bool inserted = false; + + ETL_ASSERT(!full(), ETL_ERROR(set_full)); + + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might bestd::nullptr if node was a duplicate) + inserted_node = insert_node(root_node, node); + inserted = inserted_node == &node; + + // Insert node into tree and return iterator to new node location in tree + return std::make_pair(iterator(*this, inserted_node), inserted); + } + + //********************************************************************* + /// Inserts a value to the set starting at the position recommended. + /// If asserts or exceptions are enabled, emits set_full if the set is already full. + ///\param position The position that would precede the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator, value_type& value) + { + // Default to no inserted node + Node* inserted_node =std::nullptr; + + ETL_ASSERT(!full(), ETL_ERROR(set_full)); + + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might bestd::nullptr if node was a duplicate) + inserted_node = insert_node(root_node, node); + + // Insert node into tree and return iterator to new node location in tree + return iterator(*this, inserted_node); + } + + //********************************************************************* + /// Inserts a value to the set starting at the position recommended. + /// If asserts or exceptions are enabled, emits set_full if the set is already full. + ///\param position The position that would precede the value to insert. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator, value_type& value) + { + // Default to no inserted node + Node* inserted_node =std::nullptr; + + ETL_ASSERT(!full(), ETL_ERROR(set_full)); + + // Get next available free node + Data_Node& node = allocate_data_node(value); + + // Obtain the inserted node (might bestd::nullptr if node was a duplicate) + inserted_node = insert_node(root_node, node); + + // Insert node into tree and return iterator to new node location in tree + return iterator(*this, inserted_node); + } + + //********************************************************************* + /// Inserts a range of values to the set. + /// If asserts or exceptions are enabled, emits set_full if the set does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first, TIterator last) + { + while (first != last) + { + insert(*first++); + } + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go before the key provided or end() + /// if all keys are considered to go before the key provided. + ///\return An iterator pointing to the element not before key or end() + //********************************************************************* + iterator lower_bound(key_parameter_t key) + { + return iterator(*this, find_lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go before the key provided + /// or end() if all keys are considered to go before the key provided. + ///\return An const_iterator pointing to the element not before key or end() + //********************************************************************* + const_iterator lower_bound(key_parameter_t key) const + { + return const_iterator(*this, find_lower_node(root_node, key)); + } + + //********************************************************************* + /// Returns an iterator pointing to the first element in the container + /// whose key is not considered to go after the key provided or end() + /// if all keys are considered to go after the key provided. + ///\return An iterator pointing to the element after key or end() + //********************************************************************* + iterator upper_bound(key_parameter_t key) + { + return iterator(*this, find_upper_node(root_node, key)); + } + + //********************************************************************* + /// Returns a const_iterator pointing to the first element in the + /// container whose key is not considered to go after the key provided + /// or end() if all keys are considered to go after the key provided. + ///\return An const_iterator pointing to the element after key or end() + //********************************************************************* + const_iterator upper_bound(key_parameter_t key) const + { + return const_iterator(*this, find_upper_node(root_node, key)); + } + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + iset(etl::ipool& node_pool, size_t max_size_) + : etl::set_base(max_size_) + , p_node_pool(&node_pool) + { + } + + //************************************************************************* + /// Initialise the set. + //************************************************************************* + void initialise() + { + erase(begin(), end()); + } + + private: + + //************************************************************************* + /// Allocate a Data_Node. + //************************************************************************* + Data_Node& allocate_data_node(value_type value) + { + Data_Node& node = *p_node_pool->allocate<Data_Node>(); + ::new ((void*)&node.value) value_type(value); + ++construct_count; + return node; + } + + //************************************************************************* + /// Destroy a Data_Node. + //************************************************************************* + void destroy_data_node(Data_Node& node) + { + node.value.~value_type(); + p_node_pool->release(&node); + --construct_count; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + Node* find_node(Node* position, key_parameter_t key) + { + Node* found = position; + while (found) + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = iset::data_cast(*found); + + // Compare the node value to the current position value + if (node_comp(key, found_data_node)) + { + // Keep searching for the node on the left + found = found->children[kLeft]; + } + else if (node_comp(found_data_node, key)) + { + // Keep searching for the node on the right + found = found->children[kRight]; + } + else + { + // Node that matches the key provided was found, exit loop + break; + } + } + + // Return the node found (might bestd::nullptr) + return found; + } + + //************************************************************************* + /// Find the value matching the node provided + //************************************************************************* + const Node* find_node(const Node* position, key_parameter_t key) const + { + const Node* found = position; + while (found) + { + // Downcast found to Data_Node class for comparison and other operations + const Data_Node& found_data_node = iset::data_cast(*found); + + // Compare the node value to the current position value + if (node_comp(key, found_data_node)) + { + // Keep searching for the node on the left + found = found->children[kLeft]; + } + else if (node_comp(found_data_node, key)) + { + // Keep searching for the node on the right + found = found->children[kRight]; + } + else + { + // Node that matches the key provided was found, exit loop + break; + } + } + + // Return the node found (might bestd::nullptr) + return found; + } + + //************************************************************************* + /// Find the reference node matching the node provided + //************************************************************************* + Node*& find_node(Node*& position, const Node* node) + { + Node* found = position; + while (found) + { + if (found->children[kLeft] == node) + { + return found->children[kLeft]; + } + else if (found->children[kRight] == node) + { + return found->children[kRight]; + } + else + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = iset::data_cast(*found); + const Data_Node& data_node = iset::data_cast(*node); + + // Compare the node value to the current position value + if (node_comp(data_node, found_data_node)) + { + // Keep searching for the node on the left + found = found->children[kLeft]; + } + else if (node_comp(found_data_node, data_node)) + { + // Keep searching for the node on the right + found = found->children[kRight]; + } + else + { + // Return position provided (it matches the node) + return position; + } + } + } + + // Return root node if nothing was found + return root_node; + } + + //************************************************************************* + /// Find the parent node that contains the node provided in its left or + /// right tree + //************************************************************************* + Node* find_parent_node(Node* position, const Node* node) + { + // Default to no parent node found + Node* found =std::nullptr; + + // If the position provided is the same as the node then there is no parent + if (position && node && position != node) + { + while (position) + { + // Is this position not the parent of the node we are looking for? + if (position->children[kLeft] != node && + position->children[kRight] != node) + { + // Downcast node and position to Data_Node references for key comparisons + const Data_Node& node_data_node = iset::data_cast(*node); + Data_Node& position_data_node = iset::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(node_data_node, position_data_node)) + { + // Keep looking for parent on the left + position = position->children[kLeft]; + } + else if (node_comp(position_data_node, node_data_node)) + { + // Keep looking for parent on the right + position = position->children[kRight]; + } + } + else + { + // Return the current position as the parent node found + found = position; + + // Parent node found, exit loop + break; + } + } + } + + // Return the parent node found (might bestd::nullptr) + return found; + } + + //************************************************************************* + /// Find the parent node that contains the node provided in its left or + /// right tree + //************************************************************************* + const Node* find_parent_node(const Node* position, const Node* node) const + { + // Default to no parent node found + const Node* found =std::nullptr; + + // If the position provided is the same as the node then there is no parent + if (position && node && position != node) + { + while (position) + { + // Is this position not the parent of the node we are looking for? + if (position->children[kLeft] != node && + position->children[kRight] != node) + { + // Downcast node and position to Data_Node references for key comparisons + const Data_Node& node_data_node = iset::data_cast(*node); + const Data_Node& position_data_node = iset::data_cast(*position); + // Compare the node value to the current position value + if (node_comp(node_data_node, position_data_node)) + { + // Keep looking for parent on the left + position = position->children[kLeft]; + } + else if (node_comp(position_data_node, node_data_node)) + { + // Keep looking for parent on the right + position = position->children[kRight]; + } + } + else + { + // Return the current position as the parent node found + found = position; + + // Parent node found, exit loop + break; + } + } + } + + // Return the parent node found (might bestd::nullptr) + return found; + } + + //************************************************************************* + /// Find the node whose key is not considered to go before the key provided + //************************************************************************* + Node* find_lower_node(Node* position, key_parameter_t key) const + { + // Something at this position? keep going + Node* lower_node = position; + while (lower_node) + { + // Downcast lower node to Data_Node reference for key comparisons + Data_Node& data_node = iset::data_cast(*lower_node); + // Compare the key value to the current lower node key value + if (node_comp(key, data_node)) + { + if (lower_node->children[kLeft]) + { + lower_node = lower_node->children[kLeft]; + } + else + { + // Found lowest node + break; + } + } + else if (node_comp(data_node, key)) + { + lower_node = lower_node->children[kRight]; + } + else + { + // Found equal node + break; + } + } + + // Return the lower_node position found + return lower_node; + } + + //************************************************************************* + /// Find the node whose key is considered to go after the key provided + //************************************************************************* + Node* find_upper_node(Node* position, key_parameter_t key) const + { + // Keep track of parent of last upper node + Node* upper_node =std::nullptr; + // Start with position provided + Node* node = position; + while (node) + { + // Downcast position to Data_Node reference for key comparisons + Data_Node& data_node = iset::data_cast(*node); + // Compare the key value to the current upper node key value + if (node_comp(key, data_node)) + { + upper_node = node; + node = node->children[kLeft]; + } + else if (node_comp(data_node, key)) + { + node = node->children[kRight]; + } + else if (node->children[kRight]) + { + upper_node = find_limit_node(node->children[kRight], kLeft); + break; + } + else + { + break; + } + } + + // Return the upper node position found (might bestd::nullptr) + return upper_node; + } + + //************************************************************************* + /// Insert a node. + //************************************************************************* + Node* insert_node(Node*& position, Data_Node& node) + { + // Find the location where the node belongs + Node* found = position; + + // Was position provided not empty? then find where the node belongs + if (position) + { + // Find the critical parent node (default tostd::nullptr) + Node* critical_parent_node =std::nullptr; + Node* critical_node = root_node; + + while (found) + { + // Search for critical weight node (all nodes whose weight factor + // is set to kNeither (balanced) + if (kNeither != found->weight) + { + critical_node = found; + } + + // Downcast found to Data_Node class for comparison and other operations + Data_Node& found_data_node = iset::data_cast(*found); + + // Is the node provided to the left of the current position? + if (node_comp(node, found_data_node)) + { + // Update direction taken to insert new node in parent node + found->dir = kLeft; + } + // Is the node provided to the right of the current position? + else if (node_comp(found_data_node, node)) + { + // Update direction taken to insert new node in parent node + found->dir = kRight; + } + else + { + // Update direction taken to insert new node in parent node + found->dir = kNeither; + + // Clear critical node value to skip weight step below + critical_node =std::nullptr; + + // Destroy the node provided (its a duplicate) + destroy_data_node(node); + + // Exit loop, duplicate node found + break; + } + + // Is there a child of this parent node? + if (found->children[found->dir]) + { + // Will this node be the parent of the next critical node whose + // weight factor is set to kNeither (balanced)? + if (kNeither != found->children[found->dir]->weight) + { + critical_parent_node = found; + } + + // Keep looking for empty spot to insert new node + found = found->children[found->dir]; + } + else + { + // Attatch node to right + attach_node(found->children[found->dir], node); + + // Return newly added node + found = found->children[found->dir]; + + // Exit loop + break; + } + } + + // Was a critical node found that should be checked for balance? + if (critical_node) + { + if (critical_parent_node ==std::nullptr && critical_node == root_node) + { + balance_node(root_node); + } + else if (critical_parent_node ==std::nullptr && critical_node == position) + { + balance_node(position); + } + else + { + balance_node(critical_parent_node->children[critical_parent_node->dir]); + } + } + } + else + { + // Attatch node to current position + attach_node(position, node); + + // Return newly added node at current position + found = position; + } + + // Return the node found (might bestd::nullptr) + return found; + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(Node*&position) + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the next node in sequence from the node provided + //************************************************************************* + void next_node(const Node*& position) const + { + if (position) + { + // Is there a tree on the right? then find the minimum of that tree + if (position->children[kRight]) + { + // Return minimum node found + position = find_limit_node(position->children[kRight], kLeft); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = find_parent_node(root_node, position); + // Repeat while previous position was on right side of parent tree + } while (parent && parent->children[kRight] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(Node*&position) + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = find_parent_node(root_node, position); + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Find the previous node in sequence from the node provided + //************************************************************************* + void prev_node(const Node*& position) const + { + // If starting at the terminal end, the previous node is the maximum node + // from the root + if (!position) + { + position = find_limit_node(root_node, kRight); + } + else + { + // Is there a tree on the left? then find the maximum of that tree + if (position->children[kLeft]) + { + // Return maximum node found + position = find_limit_node(position->children[kLeft], kRight); + } + // Otherwise find the parent of this node + else + { + // Start with current position as parent + const Node* parent = position; + do { + // Update current position as previous parent + position = parent; + // Find parent of current position + parent = find_parent_node(root_node, position); + // Repeat while previous position was on left side of parent tree + } while (parent && parent->children[kLeft] == position); + + // Set parent node as the next position + position = parent; + } + } + } + + //************************************************************************* + /// Remove the node specified from somewhere starting at the position + /// provided + //************************************************************************* + Node* remove_node(Node*& position, key_parameter_t key) + { + // Step 1: Find the target node that matches the key provided, the + // replacement node (might be the same as target node), and the critical + // node to start rebalancing the tree from (up to the replacement node) + Node* found_parent =std::nullptr; + Node* found =std::nullptr; + Node* replace_parent =std::nullptr; + Node* replace = position; + Node* balance_parent =std::nullptr; + Node* balance = root_node; + while (replace) + { + // Downcast found to Data_Node class for comparison and other operations + Data_Node& replace_data_node = iset::data_cast(*replace); + + // Compare the key provided to the replace data node key + if (node_comp(key, replace_data_node)) + { + // Update the direction to the target/replace node + replace->dir = kLeft; + } + else if (node_comp(replace_data_node, key)) + { + // Update the direction to the target/replace node + replace->dir = kRight; + } + else + { + // Update the direction to the replace node (target node found here) + replace->dir = replace->children[kLeft] ? kLeft : kRight; + + // Note the target node was found (and its parent) + found_parent = replace_parent; + found = replace; + } + // Replacement node found if its missing a child in the replace->dir + // value set above + if (replace->children[replace->dir] ==std::nullptr) + { + // Exit loop once replace node is found (target might not have been) + break; + } + + // If replacement node weight is kNeither or we are taking the shorter + // path of replacement node and our sibling (on longer path) is + // balanced then we need to update the balance node to match this + // replacement node but all our ancestors will not require rebalancing + if ((replace->weight == kNeither) || + (replace->weight == (1 - replace->dir) && + replace->children[1 - replace->dir]->weight == kNeither)) + { + // Update balance node (and its parent) to replacement node + balance_parent = replace_parent; + balance = replace; + } + + // Keep searching for the replacement node + replace_parent = replace; + replace = replace->children[replace->dir]; + } + + // If target node was found, proceed with rebalancing and replacement + if (found) + { + // Step 2: Update weights from critical node to replacement parent node + while (balance) + { + if (balance->children[balance->dir] ==std::nullptr) + { + break; + } + + if (balance->weight == kNeither) + { + balance->weight = 1 - balance->dir; + } + else if (balance->weight == balance->dir) + { + balance->weight = kNeither; + } + else + { + int weight = balance->children[1 - balance->dir]->weight; + // Perform a 3 node rotation if weight is same as balance->dir + if (weight == balance->dir) + { + // Is the root node being rebalanced (no parent) + if (balance_parent ==std::nullptr) + { + rotate_3node(root_node, 1 - balance->dir, + balance->children[1 - balance->dir]->children[balance->dir]->weight); + } + else + { + rotate_3node(balance_parent->children[balance_parent->dir], 1 - balance->dir, + balance->children[1 - balance->dir]->children[balance->dir]->weight); + } + } + // Already balanced, rebalance and make it heavy in opposite + // direction of the node being removed + else if (weight == kNeither) + { + // Is the root node being rebalanced (no parent) + if (balance_parent ==std::nullptr) + { + rotate_2node(root_node, 1 - balance->dir); + root_node->weight = balance->dir; + } + else + { + rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir); + balance_parent->children[balance_parent->dir]->weight = balance->dir; + } + // Update balance node weight in opposite direction of node removed + balance->weight = 1 - balance->dir; + } + // Rebalance and leave it balanced + else + { + // Is the root node being rebalanced (no parent) + if (balance_parent ==std::nullptr) + { + rotate_2node(root_node, 1 - balance->dir); + } + else + { + rotate_2node(balance_parent->children[balance_parent->dir], 1 - balance->dir); + } + } + + // Is balance node the same as the target node found? then update + // its parent after the rotation performed above + if (balance == found) + { + if (balance_parent) + { + found_parent = balance_parent->children[balance_parent->dir]; + // Update dir since it is likely stale + found_parent->dir = found_parent->children[kLeft] == found ? kLeft : kRight; + } + else + { + found_parent = root_node; + root_node->dir = root_node->children[kLeft] == found ? kLeft : kRight; + } + } + } + + // Next balance node to consider + balance_parent = balance; + balance = balance->children[balance->dir]; + } // while(balance) + + // Step 3: Swap found node with replacement node + if (found_parent) + { + // Handle traditional case + detach_node(found_parent->children[found_parent->dir], + replace_parent->children[replace_parent->dir]); + } + // Handle root node removal + else + { + // Valid replacement node for root node being removed? + if (replace_parent) + { + detach_node(root_node, replace_parent->children[replace_parent->dir]); + } + else + { + // Target node and replacement node are both root node + detach_node(root_node, root_node); + } + } + + // Downcast found into data node + Data_Node& found_data_node = iset::data_cast(*found); + + // One less. + --current_size; + + // Destroy the node removed + destroy_data_node(found_data_node); + } // if(found) + + // Return node found (might bestd::nullptr) + return found; + } + + // Disable copy construction. + iset(const iset&); + }; + + //************************************************************************* + /// A templated set implementation that uses a fixed size buffer. + //************************************************************************* + template <typename T, const size_t MAX_SIZE_, typename TCompare = std::less<T> > + class set : public etl::iset<T, TCompare> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + set() + : etl::iset<T, TCompare>(node_pool, MAX_SIZE) + { + etl::iset<T, TCompare>::initialise(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + set(const set& other) + : etl::iset<T, TCompare>(node_pool, MAX_SIZE) + { + etl::iset<T, TCompare>::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + set(TIterator first, TIterator last) + : etl::iset<T, TCompare>(node_pool, MAX_SIZE) + { + etl::iset<T, TCompare>::assign(first, last); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~set() + { + etl::iset<T, TCompare>::initialise(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + set& operator = (const set& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + etl::iset<T, TCompare>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of data nodes used for the set. + etl::pool<typename etl::iset<T, TCompare>::Data_Node, MAX_SIZE> node_pool; + }; +} + +//*************************************************************************** +/// Equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> +///\ingroup lookup +//*************************************************************************** +template <typename T, typename TCompare> +bool operator ==(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs) +{ + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +//*************************************************************************** +/// Not equal operator. +///\param lhs Reference to the first lookup. +///\param rhs Reference to the second lookup. +///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> +///\ingroup lookup +//*************************************************************************** +template <typename T, typename TCompare> +bool operator !=(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs) +{ + return !(lhs == rhs); +} + +//************************************************************************* +/// Less than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename T, typename TCompare> +bool operator <(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs) +{ + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); +} + +//************************************************************************* +/// Greater than operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than the +/// second, otherwise <b>false</b>. +//************************************************************************* +template <typename T, typename TCompare> +bool operator >(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs) +{ + return (rhs < lhs); +} + +//************************************************************************* +/// Less than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically less than or equal +/// to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename T, typename TCompare> +bool operator <=(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs) +{ + return !(lhs > rhs); +} + +//************************************************************************* +/// Greater than or equal operator. +///\param lhs Reference to the first list. +///\param rhs Reference to the second list. +///\return <b>true</b> if the first list is lexicographically greater than or +/// equal to the second, otherwise <b>false</b>. +//************************************************************************* +template <typename T, typename TCompare> +bool operator >=(const etl::iset<T, TCompare>& lhs, const etl::iset<T, TCompare>& rhs) +{ + return !(lhs < rhs); +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/smallest.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,342 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -osmallest.h -DNTypes=<n> smallest_generator.h +// Where <n> is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_SMALLEST__ +#define __ETL_SMALLEST__ + +#include <stdint.h> + +#include "platform.h" +#include "integral_limits.h" + +///\defgroup smallest smallest +///\ingroup utilities + +namespace etl +{ + /* 7.18.2.1 Limits of exact-width integer types */ + #define INT8_MIN (-128) + #define INT16_MIN (-32768) + #define INT32_MIN (-2147483647 - 1) + #define INT64_MIN (-9223372036854775807LL - 1) + + #define INT8_MAX 127 + #define INT16_MAX 32767 + #define INT32_MAX 2147483647 + #define INT64_MAX 9223372036854775807LL + + + #define UINT8_MAX 0xff /* 255U */ + #define UINT16_MAX 0xffff /* 65535U */ + #define UINT32_MAX 0xffffffff /* 4294967295U */ + #define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ + + /* 7.18.2.2 Limits of minimum-width integer types */ + #define INT_LEAST8_MIN INT8_MIN + #define INT_LEAST16_MIN INT16_MIN + #define INT_LEAST32_MIN INT32_MIN + #define INT_LEAST64_MIN INT64_MIN + + #define INT_LEAST8_MAX INT8_MAX + #define INT_LEAST16_MAX INT16_MAX + #define INT_LEAST32_MAX INT32_MAX + #define INT_LEAST64_MAX INT64_MAX + + #define UINT_LEAST8_MAX UINT8_MAX + #define UINT_LEAST16_MAX UINT16_MAX + #define UINT_LEAST32_MAX UINT32_MAX + #define UINT_LEAST64_MAX UINT64_MAX + + + //*************************************************************************** + /// Template to determine the smallest type and size. + /// Supports up to 16 types. + /// Defines 'value_type' which is the type of the smallest parameter. + /// Defines 'size' which is the size of the smallest parameter. + ///\ingroup smallest + //*************************************************************************** + template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void> + struct smallest_type + { + private: + + // Declaration. + template <const bool Boolean, typename TrueType, typename FalseType> + struct choose_type; + + // Specialisation for 'true'. + // Defines 'type' as 'TrueType'. + template <typename TrueType, typename FalseType> + struct choose_type<true, TrueType, FalseType> + { + typedef TrueType type; + }; + + // Specialisation for 'false'. + // Defines 'type' as 'FalseType'. + template <typename TrueType, typename FalseType> + struct choose_type<false, TrueType, FalseType> + { + typedef FalseType type; + }; + + public: + + // Define 'smallest_other' as 'smallest_type' with all but the first parameter. + typedef typename smallest_type<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::type smallest_other; + + // Set 'type' to be the smallest of the first parameter and any of the others. + // This is recursive. + typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)), // Boolean + T1, // TrueType + smallest_other> // FalseType + ::type type; // The smallest type of the two. + + // The size of the smallest type. + enum + { + size = sizeof(type) + }; + }; + + //*************************************************************************** + // Specialisation for one template parameter. + //*************************************************************************** + template <typename T1> + struct smallest_type<T1, void, void, void, void, void, void, void, + void, void, void, void, void, void, void, void> + { + typedef T1 type; + + enum + { + size = sizeof(type) + }; + }; + + namespace __private_smallest__ + { + //************************************************************************* + // Determine the type to hold the number of bits based on the index. + //************************************************************************* + template <const int index> + struct best_fit_uint_type; + + //************************************************************************* + // Less than or equal to 8 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<0> + { + typedef uint_least8_t type; + }; + + //************************************************************************* + // 9 to 16 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<1> + { + typedef uint_least16_t type; + }; + + //************************************************************************* + // 17 to 31 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<2> + { + typedef uint_least32_t type; + }; + + //************************************************************************* + // Greater than 32 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<3> + { + typedef uint_least64_t type; + }; + + //************************************************************************* + // Determine the type to hold the number of bits based on the index. + //************************************************************************* + template <const int index> + struct best_fit_int_type; + + //************************************************************************* + // Less than or equal to 8 bits. + //************************************************************************* + template <> + struct best_fit_int_type<0> + { + typedef int_least8_t type; + }; + + //************************************************************************* + // 9 to 16 bits. + //************************************************************************* + template <> + struct best_fit_int_type<1> + { + typedef int_least16_t type; + }; + + //************************************************************************* + // 17 to 31 bits. + //************************************************************************* + template <> + struct best_fit_int_type<2> + { + typedef int_least32_t type; + }; + + //************************************************************************* + // Greater than 32 bits. + //************************************************************************* + template <> + struct best_fit_int_type<3> + { + typedef int_least64_t type; + }; + } + + //*************************************************************************** + /// Template to determine the smallest unsigned int type that can contain a + /// value with the specified number of bits. + /// Defines 'type' which is the type of the smallest unsigned integer. + ///\ingroup smallest + //*************************************************************************** + template <const size_t NBITS> + struct smallest_uint_for_bits + { + private: + + // Determines the index of the best unsigned type for the required number of bits. + static const int TYPE_INDEX = ((NBITS > 8) ? 1 : 0) + + ((NBITS > 16) ? 1 : 0) + + ((NBITS > 32) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_uint_type<TYPE_INDEX>::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest signed int type that can contain a + /// value with the specified number of bits. + /// Defines 'type' which is the type of the smallest signed integer. + ///\ingroup smallest + //*************************************************************************** + template <const size_t NBITS> + struct smallest_int_for_bits + { + private: + + // Determines the index of the best unsigned type for the required number of bits. + static const int TYPE_INDEX = ((NBITS > 8) ? 1 : 0) + + ((NBITS > 16) ? 1 : 0) + + ((NBITS > 32) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_int_type<TYPE_INDEX>::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest unsigned int type that can contain the + /// specified unsigned value. + /// Defines 'type' which is the type of the smallest unsigned integer. + ///\ingroup smallest + //*************************************************************************** + template <const uintmax_t VALUE> + struct smallest_uint_for_value + { + private: + + // Determines the index of the best unsigned type for the required value. + static const int TYPE_INDEX = ((VALUE > UINT_LEAST8_MAX) ? 1 : 0) + + ((VALUE > UINT16_MAX) ? 1 : 0) + + ((VALUE > UINT32_MAX) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_uint_type<TYPE_INDEX>::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest int type that can contain the + /// specified signed value. + /// Defines 'type' which is the type of the smallest signed integer. + ///\ingroup smallest + //*************************************************************************** + template <const intmax_t VALUE> + struct smallest_int_for_value + { + private: + + // Determines the index of the best signed type for the required value. + static const int TYPE_INDEX = (((VALUE > INT_LEAST8_MAX) || (VALUE < INT_LEAST8_MIN)) ? 1 : 0) + + (((VALUE > INT16_MAX) || (VALUE < INT16_MIN)) ? 1 : 0) + + (((VALUE > INT32_MAX) || (VALUE < INT32_MIN)) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_int_type<TYPE_INDEX>::type type; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/smallest_generator.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,338 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -osmallest.h -DNTypes=<n> smallest_generator.h +// Where <n> is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_SMALLEST__ +#define __ETL_SMALLEST__ + +#include <stdint.h> + +#include "platform.h" +#include "integral_limits.h" + +///\defgroup smallest smallest +///\ingroup utilities + +namespace etl +{ + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the smallest type and size.") + cog.outl("/// Supports up to %s types." % NTypes) + cog.outl("/// Defines 'value_type' which is the type of the smallest parameter.") + cog.outl("/// Defines 'size' which is the size of the smallest parameter.") + cog.outl("///\ingroup smallest") + cog.outl("//***************************************************************************") + cog.out("template <typename T1, ") + for n in range(2, int(NTypes)): + cog.out("typename T%s = void, " % n) + if n % 4 == 0: + cog.outl("") + cog.out(" ") + cog.outl("typename T%s = void>" % int(NTypes)) + cog.outl("struct smallest_type") + cog.outl("{") + cog.outl("private:") + cog.outl("") + cog.outl(" // Declaration.") + cog.outl(" template <const bool Boolean, typename TrueType, typename FalseType>") + cog.outl(" struct choose_type;") + cog.outl("") + cog.outl(" // Specialisation for 'true'.") + cog.outl(" // Defines 'type' as 'TrueType'.") + cog.outl(" template <typename TrueType, typename FalseType>") + cog.outl(" struct choose_type<true, TrueType, FalseType>") + cog.outl(" {") + cog.outl(" typedef TrueType type;") + cog.outl(" };") + cog.outl("") + cog.outl(" // Specialisation for 'false'. ") + cog.outl(" // Defines 'type' as 'FalseType'.") + cog.outl(" template <typename TrueType, typename FalseType>") + cog.outl(" struct choose_type<false, TrueType, FalseType>") + cog.outl(" {") + cog.outl(" typedef FalseType type;") + cog.outl(" };") + cog.outl("") + cog.outl("public:") + cog.outl("") + cog.outl(" // Define 'smallest_other' as 'smallest_type' with all but the first parameter. ") + cog.out(" typedef typename smallest_type<") + for n in range(2, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type smallest_other;" % int(NTypes)) + cog.outl("") + cog.outl(" // Set 'type' to be the smallest of the first parameter and any of the others.") + cog.outl(" // This is recursive.") + cog.outl(" typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)), // Boolean") + cog.outl(" T1, // TrueType") + cog.outl(" smallest_other> // FalseType") + cog.outl(" ::type type; // The smallest type of the two.") + cog.outl("") + cog.outl(" // The size of the smallest type.") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for one template parameter.") + cog.outl("//***************************************************************************") + cog.outl("template <typename T1>") + cog.out("struct smallest_type<T1, ") + for n in range(2, int(NTypes)): + cog.out("void, ") + if n % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl("void>") + cog.outl("{") + cog.outl(" typedef T1 type;") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + namespace __private_smallest__ + { + //************************************************************************* + // Determine the type to hold the number of bits based on the index. + //************************************************************************* + template <const int index> + struct best_fit_uint_type; + + //************************************************************************* + // Less than or equal to 8 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<0> + { + typedef uint_least8_t type; + }; + + //************************************************************************* + // 9 to 16 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<1> + { + typedef uint_least16_t type; + }; + + //************************************************************************* + // 17 to 31 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<2> + { + typedef uint_least32_t type; + }; + + //************************************************************************* + // Greater than 32 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<3> + { + typedef uint_least64_t type; + }; + + //************************************************************************* + // Determine the type to hold the number of bits based on the index. + //************************************************************************* + template <const int index> + struct best_fit_int_type; + + //************************************************************************* + // Less than or equal to 8 bits. + //************************************************************************* + template <> + struct best_fit_int_type<0> + { + typedef int_least8_t type; + }; + + //************************************************************************* + // 9 to 16 bits. + //************************************************************************* + template <> + struct best_fit_int_type<1> + { + typedef int_least16_t type; + }; + + //************************************************************************* + // 17 to 31 bits. + //************************************************************************* + template <> + struct best_fit_int_type<2> + { + typedef int_least32_t type; + }; + + //************************************************************************* + // Greater than 32 bits. + //************************************************************************* + template <> + struct best_fit_int_type<3> + { + typedef int_least64_t type; + }; + } + + //*************************************************************************** + /// Template to determine the smallest unsigned int type that can contain a + /// value with the specified number of bits. + /// Defines 'type' which is the type of the smallest unsigned integer. + ///\ingroup smallest + //*************************************************************************** + template <const size_t NBITS> + struct smallest_uint_for_bits + { + private: + + // Determines the index of the best unsigned type for the required number of bits. + static const int TYPE_INDEX = ((NBITS > 8) ? 1 : 0) + + ((NBITS > 16) ? 1 : 0) + + ((NBITS > 32) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_uint_type<TYPE_INDEX>::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest signed int type that can contain a + /// value with the specified number of bits. + /// Defines 'type' which is the type of the smallest signed integer. + ///\ingroup smallest + //*************************************************************************** + template <const size_t NBITS> + struct smallest_int_for_bits + { + private: + + // Determines the index of the best unsigned type for the required number of bits. + static const int TYPE_INDEX = ((NBITS > 8) ? 1 : 0) + + ((NBITS > 16) ? 1 : 0) + + ((NBITS > 32) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_int_type<TYPE_INDEX>::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest unsigned int type that can contain the + /// specified unsigned value. + /// Defines 'type' which is the type of the smallest unsigned integer. + ///\ingroup smallest + //*************************************************************************** + template <const uintmax_t VALUE> + struct smallest_uint_for_value + { + private: + + // Determines the index of the best unsigned type for the required value. + static const int TYPE_INDEX = ((VALUE > UINT_LEAST8_MAX) ? 1 : 0) + + ((VALUE > UINT16_MAX) ? 1 : 0) + + ((VALUE > UINT32_MAX) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_uint_type<TYPE_INDEX>::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest int type that can contain the + /// specified signed value. + /// Defines 'type' which is the type of the smallest signed integer. + ///\ingroup smallest + //*************************************************************************** + template <const intmax_t VALUE> + struct smallest_int_for_value + { + private: + + // Determines the index of the best signed type for the required value. + static const int TYPE_INDEX = (((VALUE > INT_LEAST8_MAX) || (VALUE < INT_LEAST8_MIN)) ? 1 : 0) + + (((VALUE > INT16_MAX) || (VALUE < INT16_MIN)) ? 1 : 0) + + (((VALUE > INT32_MAX) || (VALUE < INT32_MIN)) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_int_type<TYPE_INDEX>::type type; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sqrt.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,61 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_SQRT__ +#define __ETL_SQRT__ + +#include <stddef.h> + +#include "platform.h" +#include "type_traits.h" +#include "constant.h" + +namespace etl +{ + //*************************************************************************** + /// Calculates the smallest value that, when squared, will be not greater than VALUE. + //*************************************************************************** + template <const size_t VALUE, const size_t I = 1> + struct sqrt + { + typedef typename etl::conditional<((I * I) > VALUE), + etl::constant<intmax_t, I - 1>, + etl::sqrt<VALUE, I + 1> >::type type; + + enum value_type + { + // Recursive definition. + value = type::value + }; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stack.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,492 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove, Mark Kitson + +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_STACK__ +#define __ETL_STACK__ + +#include <stddef.h> +#include <stdint.h> +#include <algorithm> + +#include "platform.h" +#include "container.h" +#include "alignment.h" +#include "array.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "type_traits.h" +#include "parameter_type.h" + +#define ETL_FILE "15" + +//***************************************************************************** +///\defgroup stack stack +/// A Last-in / first-out stack with the capacity defined at compile time, +/// written in the STL style. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + ///\ingroup stack + /// The base class for stack exceptions. + //*************************************************************************** + class stack_exception : public exception + { + public: + + stack_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the stack is full. + //*************************************************************************** + class stack_full : public stack_exception + { + public: + + stack_full(string_type file_name_, numeric_type line_number_) + : stack_exception(ETL_ERROR_TEXT("stack:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the stack is empty. + //*************************************************************************** + class stack_empty : public stack_exception + { + public: + + stack_empty(string_type file_name_, numeric_type line_number_) + : stack_exception(ETL_ERROR_TEXT("stack:empty", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// A fixed capacity stack written in the STL style. + /// \warntopg This stack cannot be used for concurrent access from multiple threads. + //*************************************************************************** + class stack_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of stack. + + //************************************************************************* + /// Checks to see if the stack is empty. + /// \return <b>true</b> if the stack is empty, otherwise <b>false</b> + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Checks to see if the stack is full. + /// \return <b>true</b> if the stack is full, otherwise <b>false</b> + //************************************************************************* + bool full() const + { + return current_size == CAPACITY; + } + + //************************************************************************* + /// Returns the current number of items top the stack. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Returns the maximum number of items that can be stacked. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + stack_base(size_type max_size_) + : top_index(0), + current_size(0), + CAPACITY(max_size_) + { + } + + //************************************************************************* + /// Increments the indexes value to record a stack addition. + //************************************************************************* + void add_in() + { + top_index = current_size++; + ++construct_count; + } + + //************************************************************************* + /// Decrements the indexes value to record a queue deletion. + //************************************************************************* + void del_out() + { + --top_index; + --current_size; + --construct_count; + } + + size_type top_index; ///< The index of the top of the stack. + size_type current_size; ///< The number of items in the stack. + const size_type CAPACITY; ///< The maximum number of items in the stack. + etl::debug_count construct_count; ///< For internal debugging purposes. + }; + + //*************************************************************************** + ///\ingroup stack + ///\brief This is the base for all stacks that contain a particular type. + ///\details Normally a reference to this type will be taken from a derived stack. + ///\code + /// etl::stack<int, 10> myStack; + /// etl::istack<int>& iStack = myStack; + ///\endcode + /// \warning This stack cannot be used for concurrent access from multiple threads. + /// \tparam T The type of value that the stack holds. + //*************************************************************************** + template <typename T> + class istack : public etl::stack_base + { + public: + + typedef T value_type; ///< The type stored in the stack. + typedef T& reference; ///< A reference to the type used in the stack. + typedef const T& const_reference; ///< A const reference to the type used in the stack. + typedef T* pointer; ///< A pointer to the type used in the stack. + typedef const T* const_pointer; ///< A const pointer to the type used in the stack. + typedef stack_base::size_type size_type; ///< The type used for determining the size of the stack. + + private: + + typedef typename etl::parameter_type<T>::type parameter_t; + typedef typename etl::stack_base base_t; + + public: + + //************************************************************************* + /// Gets a reference to the value at the top of the stack.<br> + /// \return A reference to the value at the top of the stack. + //************************************************************************* + reference top() + { + return p_buffer[top_index]; + } + + //************************************************************************* + /// Adds a value to the stack. + /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. + ///\param value The value to push to the stack. + //************************************************************************* + void push(parameter_t value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + base_t::add_in(); + ::new (&p_buffer[top_index]) T(value); + } + + //************************************************************************* + /// Constructs a value in the stack place'. + /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. + ///\param value The value to push to the stack. + //************************************************************************* + template <typename T1> + void emplace(const T1& value1) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + base_t::add_in(); + ::new (&p_buffer[top_index]) T(value1); + } + + //************************************************************************* + /// Constructs a value in the stack place'. + /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. + ///\param value The value to push to the stack. + //************************************************************************* + template <typename T1, typename T2> + void emplace(const T1& value1, const T2& value2) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + base_t::add_in(); + ::new (&p_buffer[top_index]) T(value1, value2); + } + + //************************************************************************* + /// Constructs a value in the stack place'. + /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. + ///\param value The value to push to the stack. + //************************************************************************* + template <typename T1, typename T2, typename T3> + void emplace(const T1& value1, const T2& value2, const T3& value3) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + base_t::add_in(); + ::new (&p_buffer[top_index]) T(value1, value2, value3); + } + + //************************************************************************* + /// Constructs a value in the stack place'. + /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. + ///\param value The value to push to the stack. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + void emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + base_t::add_in(); + ::new (&p_buffer[top_index]) T(value1, value2, value3, value4); + } + + //************************************************************************* + /// Allows a possibly more efficient 'push' by moving to the next input value + /// and returning a reference to it. + /// This may eliminate a copy by allowing direct construction in-place.<br> + /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. + /// \return A reference to the position to 'push' to. + //************************************************************************* + reference push() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + base_t::add_in(); + + return p_buffer[top_index]; + } + + //************************************************************************* + /// Gets a const reference to the value at the top of the stack.<br> + /// \return A const reference to the value at the top of the stack. + //************************************************************************* + const_reference top() const + { + return p_buffer[top_index]; + } + + //************************************************************************* + /// Clears the stack to the empty state. + //************************************************************************* + void clear() + { + while (current_size > 0) + { + p_buffer[top_index].~T(); + base_t::del_out(); + } + } + + //************************************************************************* + /// Removes the oldest item from the top of the stack. + //************************************************************************* + void pop() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(stack_empty)); +#endif + p_buffer[top_index].~T(); + base_t::del_out(); + } + + //************************************************************************* + /// Removes the oldest item from the top of the stack and puts it in the destination. + //************************************************************************* + void pop_into(reference destination) + { + destination = top(); + pop(); + } + + //************************************************************************* + /// Removes the oldest item from the top of the stack and pushes it to the + /// destination container. + /// NOTE: The destination must support a push(T) member function. + //************************************************************************* + template <typename TContainer> + void pop_into(TContainer& destination) + { + destination.push(top()); + pop(); + } + + //************************************************************************* + /// Reverses the stack. + //************************************************************************* + void reverse() + { + std::reverse(p_buffer, p_buffer + current_size); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + istack& operator = (const istack& rhs) + { + if (&rhs != this) + { + clear(); + clone(rhs); + } + + return *this; + } + + protected: + + //************************************************************************* + /// Make this a clone of the supplied stack + //************************************************************************* + void clone(const istack& other) + { + size_t index = 0; + + for (size_t i = 0; i < other.size(); ++i) + { + push(other.p_buffer[index++]); + } + } + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + istack(T* p_buffer_, size_type max_size_) + : stack_base(max_size_), + p_buffer(p_buffer_) + { + } + + private: + + // Disable copy construction. + istack(const istack&); + + T* p_buffer; ///< The internal buffer. + }; + + //*************************************************************************** + ///\ingroup stack + /// A fixed capacity stack. + /// This stack does not suppo7rt concurrent access by different threads. + /// \tparam T The type this stack should support. + /// \tparam MAX_SIZE The maximum capacity of the stack. + //*************************************************************************** + template <typename T, const size_t SIZE> + class stack : public etl::istack<T> + { + public: + + static const size_t MAX_SIZE = SIZE; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + stack() + : etl::istack<T>(reinterpret_cast<T*>(&buffer[0]), SIZE) + { + } + + //************************************************************************* + /// Copy constructor + //************************************************************************* + stack(const stack& rhs) + : etl::istack<T>(reinterpret_cast<T*>(&buffer[0]), SIZE) + { + etl::istack<T>::clone(rhs); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~stack() + { + etl::istack<T>::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + stack& operator = (const stack& rhs) + { + if (&rhs != this) + { + etl::istack<T>::clone(rhs); + } + + return *this; + } + + private: + + /// The unintitialised buffer of T used in the stack. + typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[SIZE]; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static_assert.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,53 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_STATIC_ASSERT__ +#define __ETL_STATIC_ASSERT__ + +#include "platform.h" + +#if (ETL_CPP11_SUPPORTED) + #define STATIC_ASSERT(Condition, Message) static_assert(Condition, Message) +#else + template <bool Condition> + struct STATIC_ASSERT_FAILED; + + template <> + struct STATIC_ASSERT_FAILED<true> {}; + + #define ETL_SA1(a,b) a##b + #define ETL_SA2(a,b) ETL_SA1(a,b) + #define STATIC_ASSERT(Condition, Message) \ + enum \ + { \ + ETL_SA2(dummy, __LINE__) = sizeof(STATIC_ASSERT_FAILED<(bool)(Condition)>) \ + } +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/string_view.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,876 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_STRING_VIEW__ +#define __ETL_STRING_VIEW__ + +#include "platform.h" +#include "memory.h" +#include "iterator.h" +#include "error_handler.h" +#include "exception.h" +#include "char_traits.h" +#include "integral_limits.h" +#include "hash.h" + +#include <algorithm> + +///\defgroup array array +/// A wrapper for arrays +///\ingroup containers + +#undef ETL_FILE +#define ETL_FILE "42" + +#ifdef ETL_COMPILER_MICROSOFT +#undef min +#undef max +#endif + +namespace etl +{ + //*************************************************************************** + /// The base class for basic_string_view exceptions. + //*************************************************************************** + class string_view_exception : public exception + { + public: + + string_view_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the index is out of bounds. + //*************************************************************************** + class string_view_bounds : public string_view_exception + { + public: + + string_view_bounds(string_type file_name_, numeric_type line_number_) + : string_view_exception(ETL_ERROR_TEXT("basic_string_view:bounds", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the view is uninitialised. + //*************************************************************************** + class string_view_uninitialised : public string_view_exception + { + public: + + string_view_uninitialised(string_type file_name_, numeric_type line_number_) + : string_view_exception(ETL_ERROR_TEXT("basic_string_view:uninitialised", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// String view. + //*************************************************************************** + template <typename T, typename TTraits = etl::char_traits<T> > + class basic_string_view + { + public: + + typedef T value_type; + typedef TTraits traits_type; + typedef std::size_t size_type; + typedef const T& const_reference; + typedef const T* const_pointer; + typedef const T* const_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + enum + { + npos = etl::integral_limits<size_t>::max + }; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + basic_string_view() + : mbegin(std::nullptr), + mend(std::nullptr) + { + } + + //************************************************************************* + /// Construct from T*. + //************************************************************************* + basic_string_view(const T* begin_) + : mbegin(begin_), + mend(begin_ + TTraits::length(begin_)) + { + } + + //************************************************************************* + /// Construct from pointer range. + //************************************************************************* + basic_string_view(const T* begin_, const T* end_) + : mbegin(begin_), + mend(end_) + { + } + + //************************************************************************* + /// Construct from iterator/size. + //************************************************************************* + template <typename TSize, typename TDummy = typename etl::enable_if<etl::is_integral<TSize>::value, void>::type> + basic_string_view(const T* begin_, TSize size_) + : mbegin(begin_), + mend(begin_ + size_) + { + } + + //************************************************************************* + /// Copy constructor + //************************************************************************* + basic_string_view(const basic_string_view& other) + : mbegin(other.mbegin), + mend(other.mend) + { + } + + //************************************************************************* + /// Returns a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return *mbegin; + } + + //************************************************************************* + /// Returns a const reference to the last element. + //************************************************************************* + const_reference back() const + { + return *(mend - 1); + } + + //************************************************************************* + /// Returns a const pointer to the first element of the internal storage. + //************************************************************************* + const_pointer data() const + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator begin() const + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator cbegin() const + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator end() const + { + return mend; + } + + //************************************************************************* + // Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator cend() const + { + return mend; + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(mbegin); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(mbegin); + } + + //************************************************************************* + // Capacity + //************************************************************************* + + //************************************************************************* + /// Returns <b>true</b> if the array size is zero. + //************************************************************************* + bool empty() const + { + return (mbegin == mend); + } + + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + size_t size() const + { + return (mend - mbegin); + } + + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + size_t length() const + { + return size(); + } + + //************************************************************************* + /// Returns the maximum possible size of the array. + //************************************************************************* + size_t max_size() const + { + return size(); + } + + //************************************************************************* + /// Assign from a view. + //************************************************************************* + etl::basic_string_view<T, TTraits>& operator=(const etl::basic_string_view<T, TTraits>& other) + { + mbegin = other.mbegin; + mend = other.mend; + return *this; + } + + //************************************************************************* + /// Assign from iterators + //************************************************************************* + template <typename TIterator, + typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + void assign(TIterator begin_, TIterator end_) + { + mbegin = etl::addressof(*begin_); + mend = etl::addressof(*begin_) + std::distance(begin_, end_); + } + + //************************************************************************* + /// Assign from iterator and size. + //************************************************************************* + template <typename TIterator, + typename TSize, + typename TDummy = typename etl::enable_if<etl::is_random_iterator<TIterator>::value, void>::type> + void assign(TIterator begin_, TSize size_) + { + mbegin = etl::addressof(*begin_); + mend = etl::addressof(*begin_) + size_; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference operator[](size_t i) const + { + return mbegin[i]; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference at(size_t i) const + { + ETL_ASSERT((mbegin != std::nullptr && mend != std::nullptr), ETL_ERROR(string_view_uninitialised)); + ETL_ASSERT(i < size(), ETL_ERROR(string_view_bounds)); + return mbegin[i]; + } + + //************************************************************************* + /// Swaps with another basic_string_view. + //************************************************************************* + void swap(basic_string_view& other) + { + std::swap(mbegin, other.mbegin); + std::swap(mend, other.mend); + } + + //************************************************************************* + /// Copies characters + //************************************************************************* + size_type copy(T* destination, size_type count, size_type position = 0) const + { + size_t n = 0; + + if (position < size()) + { + n = std::min(count, size() - position); + + std::copy(mbegin + position, mbegin + position + n, destination); + } + + return n; + } + + //************************************************************************* + /// Returns a substring + //************************************************************************* + basic_string_view substr(size_type position = 0, size_type count = npos) const + { + basic_string_view view; + + if (position < size()) + { + size_t n = std::min(count, size() - position); + + view = basic_string_view(mbegin + position, mbegin + position + n); + } + + return view; + } + + //************************************************************************* + /// Shrinks the view by moving its start forward. + //************************************************************************* + void remove_prefix(size_type n) + { + mbegin += n; + } + + //************************************************************************* + /// Shrinks the view by moving its end backward. + //************************************************************************* + void remove_suffix(size_type n) + { + mend -= n; + } + + //************************************************************************* + /// Compares two views + //************************************************************************* + int compare(basic_string_view<T, TTraits> view) const + { + return (*this == view) ? 0 : ((*this > view) ? 1 : -1); + } + + int compare(size_type position, size_type count, basic_string_view view) const + { + return substr(position, count).compare(view); + } + + int compare(size_type position1, size_type count1, + basic_string_view view, + size_type position2, size_type count2) const + { + return substr(position1, count1).compare(view.substr(position2, count2)); + } + + int compare(const T* text) const + { + return compare(etl::basic_string_view<T, TTraits>(text)); + } + + int compare(size_type position, size_type count, const T* text) const + { + return substr(position, count).compare(etl::basic_string_view<T, TTraits>(text)); + } + + int compare(size_type position, size_type count1, const T* text, size_type count2) const + { + return substr(position, count1).compare(etl::basic_string_view<T, TTraits>(text, count2)); + } + + //************************************************************************* + /// Checks if the string view starts with the given prefix + //************************************************************************* + bool starts_with(etl::basic_string_view<T, TTraits> view) const + { + return (size() >= view.size()) && + (compare(0, view.size(), view) == 0); + } + + bool starts_with(T c) const + { + return !empty() && (front() == c); + } + + bool starts_with(const T* text) const + { + size_t lengthtext = TTraits::length(text); + + return (size() >= lengthtext) && + (compare(0, lengthtext, text) == 0); + } + + //************************************************************************* + /// Checks if the string view ends with the given suffix + //************************************************************************* + bool ends_with(etl::basic_string_view<T, TTraits> view) const + { + return (size() >= view.size()) && + (compare(size() - view.size(), npos, view) == 0); + } + + bool ends_with(T c) const + { + return !empty() && (back() == c); + } + + bool ends_with(const T* text) const + { + size_t lengthtext = TTraits::length(text); + size_t lengthview = size(); + + return (lengthview >= lengthtext) && + (compare(lengthview - lengthtext, lengthtext, text) == 0); + } + + //************************************************************************* + /// Find characters in the view + //************************************************************************* + size_type find(etl::basic_string_view<T, TTraits> view, size_type position = 0) const + { + if ((size() < view.size())) + { + return npos; + } + + const_iterator iposition = std::search(begin() + position, end(), view.begin(), view.end()); + + if (iposition == end()) + { + return npos; + } + else + { + return std::distance(begin(), iposition); + } + } + + size_type find(T c, size_type position = 0) const + { + return find(etl::basic_string_view<T, TTraits>(&c, 1), position); + } + + size_type find(const T* text, size_type position, size_type count) const + { + return find(etl::basic_string_view<T, TTraits>(text, count), position); + } + + size_type find(const T* text, size_type position = 0) const + { + return find(etl::basic_string_view<T, TTraits>(text), position); + } + + //************************************************************************* + /// Find the last occurrence of a substring + //************************************************************************* + size_type rfind(etl::basic_string_view<T, TTraits> view, size_type position = npos) const + { + if ((size() < view.size())) + { + return npos; + } + + position = std::min(position, size()); + + const_iterator iposition = std::find_end(begin(), + begin() + position, + view.begin(), + view.end()); + + if (iposition == end()) + { + return npos; + } + else + { + return std::distance(begin(), iposition); + } + } + + size_type rfind(T c, size_type position = npos) const + { + return rfind(etl::basic_string_view<T, TTraits>(&c, 1), position); + } + + size_type rfind(const T* text, size_type position, size_type count) const + { + return rfind(etl::basic_string_view<T, TTraits>(text, count), position); + } + + size_type rfind(const T* text, size_type position = npos) const + { + return rfind(etl::basic_string_view<T, TTraits>(text), position); + } + + //************************************************************************* + /// Find first occurrence of characters + //************************************************************************* + size_type find_first_of(etl::basic_string_view<T, TTraits> view, size_type position = 0) const + { + const size_t lengthtext = size(); + + if (position < lengthtext) + { + for (size_t i = position; i < lengthtext; ++i) + { + const size_t lengthview = view.size(); + + for (size_t j = 0; j < lengthview; ++j) + { + if (mbegin[i] == view[j]) + { + return i; + } + } + } + } + + return npos; + } + + size_type find_first_of(T c, size_type position = 0) const + { + return find_first_of(etl::basic_string_view<T, TTraits>(&c, 1), position); + } + + size_type find_first_of(const T* text, size_type position, size_type count) const + { + return find_first_of(etl::basic_string_view<T, TTraits>(text, count), position); + } + + size_type find_first_of(const T* text, size_type position = 0) const + { + return find_first_of(etl::basic_string_view<T, TTraits>(text), position); + } + + //************************************************************************* + /// Find last occurrence of characters + //************************************************************************* + size_type find_last_of(etl::basic_string_view<T, TTraits> view, size_type position = npos) const + { + if (empty()) + { + return npos; + } + + position = std::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + const size_t viewlength = view.size(); + + for (size_t j = 0; j < viewlength; ++j) + { + if (mbegin[position] == view[j]) + { + return position; + } + } + + ++it; + --position; + } + + return npos; + } + + size_type find_last_of(T c, size_type position = npos) const + { + return find_last_of(etl::basic_string_view<T, TTraits>(&c, 1), position);; + } + + size_type find_last_of(const T* text, size_type position, size_type count) const + { + return find_last_of(etl::basic_string_view<T, TTraits>(text, count), position);; + } + + size_type find_last_of(const T* text, size_type position = npos) const + { + return find_last_of(etl::basic_string_view<T, TTraits>(text), position);; + } + + //************************************************************************* + /// Find first absence of characters + //************************************************************************* + size_type find_first_not_of(etl::basic_string_view<T, TTraits> view, size_type position = 0) const + { + const size_t lengthtext = size(); + + if (position < lengthtext) + { + for (size_t i = position; i < lengthtext; ++i) + { + bool found = false; + + const size_t viewlength = view.size(); + + for (size_t j = 0; j < viewlength; ++j) + { + if (mbegin[i] == view[j]) + { + found = true; + } + } + + if (!found) + { + return i; + } + } + } + + return npos; + } + + size_type find_first_not_of(T c, size_type position = 0) const + { + return find_first_not_of(etl::basic_string_view<T, TTraits>(&c, 1), position); + } + + size_type find_first_not_of(const T* text, size_type position, size_type count) const + { + return find_first_not_of(etl::basic_string_view<T, TTraits>(text, count), position); + } + + size_type find_first_not_of(const T* text, size_type position = 0) const + { + return find_first_not_of(etl::basic_string_view<T, TTraits>(text), position); + } + + //************************************************************************* + /// Find last absence of characters + //************************************************************************* + size_type find_last_not_of(etl::basic_string_view<T, TTraits> view, size_type position = npos) const + { + if (empty()) + { + return npos; + } + + position = std::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + bool found = false; + + const size_t viewlength = view.size(); + + for (size_t j = 0; j < viewlength; ++j) + { + if (mbegin[position] == view[j]) + { + found = true; + } + } + + if (!found) + { + return position; + } + + ++it; + --position; + } + + return npos; + } + + size_type find_last_not_of(T c, size_type position = npos) const + { + return find_last_not_of(etl::basic_string_view<T, TTraits>(&c, 1), position);; + } + + size_type find_last_not_of(const T* text, size_type position, size_type count) const + { + return find_last_not_of(etl::basic_string_view<T, TTraits>(text, count), position);; + } + + size_type find_last_not_of(const T* text, size_type position = npos) const + { + return find_last_not_of(etl::basic_string_view<T, TTraits>(text), position);; + } + + //************************************************************************* + /// Equality for array views. + //************************************************************************* + friend bool operator == (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs) + { + return (lhs.size() == rhs.size()) && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //************************************************************************* + /// Inequality for array views. + //************************************************************************* + friend bool operator != (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// Less-than for array views. + //************************************************************************* + friend bool operator < (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //************************************************************************* + /// Greater-than for array views. + //************************************************************************* + friend bool operator > (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs) + { + return rhs < lhs; + } + + //************************************************************************* + /// Less-than-equal for array views. + //************************************************************************* + friend bool operator <= (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs) + { + return !(lhs > rhs); + } + + //************************************************************************* + /// Greater-than-equal for array views. + //************************************************************************* + friend bool operator >= (const etl::basic_string_view<T, TTraits>& lhs, const etl::basic_string_view<T, TTraits>& rhs) + { + return !(lhs < rhs); + } + + private: + + const T* mbegin; + const T* mend; + }; + + typedef etl::basic_string_view<char> string_view; + typedef etl::basic_string_view<wchar_t> wstring_view; + typedef etl::basic_string_view<char16_t> u16string_view; + typedef etl::basic_string_view<char32_t> u32string_view; + + //************************************************************************* + /// Hash function. + //************************************************************************* +#if ETL_8BIT_SUPPORT + template <> + struct hash<etl::string_view> + { + size_t operator()(const etl::string_view& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; + + template <> + struct hash<etl::wstring_view> + { + size_t operator()(const etl::wstring_view& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; + + template <> + struct hash<etl::u16string_view> + { + size_t operator()(const etl::u16string_view& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; + + template <> + struct hash<etl::u32string_view> + { + size_t operator()(const etl::u32string_view& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; +#endif +} + +//************************************************************************* +/// Swaps the values. +//************************************************************************* +template <typename T, typename TTraits = etl::char_traits<T>> +void swap(etl::basic_string_view<T, TTraits>& lhs, etl::basic_string_view<T, TTraits>& rhs) +{ + lhs.swap(rhs); +} + +#ifdef ETL_COMPILER_MICROSOFT +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#undef ETL_FILE + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,127 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_TASK__ +#define __ETL_TASK__ + +#include <stdint.h> + +#include "platform.h" +#include "error_handler.h" +#include "exception.h" + +#undef ETL_FILE +#define ETL_FILE "37" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for task. + //*************************************************************************** + class task_exception : public etl::exception + { + public: + + task_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + typedef uint_least8_t task_priority_t; + + //*************************************************************************** + /// Scheduler. + //*************************************************************************** + class task + { + public: + + //******************************************* + /// Constructor. + //******************************************* + task(task_priority_t priority) + : task_running(true), + task_priority(priority) + { + } + + //******************************************* + /// Destructor. + //******************************************* + virtual ~task() + { + } + + //******************************************* + /// Called to check if the task has work. + /// Returns a score as to the amount of work it has to do. + //******************************************* + virtual uint32_t task_request_work() const = 0; + + //******************************************* + /// Called to get the task to do work. + //******************************************* + virtual void task_process_work() = 0; + + //******************************************* + /// Set the running state for the task. + //******************************************* + void set_task_running(bool task_running_) + { + task_running = task_running_; + } + + //******************************************* + /// Get the running state for the task. + //******************************************* + bool task_is_running() const + { + return task_running; + } + + //******************************************* + /// Get the priority of the task. + /// Higher value = higher priority. + //******************************************* + etl::task_priority_t get_task_priority() const + { + return task_priority; + } + + private: + + bool task_running; + etl::task_priority_t task_priority; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/temp.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,898 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_TYPE_LOOKUP__ +#define __ETL_TYPE_LOOKUP__ + +#undef ETL_FILE +#define ETL_FILE "41" + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +namespace etl +{ + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID = 0, typename T2 = void, + const size_t T3ID = 0, typename T3 = void, + const size_t T4ID = 0, typename T4 = void, + const size_t T5ID = 0, typename T5 = void, + const size_t T6ID = 0, typename T6 = void, + const size_t T7ID = 0, typename T7 = void, + const size_t T8ID = 0, typename T8 = void, + const size_t T9ID = 0, typename T9 = void, + const size_t T10ID = 0, typename T10 = void, + const size_t T11ID = 0, typename T11 = void, + const size_t T12ID = 0, typename T12 = void, + const size_t T13ID = 0, typename T13 = void, + const size_t T14ID = 0, typename T14 = void, + const size_t T15ID = 0, typename T15 = void, + const size_t T16ID = 0, typename T16 = void> + struct type_lookup + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + typename etl::conditional<ID == T8ID, T8, + typename etl::conditional<ID == T9ID, T9, + typename etl::conditional<ID == T10ID, T10, + typename etl::conditional<ID == T11ID, T11, + typename etl::conditional<ID == T12ID, T12, + typename etl::conditional<ID == T13ID, T13, + typename etl::conditional<ID == T14ID, T14, + typename etl::conditional<ID == T15ID, T15, + typename etl::conditional<ID == T16ID, T16, + void>::type>::type>::type>::type>::type>::type>::type> + ::type>::type>::type>::type>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + etl::is_same<T, T8>::value ? T8ID : + etl::is_same<T, T9>::value ? T9ID : + etl::is_same<T, T10>::value ? T10ID : + etl::is_same<T, T11>::value ? T11ID : + etl::is_same<T, T12>::value ? T12ID : + etl::is_same<T, T13>::value ? T13ID : + etl::is_same<T, T14>::value ? T14ID : + etl::is_same<T, T15>::value ? T15ID : + etl::is_same<T, T16>::value ? T16ID : + UNKNOWN + }; + }; + }; + + //************************************************************************* + + //*************************************************************************** + // Specialisation for 15 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6, + const size_t T7ID, typename T7, + const size_t T8ID, typename T8, + const size_t T9ID, typename T9, + const size_t T10ID, typename T10, + const size_t T11ID, typename T11, + const size_t T12ID, typename T12, + const size_t T13ID, typename T13, + const size_t T14ID, typename T14, + const size_t T15ID, typename T15> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, + T9ID, T9, T10ID, T10, T11ID, T11, T12ID, T12, T13ID, T13, T14ID, T14, T15ID, T15, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + typename etl::conditional<ID == T8ID, T8, + typename etl::conditional<ID == T9ID, T9, + typename etl::conditional<ID == T10ID, T10, + typename etl::conditional<ID == T11ID, T11, + typename etl::conditional<ID == T12ID, T12, + typename etl::conditional<ID == T13ID, T13, + typename etl::conditional<ID == T14ID, T14, + typename etl::conditional<ID == T15ID, T15, + void>::type>::type>::type>::type>::type>::type>::type> + ::type>::type>::type>::type>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + etl::is_same<T, T8>::value ? T8ID : + etl::is_same<T, T9>::value ? T9ID : + etl::is_same<T, T10>::value ? T10ID : + etl::is_same<T, T11>::value ? T11ID : + etl::is_same<T, T12>::value ? T12ID : + etl::is_same<T, T13>::value ? T13ID : + etl::is_same<T, T14>::value ? T14ID : + etl::is_same<T, T15>::value ? T15ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 14 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6, + const size_t T7ID, typename T7, + const size_t T8ID, typename T8, + const size_t T9ID, typename T9, + const size_t T10ID, typename T10, + const size_t T11ID, typename T11, + const size_t T12ID, typename T12, + const size_t T13ID, typename T13, + const size_t T14ID, typename T14> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, + T9ID, T9, T10ID, T10, T11ID, T11, T12ID, T12, T13ID, T13, T14ID, T14, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + typename etl::conditional<ID == T8ID, T8, + typename etl::conditional<ID == T9ID, T9, + typename etl::conditional<ID == T10ID, T10, + typename etl::conditional<ID == T11ID, T11, + typename etl::conditional<ID == T12ID, T12, + typename etl::conditional<ID == T13ID, T13, + typename etl::conditional<ID == T14ID, T14, + void>::type>::type>::type>::type>::type>::type>::type> + ::type>::type>::type>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + etl::is_same<T, T8>::value ? T8ID : + etl::is_same<T, T9>::value ? T9ID : + etl::is_same<T, T10>::value ? T10ID : + etl::is_same<T, T11>::value ? T11ID : + etl::is_same<T, T12>::value ? T12ID : + etl::is_same<T, T13>::value ? T13ID : + etl::is_same<T, T14>::value ? T14ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 13 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6, + const size_t T7ID, typename T7, + const size_t T8ID, typename T8, + const size_t T9ID, typename T9, + const size_t T10ID, typename T10, + const size_t T11ID, typename T11, + const size_t T12ID, typename T12, + const size_t T13ID, typename T13> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, + T9ID, T9, T10ID, T10, T11ID, T11, T12ID, T12, T13ID, T13, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + typename etl::conditional<ID == T8ID, T8, + typename etl::conditional<ID == T9ID, T9, + typename etl::conditional<ID == T10ID, T10, + typename etl::conditional<ID == T11ID, T11, + typename etl::conditional<ID == T12ID, T12, + typename etl::conditional<ID == T13ID, T13, + void>::type>::type>::type>::type>::type>::type>::type> + ::type>::type>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + etl::is_same<T, T8>::value ? T8ID : + etl::is_same<T, T9>::value ? T9ID : + etl::is_same<T, T10>::value ? T10ID : + etl::is_same<T, T11>::value ? T11ID : + etl::is_same<T, T12>::value ? T12ID : + etl::is_same<T, T13>::value ? T13ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 12 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6, + const size_t T7ID, typename T7, + const size_t T8ID, typename T8, + const size_t T9ID, typename T9, + const size_t T10ID, typename T10, + const size_t T11ID, typename T11, + const size_t T12ID, typename T12> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, + T9ID, T9, T10ID, T10, T11ID, T11, T12ID, T12, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + typename etl::conditional<ID == T8ID, T8, + typename etl::conditional<ID == T9ID, T9, + typename etl::conditional<ID == T10ID, T10, + typename etl::conditional<ID == T11ID, T11, + typename etl::conditional<ID == T12ID, T12, + void>::type>::type>::type>::type>::type>::type>::type> + ::type>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + etl::is_same<T, T8>::value ? T8ID : + etl::is_same<T, T9>::value ? T9ID : + etl::is_same<T, T10>::value ? T10ID : + etl::is_same<T, T11>::value ? T11ID : + etl::is_same<T, T12>::value ? T12ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 11 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6, + const size_t T7ID, typename T7, + const size_t T8ID, typename T8, + const size_t T9ID, typename T9, + const size_t T10ID, typename T10, + const size_t T11ID, typename T11> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, + T9ID, T9, T10ID, T10, T11ID, T11, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + typename etl::conditional<ID == T8ID, T8, + typename etl::conditional<ID == T9ID, T9, + typename etl::conditional<ID == T10ID, T10, + typename etl::conditional<ID == T11ID, T11, + void>::type>::type>::type>::type>::type>::type>::type> + ::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + etl::is_same<T, T8>::value ? T8ID : + etl::is_same<T, T9>::value ? T9ID : + etl::is_same<T, T10>::value ? T10ID : + etl::is_same<T, T11>::value ? T11ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 10 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6, + const size_t T7ID, typename T7, + const size_t T8ID, typename T8, + const size_t T9ID, typename T9, + const size_t T10ID, typename T10> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, + T9ID, T9, T10ID, T10, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + typename etl::conditional<ID == T8ID, T8, + typename etl::conditional<ID == T9ID, T9, + typename etl::conditional<ID == T10ID, T10, + void>::type>::type>::type>::type>::type>::type>::type> + ::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + etl::is_same<T, T8>::value ? T8ID : + etl::is_same<T, T9>::value ? T9ID : + etl::is_same<T, T10>::value ? T10ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 9 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6, + const size_t T7ID, typename T7, + const size_t T8ID, typename T8, + const size_t T9ID, typename T9> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, + T9ID, T9, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + typename etl::conditional<ID == T8ID, T8, + typename etl::conditional<ID == T9ID, T9, + void>::type>::type>::type>::type>::type>::type>::type> + ::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + etl::is_same<T, T8>::value ? T8ID : + etl::is_same<T, T9>::value ? T9ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 8 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6, + const size_t T7ID, typename T7, + const size_t T8ID, typename T8> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, T8ID, T8, + 0, void, + 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + typename etl::conditional<ID == T8ID, T8, + void>::type>::type>::type>::type>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + etl::is_same<T, T8>::value ? T8ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 7 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6, + const size_t T7ID, typename T7> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, T7ID, T7, 0, void, 0, void, + 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + typename etl::conditional<ID == T7ID, T7, + void>::type>::type>::type>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + etl::is_same<T, T7>::value ? T7ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 6 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5, + const size_t T6ID, typename T6> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, T6ID, T6, 0, void, 0, void, 0, void, + 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + typename etl::conditional<ID == T6ID, T6, + void>::type>::type>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + etl::is_same<T, T6>::value ? T6ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 5 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4, + const size_t T5ID, typename T5> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, T5ID, T5, 0, void, 0, void, 0, void, 0, void, + 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + typename etl::conditional<ID == T5ID, T5, + void>::type>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + etl::is_same<T, T5>::value ? T5ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 4 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3, + const size_t T4ID, typename T4> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, T4ID, T4, 0, void, 0, void, 0, void, 0, void, 0, void, + 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + typename etl::conditional<ID == T4ID, T4, + void>::type>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + etl::is_same<T, T4>::value ? T4ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 3 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2, + const size_t T3ID, typename T3> + struct type_lookup<T1ID, T1, T2ID, T2, T3ID, T3, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, + 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + typename etl::conditional<ID == T3ID, T3, + void>::type>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + etl::is_same<T, T3>::value ? T3ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 2 types. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T2ID, typename T2> + struct type_lookup<T1ID, T1, T2ID, T2, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, + 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + typename etl::conditional<ID == T2ID, T2, + void>::type>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + etl::is_same<T, T2>::value ? T2ID : + UNKNOWN + }; + }; + }; + + //*************************************************************************** + // Specialisation for 1 type. + //*************************************************************************** + template <const size_t T1ID, typename T1, + const size_t T1ID, typename T1> + struct type_lookup<T1ID, T1, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, + 0, void, 0, void, 0, void, 0, void, 0, void, 0, void, 0, void> + { + //************************************ + template <size_t ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1ID, T1, + void>::type type; + }; + + //************************************ + template <typename T> + struct id_from_type + { + enum + { + UNKNOWN = 0xFFFFFFFF, + value = + etl::is_same<T, T1>::value ? T1ID : + UNKNOWN + }; + }; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/timer.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,102 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_TIMER__ +#define __ETL_TIMER__ + +#include <stdint.h> + +#include "platform.h" + +#include "atomic.h" + +//***************************************************************************** +// Definitions common to timers. +//***************************************************************************** + +namespace etl +{ +#ifdef ETL_TIMER_SEMAPHORE_TYPE + typedef ETL_TIMER_SEMAPHORE_TYPE timer_semaphore_t; +#else + typedef etl::atomic_uint32_t timer_semaphore_t; +#endif + + //*************************************************************************** + /// Common definitions for the timer framework. + //*************************************************************************** + struct timer + { + // Timer modes. + struct mode + { + enum + { + SINGLE_SHOT = false, + REPEATING = true + }; + + typedef bool type; + }; + + // Timer start status. + struct start + { + enum + { + DELAYED = false, + IMMEDIATE = true + }; + + typedef bool type; + }; + + // Timer id. + struct id + { + enum + { + NO_TIMER = 255 + }; + + typedef uint_least8_t type; + }; + + // Timer state. + struct state + { + enum + { + INACTIVE = 0xFFFFFFFF + }; + }; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/type_def.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,309 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_TYPE_DEF__ +#define __ETL_TYPE_DEF__ + +#include "platform.h" + +namespace etl +{ + #define ETL_TYPEDEF(T, name) class name##_tag; typedef etl::type_def<name##_tag, T> name + + //************************************************************************* + /// A template type to define strong typedefs. + /// Usage: + ///\code + /// // Short form. + /// ETL_TYPEDEF(int, mytype); + /// + /// // Long form. + /// class mytype_t_tag; + /// typedef etl::type_def<mytype_t_tag, int> mytype_t_tag; + ///\endcode + //************************************************************************* + template <typename TIdType, typename TValue> + class type_def + { + public: + + typedef TValue value_type; + typedef TIdType id_type; + + //********************************************************************* + type_def() + : value(TValue()) + { + } + + //********************************************************************* + type_def(TValue value_) + : value(value_) + { + } + + //********************************************************************* + type_def(const type_def& other) + : value(other.value) + { + } + + //********************************************************************* + operator TValue() const + { + return value; + } + + //********************************************************************* + type_def& operator ++() + { + ++value; + return *this; + } + + //********************************************************************* + type_def operator ++(int) + { + type_def temp(*this); + type_def::operator ++(); + return temp; + } + + //********************************************************************* + type_def& operator --() + { + --value; + return *this; + } + + //********************************************************************* + type_def operator --(int) + { + type_def temp(*this); + type_def::operator --(); + return temp; + } + + //********************************************************************* + type_def& operator +=(TValue rhs) + { + value += rhs; + return *this; + } + + //********************************************************************* + type_def& operator +=(const type_def& rhs) + { + value += rhs.value; + return *this; + } + + //********************************************************************* + type_def& operator -=(TValue rhs) + { + value -= rhs; + return *this; + } + + //********************************************************************* + type_def& operator -=(const type_def& rhs) + { + value -= rhs.value; + return *this; + } + + //********************************************************************* + type_def& operator *=(TValue rhs) + { + value *= rhs; + return *this; + } + + //********************************************************************* + type_def& operator *=(const type_def& rhs) + { + value *= rhs.value; + return *this; + } + + //********************************************************************* + type_def& operator /=(TValue rhs) + { + value /= rhs; + return *this; + } + + //********************************************************************* + type_def& operator /=(const type_def& rhs) + { + value /= rhs.value; + return *this; + } + + //********************************************************************* + type_def& operator %=(TValue rhs) + { + value %= rhs; + return *this; + } + + //********************************************************************* + type_def& operator %=(const type_def& rhs) + { + value %= rhs.value; + return *this; + } + + //********************************************************************* + type_def& operator &=(TValue rhs) + { + value &= rhs; + return *this; + } + + //********************************************************************* + type_def& operator &=(const type_def& rhs) + { + value &= rhs.value; + return *this; + } + + //********************************************************************* + type_def& operator |=(TValue rhs) + { + value |= rhs; + return *this; + } + + //********************************************************************* + type_def& operator |=(const type_def& rhs) + { + value |= rhs.value; + return *this; + } + + //********************************************************************* + type_def& operator ^=(TValue rhs) + { + value ^= rhs; + return *this; + } + + //********************************************************************* + type_def& operator ^=(const type_def& rhs) + { + value ^= rhs.value; + return *this; + } + + //********************************************************************* + type_def& operator <<=(TValue rhs) + { + value <<= rhs; + return *this; + } + + //********************************************************************* + type_def& operator >>=(TValue rhs) + { + value >>= rhs; + return *this; + } + + //********************************************************************* + type_def& operator =(TValue rhs) + { + value = rhs; + return *this; + } + + //********************************************************************* + type_def& operator =(const type_def& rhs) + { + value = rhs.value; + return *this; + } + + //********************************************************************* + TValue& get() + { + return value; + } + + //********************************************************************* + const TValue& get() const + { + return value; + } + + //********************************************************************* + friend bool operator <(const type_def& lhs, const type_def& rhs) + { + return lhs.value < rhs.value; + } + + //********************************************************************* + friend bool operator <=(const type_def& lhs, const type_def& rhs) + { + return lhs.value <= rhs.value; + } + + //********************************************************************* + friend bool operator >(const type_def& lhs, const type_def& rhs) + { + return lhs.value > rhs.value; + } + + //********************************************************************* + friend bool operator >=(const type_def& lhs, const type_def& rhs) + { + return lhs.value >= rhs.value; + } + + //********************************************************************* + friend bool operator ==(const type_def& lhs, const type_def& rhs) + { + return lhs.value == rhs.value; + } + + //********************************************************************* + friend bool operator !=(const type_def& lhs, const type_def& rhs) + { + return lhs.value != rhs.value; + } + + private: + + TValue value; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/type_lookup.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,233 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_TYPE_LOOKUP__ +#define __ETL_TYPE_LOOKUP__ + +#include <limits.h> + +#include "platform.h" +#include "type_traits.h" +#include "static_assert.h" + +#undef ETL_FILE +#define ETL_FILE "41" + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +namespace etl +{ + struct null_type {}; + + //*************************************************************************** + /// The type/id pair type to use for type/id lookup template parameters. + //*************************************************************************** + template <typename T, int ID_> + struct type_id_pair + { + typedef T type; + + enum + { + ID = ID_ + }; + }; + + //*************************************************************************** + /// The type/type pair type to use for type/type lookup template parameters. + //*************************************************************************** + template <typename T1, typename T2> + struct type_type_pair + { + typedef T1 type1; + typedef T2 type2; + }; + + //*************************************************************************** + // For 16 types. + //*************************************************************************** + template <typename T1, + typename T2 = etl::type_id_pair<etl::null_type, -2>, + typename T3 = etl::type_id_pair<etl::null_type, -3>, + typename T4 = etl::type_id_pair<etl::null_type, -4>, + typename T5 = etl::type_id_pair<etl::null_type, -5>, + typename T6 = etl::type_id_pair<etl::null_type, -6>, + typename T7 = etl::type_id_pair<etl::null_type, -7>, + typename T8 = etl::type_id_pair<etl::null_type, -8>, + typename T9 = etl::type_id_pair<etl::null_type, -9>, + typename T10 = etl::type_id_pair<etl::null_type, -10>, + typename T11 = etl::type_id_pair<etl::null_type, -11>, + typename T12 = etl::type_id_pair<etl::null_type, -12>, + typename T13 = etl::type_id_pair<etl::null_type, -13>, + typename T14 = etl::type_id_pair<etl::null_type, -14>, + typename T15 = etl::type_id_pair<etl::null_type, -15>, + typename T16 = etl::type_id_pair<etl::null_type, -16> > + struct type_id_lookup + { + public: + + //************************************ + template <int ID> + struct type_from_id + { + typedef + typename etl::conditional<ID == T1::ID, typename T1::type, + typename etl::conditional<ID == T2::ID, typename T2::type, + typename etl::conditional<ID == T3::ID, typename T3::type, + typename etl::conditional<ID == T4::ID, typename T4::type, + typename etl::conditional<ID == T5::ID, typename T5::type, + typename etl::conditional<ID == T6::ID, typename T6::type, + typename etl::conditional<ID == T7::ID, typename T7::type, + typename etl::conditional<ID == T8::ID, typename T8::type, + typename etl::conditional<ID == T9::ID, typename T9::type, + typename etl::conditional<ID == T10::ID, typename T10::type, + typename etl::conditional<ID == T11::ID, typename T11::type, + typename etl::conditional<ID == T12::ID, typename T12::type, + typename etl::conditional<ID == T13::ID, typename T13::type, + typename etl::conditional<ID == T14::ID, typename T14::type, + typename etl::conditional<ID == T15::ID, typename T15::type, + typename etl::conditional<ID == T16::ID, typename T16::type, + etl::null_type>::type>::type>::type>::type> + ::type>::type>::type>::type> + ::type>::type>::type>::type> + ::type>::type>::type>::type type; + + STATIC_ASSERT(!(etl::is_same<etl::null_type, type>::value), "Invalid id"); + }; + + //************************************ + enum + { + UNKNOWN = UINT_MAX + }; + + template <typename T> + struct id_from_type + { + enum + { + value = + (unsigned int) etl::is_same<T, typename T1::type>::value ? T1::ID : + (unsigned int) etl::is_same<T, typename T2::type>::value ? T2::ID : + (unsigned int) etl::is_same<T, typename T3::type>::value ? T3::ID : + (unsigned int) etl::is_same<T, typename T4::type>::value ? T4::ID : + (unsigned int) etl::is_same<T, typename T5::type>::value ? T5::ID : + (unsigned int) etl::is_same<T, typename T6::type>::value ? T6::ID : + (unsigned int) etl::is_same<T, typename T7::type>::value ? T7::ID : + (unsigned int) etl::is_same<T, typename T8::type>::value ? T8::ID : + (unsigned int) etl::is_same<T, typename T9::type>::value ? T9::ID : + (unsigned int) etl::is_same<T, typename T10::type>::value ? T10::ID : + (unsigned int) etl::is_same<T, typename T11::type>::value ? T11::ID : + (unsigned int) etl::is_same<T, typename T12::type>::value ? T12::ID : + (unsigned int) etl::is_same<T, typename T13::type>::value ? T13::ID : + (unsigned int) etl::is_same<T, typename T14::type>::value ? T14::ID : + (unsigned int) etl::is_same<T, typename T15::type>::value ? T15::ID : + (unsigned int) etl::is_same<T, typename T16::type>::value ? T16::ID : + (unsigned int) UNKNOWN + }; + + STATIC_ASSERT(((unsigned int)value != (unsigned int)UNKNOWN), "Invalid type"); + }; + + //************************************ + template <typename T> + static unsigned int get_id_from_type(const T&) + { + return get_id_from_type<T>(); + } + + //************************************ + template <typename T> + static unsigned int get_id_from_type() + { + return id_from_type<T>::value; + } + }; + + //*************************************************************************** + // For 16 types. + //*************************************************************************** + template <typename T1, + typename T2 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T3 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T4 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T5 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T6 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T7 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T8 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T9 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T10 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T11 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T12 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T13 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T14 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T15 = etl::type_type_pair<etl::null_type, etl::null_type>, + typename T16 = etl::type_type_pair<etl::null_type, etl::null_type> > + struct type_type_lookup + { + public: + + //************************************ + template <typename T> + struct type_from_type + { + typedef + typename etl::conditional<etl::is_same<T, typename T1::type1>::value, typename T1::type2, + typename etl::conditional<etl::is_same<T, typename T2::type1>::value, typename T2::type2, + typename etl::conditional<etl::is_same<T, typename T3::type1>::value, typename T3::type2, + typename etl::conditional<etl::is_same<T, typename T4::type1>::value, typename T4::type2, + typename etl::conditional<etl::is_same<T, typename T5::type1>::value, typename T5::type2, + typename etl::conditional<etl::is_same<T, typename T6::type1>::value, typename T6::type2, + typename etl::conditional<etl::is_same<T, typename T7::type1>::value, typename T7::type2, + typename etl::conditional<etl::is_same<T, typename T8::type1>::value, typename T8::type2, + typename etl::conditional<etl::is_same<T, typename T9::type1>::value, typename T9::type2, + typename etl::conditional<etl::is_same<T, typename T10::type1>::value, typename T10::type2, + typename etl::conditional<etl::is_same<T, typename T11::type1>::value, typename T11::type2, + typename etl::conditional<etl::is_same<T, typename T12::type1>::value, typename T12::type2, + typename etl::conditional<etl::is_same<T, typename T13::type1>::value, typename T13::type2, + typename etl::conditional<etl::is_same<T, typename T14::type1>::value, typename T14::type2, + typename etl::conditional<etl::is_same<T, typename T15::type1>::value, typename T15::type2, + typename etl::conditional<etl::is_same<T, typename T16::type1>::value, typename T16::type2, + etl::null_type>::type>::type>::type>::type>::type>::type>::type>::type> + ::type>::type>::type>::type>::type>::type>::type>::type type; + + STATIC_ASSERT(!(etl::is_same<etl::null_type, type>::value), "Invalid type"); + }; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/type_lookup_generator.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,197 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_TYPE_LOOKUP__ +#define __ETL_TYPE_LOOKUP__ + +#include <limits.h> + +#include "platform.h" +#include "type_traits.h" +#include "static_assert.h" + +#undef ETL_FILE +#define ETL_FILE "41" + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +namespace etl +{ + struct null_type {}; + + //*************************************************************************** + /// The type/id pair type to use for type/id lookup template parameters. + //*************************************************************************** + template <typename T, int ID_> + struct type_id_pair + { + typedef T type; + + enum + { + ID = ID_ + }; + }; + + //*************************************************************************** + /// The type/type pair type to use for type/type lookup template parameters. + //*************************************************************************** + template <typename T1, typename T2> + struct type_type_pair + { + typedef T1 type1; + typedef T2 type2; + }; + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("// For %s types." % int(NTypes)) + cog.outl("//***************************************************************************") + cog.outl("template <typename T1,") + for n in range(2, int(NTypes)): + cog.outl(" typename T%s = etl::type_id_pair<etl::null_type, -%s>," %(n, n)) + cog.outl(" typename T%s = etl::type_id_pair<etl::null_type, -%s> >" %(NTypes, NTypes)) + cog.outl("struct type_id_lookup") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" //************************************") + cog.outl(" template <int ID>") + cog.outl(" struct type_from_id") + cog.outl(" {") + cog.outl(" typedef ") + for n in range(1, int(NTypes) + 1): + cog.outl(" typename etl::conditional<ID == T%s::ID, typename T%s::type," %(n, n)) + cog.out(" etl::null_type>") + for n in range(1, int(NTypes) + 1): + if n == int(NTypes): + cog.outl("::type type;") + else: + cog.out("::type>") + if n % 4 == 0: + if n != int(NTypes): + cog.outl("") + cog.out(" ") + cog.outl("") + cog.outl(" STATIC_ASSERT(!(etl::is_same<etl::null_type, type>::value), \"Invalid id\");") + cog.outl(" };") + cog.outl("") + cog.outl(" //************************************") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" UNKNOWN = UINT_MAX") + cog.outl(" };") + cog.outl("") + cog.outl(" template <typename T>") + cog.outl(" struct id_from_type") + cog.outl(" {") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" value =") + for n in range(1, int(NTypes) + 1) : + cog.outl(" (unsigned int) etl::is_same<T, typename T%s::type>::value ? T%s::ID :" % (n, n)) + cog.outl(" (unsigned int) UNKNOWN") + cog.outl(" };") + cog.outl("") + cog.outl(" STATIC_ASSERT(((unsigned int)value != (unsigned int)UNKNOWN), \"Invalid type\");") + cog.outl(" };") + cog.outl("") + cog.outl(" //************************************") + cog.outl(" template <typename T>") + cog.outl(" static unsigned int get_id_from_type(const T&)") + cog.outl(" {") + cog.outl(" return get_id_from_type<T>();") + cog.outl(" }") + cog.outl("") + cog.outl(" //************************************") + cog.outl(" template <typename T>") + cog.outl(" static unsigned int get_id_from_type()") + cog.outl(" {") + cog.outl(" return id_from_type<T>::value;") + cog.outl(" }") + cog.outl("};") + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// For %s types." % int(NTypes)) + cog.outl("//***************************************************************************") + cog.outl("template <typename T1,") + for n in range(2, int(NTypes)): + cog.outl(" typename T%s = etl::type_type_pair<etl::null_type, etl::null_type>," %n) + cog.outl(" typename T%s = etl::type_type_pair<etl::null_type, etl::null_type> >" %NTypes) + cog.outl("struct type_type_lookup") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" //************************************") + cog.outl(" template <typename T>") + cog.outl(" struct type_from_type") + cog.outl(" {") + cog.outl(" typedef ") + for n in range(1, int(NTypes) + 1): + cog.outl(" typename etl::conditional<etl::is_same<T, typename T%s::type1>::value, typename T%s::type2," %(n, n)) + cog.out(" etl::null_type>") + for n in range(1, int(NTypes) + 1): + if n == int(NTypes): + cog.outl("::type type;") + else: + cog.out("::type>") + if n % 8 == 0: + if n != int(NTypes): + cog.outl("") + cog.out(" ") + cog.outl("") + cog.outl(" STATIC_ASSERT(!(etl::is_same<etl::null_type, type>::value), \"Invalid type\");") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/type_traits.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,593 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -otypes.h -DHandlers=<n> types_generator.h +// Where <n> is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_TYPE_TRAITS__ +#define __ETL_TYPE_TRAITS__ + +#include <cstddef> +#include <stddef.h> +#include <stdint.h> + +#include "platform.h" +#include "nullptr.h" +#include "static_assert.h" + +#if (ETL_CPP11_SUPPORTED) + #include <type_traits> +#endif + +///\defgroup type_traits type_traits +/// A set of type traits definitions for compilers that do not support the standard header. +/// \ingroup utilities + +namespace etl +{ + /// integral_constant + ///\ingroup type_traits + template <typename T, const T VALUE> + struct integral_constant + { + static const T value = VALUE; + + typedef T value_type; + typedef integral_constant<T, VALUE> type; + + operator value_type() const + { + return value; + } + }; + + /// integral_constant specialisations + ///\ingroup type_traits + typedef integral_constant<bool, false> false_type; + typedef integral_constant<bool, true> true_type; + + /// remove_reference + ///\ingroup type_traits + template <typename T> struct remove_reference { typedef T type; }; + template <typename T> struct remove_reference<T&> { typedef T type; }; + + /// add_reference + ///\ingroup type_traits + template <typename T> struct add_reference { typedef T& type; }; + template <typename T> struct add_reference<T&> { typedef T& type; }; + + /// remove_pointer + ///\ingroup type_traits + template <typename T> struct remove_pointer { typedef T type; }; + template <typename T> struct remove_pointer<T*> { typedef T type; }; + template <typename T> struct remove_pointer<const T*> { typedef const T type; }; + template <typename T> struct remove_pointer<volatile T*> { typedef volatile T type; }; + template <typename T> struct remove_pointer<const volatile T*> { typedef const volatile T type; }; + template <typename T> struct remove_pointer<T* const> { typedef T type; }; + template <typename T> struct remove_pointer<const T* const> { typedef const T type; }; + template <typename T> struct remove_pointer<volatile T* const> { typedef volatile T type; }; + template <typename T> struct remove_pointer<const volatile T* const> { typedef const volatile T type; }; + + /// add_pointer + ///\ingroup type_traits + template <typename T> struct add_pointer { typedef typename remove_reference<T>::type* type; }; + + /// is_const + ///\ingroup type_traits + template <typename T> struct is_const : false_type {}; + template <typename T> struct is_const<const T> : true_type {}; + template <typename T> struct is_const<const volatile T> : true_type {}; + + /// remove_const + ///\ingroup type_traits + template <typename T> struct remove_const { typedef T type; }; + template <typename T> struct remove_const<const T> { typedef T type; }; + + /// add_const + ///\ingroup type_traits + template <typename T> struct add_const { typedef const T type; }; + template <typename T> struct add_const<const T> { typedef const T type; }; + + /// is_volatile + ///\ingroup type_traits + template <typename T> struct is_volatile : false_type {}; + template <typename T> struct is_volatile<volatile T> : true_type {}; + template <typename T> struct is_volatile<const volatile T> : true_type {}; + + /// remove_volatile + ///\ingroup type_traits + template <typename T> struct remove_volatile { typedef T type; }; + template <typename T> struct remove_volatile<volatile T> { typedef T type; }; + + /// add_volatile + ///\ingroup type_traits + template <typename T> struct add_volatile { typedef volatile T type; }; + template <typename T> struct add_volatile<volatile T> { typedef volatile T type; }; + + /// remove_cv + ///\ingroup type_traits + template <typename T> struct remove_cv + { + typedef typename remove_volatile<typename remove_const<T>::type>::type type; + }; + + /// add_cv + ///\ingroup type_traits + template <typename T> struct add_cv + { + typedef typename add_volatile<typename add_const<T>::type>::type type; + }; + + /// is_integral + ///\ingroup type_traits + template <typename T> struct is_integral : false_type {}; + template <> struct is_integral<bool> : true_type {}; + template <> struct is_integral<char> : true_type {}; + template <> struct is_integral<unsigned char> : true_type {}; + template <> struct is_integral<signed char> : true_type {}; + template <> struct is_integral<wchar_t> : true_type {}; + template <> struct is_integral<short> : true_type {}; + template <> struct is_integral<unsigned short> : true_type {}; + template <> struct is_integral<int> : true_type {}; + template <> struct is_integral<unsigned int> : true_type {}; + template <> struct is_integral<long> : true_type {}; + template <> struct is_integral<unsigned long> : true_type {}; + template <> struct is_integral<long long> : true_type {}; + template <> struct is_integral<unsigned long long> : true_type {}; + template <typename T> struct is_integral<const T> : is_integral<T> {}; + template <typename T> struct is_integral<volatile T> : is_integral<T> {}; + template <typename T> struct is_integral<const volatile T> : is_integral<T> {}; + + /// is_signed + ///\ingroup type_traits + template <typename T> struct is_signed : false_type {}; + template <> struct is_signed<char> : integral_constant<bool, (char(255) < 0)> {}; + template <> struct is_signed<wchar_t> : public etl::integral_constant<bool, static_cast<bool>(wchar_t(-1) < wchar_t(0))> {}; + template <> struct is_signed<signed char> : true_type {}; + template <> struct is_signed<short> : true_type {}; + template <> struct is_signed<int> : true_type {}; + template <> struct is_signed<long> : true_type {}; + template <> struct is_signed<long long> : true_type {}; + template <> struct is_signed<float> : true_type{}; + template <> struct is_signed<double> : true_type{}; + template <> struct is_signed<long double> : true_type{}; + template <typename T> struct is_signed<const T> : is_signed<T> {}; + template <typename T> struct is_signed<volatile T> : is_signed<T> {}; + template <typename T> struct is_signed<const volatile T> : is_signed<T> {}; + + /// is_unsigned + ///\ingroup type_traits + template <typename T> struct is_unsigned : false_type {}; + template <> struct is_unsigned<bool> : true_type {}; + template <> struct is_unsigned<char> : integral_constant<bool, (char(255) > 0)> {}; + template <> struct is_unsigned<unsigned char> : true_type {}; + template <> struct is_unsigned<wchar_t> : public etl::integral_constant<bool, (wchar_t(-1) > wchar_t(0))> {}; + template <> struct is_unsigned<unsigned short> : true_type {}; + template <> struct is_unsigned<unsigned int> : true_type {}; + template <> struct is_unsigned<unsigned long> : true_type {}; + template <> struct is_unsigned<unsigned long long> : true_type {}; + template <typename T> struct is_unsigned<const T> : is_unsigned<T> {}; + template <typename T> struct is_unsigned<volatile T> : is_unsigned<T> {}; + template <typename T> struct is_unsigned<const volatile T> : is_unsigned<T> {}; + + /// is_floating_point + ///\ingroup type_traits + template <typename T> struct is_floating_point : false_type {}; + template <> struct is_floating_point<float> : true_type {}; + template <> struct is_floating_point<double> : true_type {}; + template <> struct is_floating_point<long double> : true_type {}; + template <typename T> struct is_floating_point<const T> : is_floating_point<T> {}; + template <typename T> struct is_floating_point<volatile T> : is_floating_point<T> {}; + template <typename T> struct is_floating_point<const volatile T> : is_floating_point<T> {}; + + /// is_same + ///\ingroup type_traits + template <typename T1, typename T2> struct is_same : public false_type {}; + template <typename T> struct is_same<T, T> : public true_type {}; + + /// is_void + ///\ingroup type_traits + template<typename T> struct is_void : false_type {}; + template<> struct is_void<void> : true_type {}; + + /// is_arithmetic + ///\ingroup type_traits + template<typename T> struct is_arithmetic : integral_constant<bool, is_integral<T>::value || is_floating_point<T>::value> {}; + + /// is_fundamental + ///\ingroup type_traits + template <typename T> struct is_fundamental : integral_constant<bool, is_arithmetic<T>::value || + is_void<T>::value || + is_same<std::nullptr_t, + typename remove_cv<T>::type>::value> {}; + + /// is_compound + ///\ingroup type_traits + template <typename T> struct is_compound : integral_constant<bool, !is_fundamental<T>::value> {}; + + /// is_array + ///\ingroup type_traits + template <typename T> struct is_array : false_type {}; + template <typename T> struct is_array<T[]> : true_type {}; + template <typename T, size_t MAXN> struct is_array<T[MAXN]> : true_type {}; + + /// is_pointer + ///\ingroup type_traits + template <typename T> struct is_pointer : false_type {}; + template <typename T> struct is_pointer<T*> : true_type {}; + + /// is_reference + ///\ingroup type_traits + template <typename T> struct is_reference : false_type {}; + template <typename T> struct is_reference<T&> : true_type {}; + + /// is_pod + /// For C++03, only fundamental and pointers types are recognised. + ///\ingroup type_traits +#if (ETL_CPP11_SUPPORTED && !defined(ARDUINO)) && !defined(ETL_IN_UNIT_TEST) + // For compilers that support C++11 + template <typename T> struct is_pod : std::is_pod<T> {}; +#else + template <typename T> struct is_pod : etl::integral_constant<bool, etl::is_fundamental<T>::value || etl::is_pointer<T>::value> {}; +#endif + +#if (ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED) && !defined(ETL_IN_UNIT_TEST) + /// is_trivially_constructible + ///\ingroup type_traits + template <typename T> struct is_trivially_constructible : std::is_trivially_constructible<T> {}; + + /// is_trivially_copy_constructible + ///\ingroup type_traits + template <typename T> struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> {}; + + /// is_trivially_destructible + ///\ingroup type_traits + template <typename T> struct is_trivially_destructible : std::is_trivially_destructible<T> {}; + + /// is_trivially_copy_assignable + ///\ingroup type_traits + template <typename T> struct is_trivially_copy_assignable : std::is_trivially_copy_assignable<T> {}; +#else + /// is_trivially_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template <typename T> struct is_trivially_constructible : etl::is_pod<T> {}; + + /// is_trivially_copy_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template <typename T> struct is_trivially_copy_constructible : etl::is_pod<T> {}; + + /// is_trivially_destructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template <typename T> struct is_trivially_destructible : etl::is_pod<T> {}; + + /// is_trivially_copy_assignable + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template <typename T> struct is_trivially_copy_assignable : etl::is_pod<T> {}; +#endif + + /// conditional + ///\ingroup type_traits + template <bool B, typename T, typename F> struct conditional { typedef T type; }; + template <typename T, typename F> struct conditional<false, T, F> { typedef F type; }; + + /// conditional_integral_constant + ///\ingroup type_traits + template <bool B, typename T, T TRUE_VALUE, T FALSE_VALUE> + struct conditional_integral_constant; + + template <typename T, T TRUE_VALUE, T FALSE_VALUE> + struct conditional_integral_constant<true, T, TRUE_VALUE, FALSE_VALUE> + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + static const T value = TRUE_VALUE; + }; + + template <typename T, T TRUE_VALUE, T FALSE_VALUE> + struct conditional_integral_constant<false, T, TRUE_VALUE, FALSE_VALUE> + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + static const T value = FALSE_VALUE; + }; + + /// make_signed + ///\ingroup type_traits + template <typename T> struct make_signed { typedef T type; }; + template <> struct make_signed<char> { typedef signed char type; }; + template <> struct make_signed<unsigned char> { typedef signed char type; }; + + template <> struct make_signed<wchar_t> + { + typedef etl::conditional<sizeof(wchar_t) == sizeof(int16_t), + int16_t, + etl::conditional<sizeof(wchar_t) == sizeof(int32_t), + int32_t, + void>::type>::type type; + }; + + template <> struct make_signed<unsigned short> { typedef short type; }; + template <> struct make_signed<unsigned int> { typedef int type; }; + template <> struct make_signed<unsigned long> { typedef long type; }; + template <> struct make_signed<unsigned long long> { typedef long long type; }; + template <typename T> struct make_signed<const T> : add_const<typename make_signed<T>::type> {}; + template <typename T> struct make_signed<volatile T> : add_volatile<typename make_signed<T>::type> {}; + template <typename T> struct make_signed<const volatile T> : add_const<typename add_volatile<typename make_signed<T>::type>::type> {}; + + /// make_unsigned + ///\ingroup type_traits + template <typename T> struct make_unsigned { typedef T type; }; + template <> struct make_unsigned<char> { typedef unsigned char type; }; + template <> struct make_unsigned<signed char> { typedef unsigned char type; }; + template <> struct make_unsigned<short> { typedef unsigned short type; }; + + template <> struct make_unsigned<wchar_t> + { + typedef etl::conditional<sizeof(wchar_t) == sizeof(uint16_t), + uint16_t, + etl::conditional<sizeof(wchar_t) == sizeof(uint32_t), + uint32_t, + void>::type>::type type; + }; + + template <> struct make_unsigned<int> { typedef unsigned int type; }; + template <> struct make_unsigned<long> { typedef unsigned long type; }; + template <> struct make_unsigned<long long> { typedef unsigned long long type; }; + template <typename T> struct make_unsigned<const T> : add_const<typename make_unsigned<T>::type> {}; + template <typename T> struct make_unsigned<volatile T> : add_volatile<typename make_unsigned<T>::type> {}; + template <typename T> struct make_unsigned<const volatile T> : add_const<typename add_volatile<typename make_unsigned<T>::type>::type> {}; + + /// enable_if + ///\ingroup type_traits + template <bool B, typename T = void> struct enable_if {}; + template <typename T> struct enable_if<true, T> { typedef T type; }; + + /// extent + ///\ingroup type_traits + template <typename T, size_t MAXN = 0> + struct extent : integral_constant<size_t, 0> {}; + + template <typename T> + struct extent<T[], 0> : integral_constant<size_t, 0> {}; + + template <typename T, size_t MAXN> + struct extent<T[], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {}; + + template <typename T, size_t MAXN> + struct extent<T[MAXN], 0> : integral_constant<size_t, MAXN> {}; + + template <typename T, size_t I, size_t MAXN> + struct extent<T[I], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {}; + + /// remove_extent + ///\ingroup type_traits + template <typename T> struct remove_extent { typedef T type; }; + template <typename T> struct remove_extent<T[]> { typedef T type; }; + template <typename T, size_t MAXN> struct remove_extent<T[MAXN]> { typedef T type;}; + + /// remove_all_extents + ///\ingroup type_traits + template <typename T> struct remove_all_extents { typedef T type;}; + template <typename T> struct remove_all_extents<T[]> { typedef typename remove_all_extents<T>::type type; }; + template <typename T, size_t MAXN> struct remove_all_extents<T[MAXN]> { typedef typename remove_all_extents<T>::type type; }; + + /// rank + ///\ingroup type_traits + template <typename T>struct rank : integral_constant<size_t, 0> {}; + template <typename T> struct rank<T[]> : public integral_constant<size_t, rank<T>::value + 1> {}; + template <typename T, size_t MAXN> struct rank<T[MAXN]> : public integral_constant<size_t, rank<T>::value + 1> {}; + + /// decay + ///\ingroup type_traits + template <typename T> + struct decay + { + typedef typename etl::remove_reference<T>::type U; + typedef typename etl::conditional<etl::is_array<U>::value, + typename etl::remove_extent<U>::type*, + typename etl::remove_cv<U>::type>::type type; + }; + + /// is_base_of + ///\ingroup type_traits + template<typename TBase, + typename TDerived, + const bool IsFundamental = (etl::is_fundamental<TBase>::value || etl::is_fundamental<TDerived>::value)> + struct is_base_of + { + private: + + template<typename T> struct dummy {}; + struct internal: TDerived, dummy<int>{}; + + static TBase* check(TBase*); + template<typename T> static char check(dummy<T>*); + + public: + + static const bool value = (sizeof(check((internal*)0)) == sizeof(TBase*)); + }; + + // For when TBase or TDerived is a fundamental type. + template<typename TBase, typename TDerived> + struct is_base_of<TBase, TDerived, true> + { + static const bool value = false; + }; + + /// Alignment templates. + /// These require compiler specific intrinsics. + ///\ingroup type_traits +#ifdef ETL_COMPILER_MICROSOFT + template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof(T))> {}; + +#elif defined(ETL_COMPILER_IAR) || defined(ETL_COMPILER_TI) + template <typename T> struct alignment_of : integral_constant<size_t, size_t(__ALIGNOF__(T))> {}; + +#else + template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof__(T))> {}; + +#endif + + /// Specialisation of 'alignment_of' for 'void'. + ///\ingroup type_traits + template <> struct alignment_of<void> : integral_constant <size_t, 0>{}; + + //*************************************************************************** + /// Template to determine if a type is one of a specified list. + ///\ingroup types + //*************************************************************************** + template <typename T, + typename T1, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void, + typename T17 = void> + struct is_one_of + { + static const bool value = + etl::is_same<T, T1>::value || + etl::is_same<T, T2>::value || + etl::is_same<T, T3>::value || + etl::is_same<T, T4>::value || + etl::is_same<T, T5>::value || + etl::is_same<T, T6>::value || + etl::is_same<T, T7>::value || + etl::is_same<T, T8>::value || + etl::is_same<T, T9>::value || + etl::is_same<T, T10>::value || + etl::is_same<T, T11>::value || + etl::is_same<T, T12>::value || + etl::is_same<T, T13>::value || + etl::is_same<T, T14>::value || + etl::is_same<T, T15>::value || + etl::is_same<T, T16>::value || + etl::is_same<T, T17>::value; + }; + + //*************************************************************************** + // A set of templates to allow related types to be derived. + //*************************************************************************** + // Default. + template <typename T> + struct types + { + private: + + typedef typename etl::remove_cv<T>::type type_t; + + public: + + typedef type_t type; + typedef type_t& reference; + typedef const type_t& const_reference; + typedef type_t* pointer; + typedef const type_t* const_pointer; + typedef const type_t* const const_pointer_const; + }; + + // Pointers. + template <typename T> + struct types<T*> + { + private: + + typedef typename etl::remove_cv<T>::type type_t; + + public: + + typedef type_t type; + typedef type_t& reference; + typedef const type_t& const_reference; + typedef type_t* pointer; + typedef const type_t* const_pointer; + typedef const type_t* const const_pointer_const; + }; + + // Pointers. + template <typename T> + struct types<T* const> + { + private: + + typedef typename etl::remove_cv<T>::type type_t; + + public: + + typedef type_t type; + typedef type_t& reference; + typedef const type_t& const_reference; + typedef type_t* pointer; + typedef const type_t* const_pointer; + typedef const type_t* const const_pointer_const; + }; + + // References. + template <typename T> + struct types<T&> + { + private: + + typedef typename etl::remove_cv<T>::type type_t; + + public: + + typedef type_t type; + typedef type_t& reference; + typedef const type_t& const_reference; + typedef type_t* pointer; + typedef const type_t* const_pointer; + typedef const type_t* const const_pointer_const; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/type_traits_generator.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,597 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -otypes.h -DHandlers=<n> types_generator.h +// Where <n> is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_TYPE_TRAITS__ +#define __ETL_TYPE_TRAITS__ + +#include <stddef.h> +#include <stdint.h> + +#include "platform.h" +#include "nullptr.h" +#include "static_assert.h" + +#if (ETL_CPP11_SUPPORTED) + #include <type_traits> +#endif + +///\defgroup type_traits type_traits +/// A set of type traits definitions for compilers that do not support the standard header. +/// \ingroup utilities + +namespace etl +{ + /// integral_constant + ///\ingroup type_traits + template <typename T, const T VALUE> + struct integral_constant + { + static const T value = VALUE; + + typedef T value_type; + typedef integral_constant<T, VALUE> type; + + operator value_type() const + { + return value; + } + }; + + /// integral_constant specialisations + ///\ingroup type_traits + typedef integral_constant<bool, false> false_type; + typedef integral_constant<bool, true> true_type; + + /// remove_reference + ///\ingroup type_traits + template <typename T> struct remove_reference { typedef T type; }; + template <typename T> struct remove_reference<T&> { typedef T type; }; + + /// add_reference + ///\ingroup type_traits + template <typename T> struct add_reference { typedef T& type; }; + template <typename T> struct add_reference<T&> { typedef T& type; }; + + /// remove_pointer + ///\ingroup type_traits + template <typename T> struct remove_pointer { typedef T type; }; + template <typename T> struct remove_pointer<T*> { typedef T type; }; + template <typename T> struct remove_pointer<const T*> { typedef const T type; }; + template <typename T> struct remove_pointer<volatile T*> { typedef volatile T type; }; + template <typename T> struct remove_pointer<const volatile T*> { typedef const volatile T type; }; + template <typename T> struct remove_pointer<T* const> { typedef T type; }; + template <typename T> struct remove_pointer<const T* const> { typedef const T type; }; + template <typename T> struct remove_pointer<volatile T* const> { typedef volatile T type; }; + template <typename T> struct remove_pointer<const volatile T* const> { typedef const volatile T type; }; + + /// add_pointer + ///\ingroup type_traits + template <typename T> struct add_pointer { typedef typename remove_reference<T>::type* type; }; + + /// is_const + ///\ingroup type_traits + template <typename T> struct is_const : false_type {}; + template <typename T> struct is_const<const T> : true_type {}; + template <typename T> struct is_const<const volatile T> : true_type {}; + + /// remove_const + ///\ingroup type_traits + template <typename T> struct remove_const { typedef T type; }; + template <typename T> struct remove_const<const T> { typedef T type; }; + + /// add_const + ///\ingroup type_traits + template <typename T> struct add_const { typedef const T type; }; + template <typename T> struct add_const<const T> { typedef const T type; }; + + /// is_volatile + ///\ingroup type_traits + template <typename T> struct is_volatile : false_type {}; + template <typename T> struct is_volatile<volatile T> : true_type {}; + template <typename T> struct is_volatile<const volatile T> : true_type {}; + + /// remove_volatile + ///\ingroup type_traits + template <typename T> struct remove_volatile { typedef T type; }; + template <typename T> struct remove_volatile<volatile T> { typedef T type; }; + + /// add_volatile + ///\ingroup type_traits + template <typename T> struct add_volatile { typedef volatile T type; }; + template <typename T> struct add_volatile<volatile T> { typedef volatile T type; }; + + /// remove_cv + ///\ingroup type_traits + template <typename T> struct remove_cv + { + typedef typename remove_volatile<typename remove_const<T>::type>::type type; + }; + + /// add_cv + ///\ingroup type_traits + template <typename T> struct add_cv + { + typedef typename add_volatile<typename add_const<T>::type>::type type; + }; + + /// is_integral + ///\ingroup type_traits + template <typename T> struct is_integral : false_type {}; + template <> struct is_integral<bool> : true_type {}; + template <> struct is_integral<char> : true_type {}; + template <> struct is_integral<unsigned char> : true_type {}; + template <> struct is_integral<signed char> : true_type {}; + template <> struct is_integral<wchar_t> : true_type {}; + template <> struct is_integral<short> : true_type {}; + template <> struct is_integral<unsigned short> : true_type {}; + template <> struct is_integral<int> : true_type {}; + template <> struct is_integral<unsigned int> : true_type {}; + template <> struct is_integral<long> : true_type {}; + template <> struct is_integral<unsigned long> : true_type {}; + template <> struct is_integral<long long> : true_type {}; + template <> struct is_integral<unsigned long long> : true_type {}; + template <typename T> struct is_integral<const T> : is_integral<T> {}; + template <typename T> struct is_integral<volatile T> : is_integral<T> {}; + template <typename T> struct is_integral<const volatile T> : is_integral<T> {}; + + /// is_signed + ///\ingroup type_traits + template <typename T> struct is_signed : false_type {}; + template <> struct is_signed<char> : integral_constant<bool, (char(255) < 0)> {}; + template <> struct is_signed<wchar_t> : public etl::integral_constant<bool, static_cast<bool>(wchar_t(-1) < wchar_t(0))> {}; + template <> struct is_signed<signed char> : true_type {}; + template <> struct is_signed<short> : true_type {}; + template <> struct is_signed<int> : true_type {}; + template <> struct is_signed<long> : true_type {}; + template <> struct is_signed<long long> : true_type {}; + template <> struct is_signed<float> : true_type{}; + template <> struct is_signed<double> : true_type{}; + template <> struct is_signed<long double> : true_type{}; + template <typename T> struct is_signed<const T> : is_signed<T> {}; + template <typename T> struct is_signed<volatile T> : is_signed<T> {}; + template <typename T> struct is_signed<const volatile T> : is_signed<T> {}; + + /// is_unsigned + ///\ingroup type_traits + template <typename T> struct is_unsigned : false_type {}; + template <> struct is_unsigned<bool> : true_type {}; + template <> struct is_unsigned<char> : integral_constant<bool, (char(255) > 0)> {}; + template <> struct is_unsigned<unsigned char> : true_type {}; + template <> struct is_unsigned<wchar_t> : public etl::integral_constant<bool, (wchar_t(-1) > wchar_t(0))> {}; + template <> struct is_unsigned<unsigned short> : true_type {}; + template <> struct is_unsigned<unsigned int> : true_type {}; + template <> struct is_unsigned<unsigned long> : true_type {}; + template <> struct is_unsigned<unsigned long long> : true_type {}; + template <typename T> struct is_unsigned<const T> : is_unsigned<T> {}; + template <typename T> struct is_unsigned<volatile T> : is_unsigned<T> {}; + template <typename T> struct is_unsigned<const volatile T> : is_unsigned<T> {}; + + /// is_floating_point + ///\ingroup type_traits + template <typename T> struct is_floating_point : false_type {}; + template <> struct is_floating_point<float> : true_type {}; + template <> struct is_floating_point<double> : true_type {}; + template <> struct is_floating_point<long double> : true_type {}; + template <typename T> struct is_floating_point<const T> : is_floating_point<T> {}; + template <typename T> struct is_floating_point<volatile T> : is_floating_point<T> {}; + template <typename T> struct is_floating_point<const volatile T> : is_floating_point<T> {}; + + /// is_same + ///\ingroup type_traits + template <typename T1, typename T2> struct is_same : public false_type {}; + template <typename T> struct is_same<T, T> : public true_type {}; + + /// is_void + ///\ingroup type_traits + template<typename T> struct is_void : false_type {}; + template<> struct is_void<void> : true_type {}; + + /// is_arithmetic + ///\ingroup type_traits + template<typename T> struct is_arithmetic : integral_constant<bool, is_integral<T>::value || is_floating_point<T>::value> {}; + + /// is_fundamental + ///\ingroup type_traits + template <typename T> struct is_fundamental : integral_constant<bool, is_arithmetic<T>::value || + is_void<T>::value || + is_same<std::nullptr_t, + typename remove_cv<T>::type>::value> {}; + + /// is_compound + ///\ingroup type_traits + template <typename T> struct is_compound : integral_constant<bool, !is_fundamental<T>::value> {}; + + /// is_array + ///\ingroup type_traits + template <typename T> struct is_array : false_type {}; + template <typename T> struct is_array<T[]> : true_type {}; + template <typename T, size_t MAXN> struct is_array<T[MAXN]> : true_type {}; + + /// is_pointer + ///\ingroup type_traits + template <typename T> struct is_pointer : false_type {}; + template <typename T> struct is_pointer<T*> : true_type {}; + + /// is_reference + ///\ingroup type_traits + template <typename T> struct is_reference : false_type {}; + template <typename T> struct is_reference<T&> : true_type {}; + + /// is_pod + /// For C++03, only fundamental and pointers types are recognised. + ///\ingroup type_traits +#if (ETL_CPP11_SUPPORTED && !defined(ARDUINO)) && !defined(ETL_IN_UNIT_TEST) + // For compilers that support C++11 + template <typename T> struct is_pod : std::is_pod<T> {}; +#else + template <typename T> struct is_pod : etl::integral_constant<bool, etl::is_fundamental<T>::value || etl::is_pointer<T>::value> {}; +#endif + +#if (ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED) && !defined(ETL_IN_UNIT_TEST) + /// is_trivially_constructible + ///\ingroup type_traits + template <typename T> struct is_trivially_constructible : std::is_trivially_constructible<T> {}; + + /// is_trivially_copy_constructible + ///\ingroup type_traits + template <typename T> struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T> {}; + + /// is_trivially_destructible + ///\ingroup type_traits + template <typename T> struct is_trivially_destructible : std::is_trivially_destructible<T> {}; + + /// is_trivially_copy_assignable + ///\ingroup type_traits + template <typename T> struct is_trivially_copy_assignable : std::is_trivially_copy_assignable<T> {}; +#else + /// is_trivially_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template <typename T> struct is_trivially_constructible : etl::is_pod<T> {}; + + /// is_trivially_copy_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template <typename T> struct is_trivially_copy_constructible : etl::is_pod<T> {}; + + /// is_trivially_destructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template <typename T> struct is_trivially_destructible : etl::is_pod<T> {}; + + /// is_trivially_copy_assignable + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template <typename T> struct is_trivially_copy_assignable : etl::is_pod<T> {}; +#endif + + /// conditional + ///\ingroup type_traits + template <bool B, typename T, typename F> struct conditional { typedef T type; }; + template <typename T, typename F> struct conditional<false, T, F> { typedef F type; }; + + /// conditional_integral_constant + ///\ingroup type_traits + template <bool B, typename T, T TRUE_VALUE, T FALSE_VALUE> + struct conditional_integral_constant; + + template <typename T, T TRUE_VALUE, T FALSE_VALUE> + struct conditional_integral_constant<true, T, TRUE_VALUE, FALSE_VALUE> + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + static const T value = TRUE_VALUE; + }; + + template <typename T, T TRUE_VALUE, T FALSE_VALUE> + struct conditional_integral_constant<false, T, TRUE_VALUE, FALSE_VALUE> + { + STATIC_ASSERT(etl::is_integral<T>::value, "Not an integral type"); + static const T value = FALSE_VALUE; + }; + + /// make_signed + ///\ingroup type_traits + template <typename T> struct make_signed { typedef T type; }; + template <> struct make_signed<char> { typedef signed char type; }; + template <> struct make_signed<unsigned char> { typedef signed char type; }; + + template <> struct make_signed<wchar_t> + { + typedef etl::conditional<sizeof(wchar_t) == sizeof(int16_t), + int16_t, + etl::conditional<sizeof(wchar_t) == sizeof(int32_t), + int32_t, + void>::type>::type type; + }; + + template <> struct make_signed<unsigned short> { typedef short type; }; + template <> struct make_signed<unsigned int> { typedef int type; }; + template <> struct make_signed<unsigned long> { typedef long type; }; + template <> struct make_signed<unsigned long long> { typedef long long type; }; + template <typename T> struct make_signed<const T> : add_const<typename make_signed<T>::type> {}; + template <typename T> struct make_signed<volatile T> : add_volatile<typename make_signed<T>::type> {}; + template <typename T> struct make_signed<const volatile T> : add_const<typename add_volatile<typename make_signed<T>::type>::type> {}; + + /// make_unsigned + ///\ingroup type_traits + template <typename T> struct make_unsigned { typedef T type; }; + template <> struct make_unsigned<char> { typedef unsigned char type; }; + template <> struct make_unsigned<signed char> { typedef unsigned char type; }; + template <> struct make_unsigned<short> { typedef unsigned short type; }; + + template <> struct make_unsigned<wchar_t> + { + typedef etl::conditional<sizeof(wchar_t) == sizeof(uint16_t), + uint16_t, + etl::conditional<sizeof(wchar_t) == sizeof(uint32_t), + uint32_t, + void>::type>::type type; + }; + + template <> struct make_unsigned<int> { typedef unsigned int type; }; + template <> struct make_unsigned<long> { typedef unsigned long type; }; + template <> struct make_unsigned<long long> { typedef unsigned long long type; }; + template <typename T> struct make_unsigned<const T> : add_const<typename make_unsigned<T>::type> {}; + template <typename T> struct make_unsigned<volatile T> : add_volatile<typename make_unsigned<T>::type> {}; + template <typename T> struct make_unsigned<const volatile T> : add_const<typename add_volatile<typename make_unsigned<T>::type>::type> {}; + + /// enable_if + ///\ingroup type_traits + template <bool B, typename T = void> struct enable_if {}; + template <typename T> struct enable_if<true, T> { typedef T type; }; + + /// extent + ///\ingroup type_traits + template <typename T, size_t MAXN = 0> + struct extent : integral_constant<size_t, 0> {}; + + template <typename T> + struct extent<T[], 0> : integral_constant<size_t, 0> {}; + + template <typename T, size_t MAXN> + struct extent<T[], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {}; + + template <typename T, size_t MAXN> + struct extent<T[MAXN], 0> : integral_constant<size_t, MAXN> {}; + + template <typename T, size_t I, size_t MAXN> + struct extent<T[I], MAXN> : integral_constant<size_t, extent<T, MAXN - 1>::value> {}; + + /// remove_extent + ///\ingroup type_traits + template <typename T> struct remove_extent { typedef T type; }; + template <typename T> struct remove_extent<T[]> { typedef T type; }; + template <typename T, size_t MAXN> struct remove_extent<T[MAXN]> { typedef T type;}; + + /// remove_all_extents + ///\ingroup type_traits + template <typename T> struct remove_all_extents { typedef T type;}; + template <typename T> struct remove_all_extents<T[]> { typedef typename remove_all_extents<T>::type type; }; + template <typename T, size_t MAXN> struct remove_all_extents<T[MAXN]> { typedef typename remove_all_extents<T>::type type; }; + + /// rank + ///\ingroup type_traits + template <typename T>struct rank : integral_constant<size_t, 0> {}; + template <typename T> struct rank<T[]> : public integral_constant<size_t, rank<T>::value + 1> {}; + template <typename T, size_t MAXN> struct rank<T[MAXN]> : public integral_constant<size_t, rank<T>::value + 1> {}; + + /// decay + ///\ingroup type_traits + template <typename T> + struct decay + { + typedef typename etl::remove_reference<T>::type U; + typedef typename etl::conditional<etl::is_array<U>::value, + typename etl::remove_extent<U>::type*, + typename etl::remove_cv<U>::type>::type type; + }; + + /// is_base_of + ///\ingroup type_traits + template<typename TBase, + typename TDerived, + const bool IsFundamental = (etl::is_fundamental<TBase>::value || etl::is_fundamental<TDerived>::value)> + struct is_base_of + { + private: + + template<typename T> struct dummy {}; + struct internal: TDerived, dummy<int>{}; + + static TBase* check(TBase*); + template<typename T> static char check(dummy<T>*); + + public: + + static const bool value = (sizeof(check((internal*)0)) == sizeof(TBase*)); + }; + + // For when TBase or TDerived is a fundamental type. + template<typename TBase, typename TDerived> + struct is_base_of<TBase, TDerived, true> + { + static const bool value = false; + }; + + /// Alignment templates. + /// These require compiler specific intrinsics. + ///\ingroup type_traits +#ifdef ETL_COMPILER_MICROSOFT + template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof(T))> {}; + +#elif defined(ETL_COMPILER_IAR) || defined(ETL_COMPILER_TI) + template <typename T> struct alignment_of : integral_constant<size_t, size_t(__ALIGNOF__(T))> {}; + +#else + template <typename T> struct alignment_of : integral_constant<size_t, size_t(__alignof__(T))> {}; + +#endif + + /// Specialisation of 'alignment_of' for 'void'. + ///\ingroup type_traits + template <> struct alignment_of<void> : integral_constant <size_t, 0>{}; + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine if a type is one of a specified list.") + cog.outl("///\ingroup types") + cog.outl("//***************************************************************************") + cog.outl("template <typename T,") + cog.out(" ") + cog.out("typename T1, ") + for n in range(2, int(IsOneOf)): + cog.out("typename T%s = void, " % n) + if n % 4 == 0: + cog.outl("") + cog.out(" ") + cog.outl("typename T%s = void>" % IsOneOf) + cog.outl("struct is_one_of") + cog.outl("{") + cog.outl(" static const bool value = ") + for n in range(1, int(IsOneOf)): + cog.outl(" etl::is_same<T, T%s>::value ||" % n) + cog.outl(" etl::is_same<T, T%s>::value;" % IsOneOf) + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + //*************************************************************************** + // A set of templates to allow related types to be derived. + //*************************************************************************** + // Default. + template <typename T> + struct types + { + private: + + typedef typename etl::remove_cv<T>::type type_t; + + public: + + typedef type_t type; + typedef type_t& reference; + typedef const type_t& const_reference; + typedef type_t* pointer; + typedef const type_t* const_pointer; + typedef const type_t* const const_pointer_const; + }; + + // Pointers. + template <typename T> + struct types<T*> + { + private: + + typedef typename etl::remove_cv<T>::type type_t; + + public: + + typedef type_t type; + typedef type_t& reference; + typedef const type_t& const_reference; + typedef type_t* pointer; + typedef const type_t* const_pointer; + typedef const type_t* const const_pointer_const; + }; + + // Pointers. + template <typename T> + struct types<T* const> + { + private: + + typedef typename etl::remove_cv<T>::type type_t; + + public: + + typedef type_t type; + typedef type_t& reference; + typedef const type_t& const_reference; + typedef type_t* pointer; + typedef const type_t* const_pointer; + typedef const type_t* const const_pointer_const; + }; + + // References. + template <typename T> + struct types<T&> + { + private: + + typedef typename etl::remove_cv<T>::type type_t; + + public: + + typedef type_t type; + typedef type_t& reference; + typedef const type_t& const_reference; + typedef type_t* pointer; + typedef const type_t* const_pointer; + typedef const type_t* const const_pointer_const; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/u16string.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,224 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_U16STRING__ +#define __ETL_U16STRING__ + +#include "platform.h" +#include "basic_string.h" +#include "hash.h" + +#if defined(ETL_COMPILER_MICROSOFT) + #undef min +#endif + +namespace etl +{ + typedef ibasic_string<char16_t> iu16string; + + //*************************************************************************** + /// A u16string implementation that uses a fixed size buffer. + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup u16string + //*************************************************************************** + template <const size_t MAX_SIZE_> + class u16string : public iu16string + { + public: + + typedef iu16string::value_type value_type; + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + u16string() + : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu16string::initialise(); + } + + //************************************************************************* + /// Copy constructor. + ///\param other The other string. + //************************************************************************* + u16string(const etl::u16string<MAX_SIZE_>& other) + : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu16string::initialise(); + iu16string::assign(other.begin(), other.end()); + } + + //************************************************************************* + /// From other string, position, length. + ///\param other The other string. + ///\param position The position of the first character. + ///\param length The number of characters. Default = npos. + //************************************************************************* + u16string(const etl::u16string<MAX_SIZE_>& other, size_t position, size_t length_ = npos) + : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds)); + + // Set the length to the exact amount. + length_ = (length_ > MAX_SIZE_) ? MAX_SIZE_ : length_; + + iu16string::initialise(); + iu16string::assign(other.begin() + position, other.begin() + position + length_); + } + + //************************************************************************* + /// Constructor, from null terminated text. + ///\param text The initial text of the u16string. + //************************************************************************* + u16string(const value_type* text) + : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu16string::initialise(); + iu16string::assign(text, text + etl::char_traits<value_type>::length(text)); + } + + //************************************************************************* + /// Constructor, from null terminated text and count. + ///\param text The initial text of the u16string. + ///\param count The number of characters to copy. + //************************************************************************* + u16string(const value_type* text, size_t count) + : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu16string::initialise(); + iu16string::assign(text, text + count); + } + + //************************************************************************* + /// Constructor, from initial size and value. + ///\param initialSize The initial size of the u16string. + ///\param value The value to fill the u16string with. + //************************************************************************* + u16string(size_t count, value_type c) + : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu16string::initialise(); + iu16string::resize(count, c); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + u16string(TIterator first, TIterator last) + : iu16string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu16string::assign(first, last); + } + + //************************************************************************* + /// Returns a sub-string. + ///\param position The position of the first character. Default = 0. + ///\param length The number of characters. Default = npos. + //************************************************************************* + etl::u16string<MAX_SIZE_> substr(size_t position = 0, size_t length_ = npos) const + { + etl::u16string<MAX_SIZE_> new_string; + + if (position != size()) + { + ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds)); + + length_ = std::min(length_, size() - position); + + new_string.assign(buffer + position, buffer + position + length_); + } + + return new_string; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + u16string& operator = (const u16string& rhs) + { + if (&rhs != this) + { + iu16string::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair() + { + etl::iu16string::repair(buffer); + } + + private: + + value_type buffer[MAX_SIZE + 1]; + }; + + //************************************************************************* + /// Hash function. + //************************************************************************* +#if ETL_8BIT_SUPPORT + template <> + struct hash<etl::iu16string> + { + size_t operator()(const etl::iu16string& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; + + template <const size_t SIZE> + struct hash<etl::u16string<SIZE> > + { + size_t operator()(const etl::u16string<SIZE>& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; +#endif +} + +#if defined(ETL_COMPILER_MICROSOFT) + #define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/u32string.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,224 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_U32STRING__ +#define __ETL_U32STRING__ + +#include "platform.h" +#include "basic_string.h" +#include "hash.h" + +#if defined(ETL_COMPILER_MICROSOFT) + #undef min +#endif + +namespace etl +{ + typedef ibasic_string<char32_t> iu32string; + + //*************************************************************************** + /// A u32string implementation that uses a fixed size buffer. + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup u32string + //*************************************************************************** + template <const size_t MAX_SIZE_> + class u32string : public iu32string + { + public: + + typedef iu32string::value_type value_type; + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + u32string() + : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu32string::initialise(); + } + + //************************************************************************* + /// Copy constructor. + ///\param other The other string. + //************************************************************************* + u32string(const etl::u32string<MAX_SIZE_>& other) + : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu32string::initialise(); + iu32string::assign(other.begin(), other.end()); + } + + //************************************************************************* + /// From other string, position, length. + ///\param other The other string. + ///\param position The position of the first character. + ///\param length The number of characters. Default = npos. + //************************************************************************* + u32string(const etl::u32string<MAX_SIZE_>& other, size_t position, size_t length_ = npos) + : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds)); + + // Set the length to the exact amount. + length_ = (length_ > MAX_SIZE_) ? MAX_SIZE_ : length_; + + iu32string::initialise(); + iu32string::assign(other.begin() + position, other.begin() + position + length_); + } + + //************************************************************************* + /// Constructor, from null terminated text. + ///\param text The initial text of the u32string. + //************************************************************************* + u32string(const value_type* text) + : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu32string::initialise(); + iu32string::assign(text, text + etl::char_traits<value_type>::length(text)); + } + + //************************************************************************* + /// Constructor, from null terminated text and count. + ///\param text The initial text of the u32string. + ///\param count The number of characters to copy. + //************************************************************************* + u32string(const value_type* text, size_t count) + : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu32string::initialise(); + iu32string::assign(text, text + count); + } + + //************************************************************************* + /// Constructor, from initial size and value. + ///\param initialSize The initial size of the u32string. + ///\param value The value to fill the u32string with. + //************************************************************************* + u32string(size_t count, value_type c) + : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu32string::initialise(); + iu32string::resize(count, c); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + u32string(TIterator first, TIterator last) + : iu32string(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iu32string::assign(first, last); + } + + //************************************************************************* + /// Returns a sub-string. + ///\param position The position of the first character. Default = 0. + ///\param length The number of characters. Default = npos. + //************************************************************************* + etl::u32string<MAX_SIZE_> substr(size_t position = 0, size_t length_ = npos) const + { + etl::u32string<MAX_SIZE_> new_string; + + if (position != size()) + { + ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds)); + + length_ = std::min(length_, size() - position); + + new_string.assign(buffer + position, buffer + position + length_); + } + + return new_string; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + u32string& operator = (const u32string& rhs) + { + if (&rhs != this) + { + iu32string::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair() + { + etl::iu32string::repair(buffer); + } + + private: + + value_type buffer[MAX_SIZE + 1]; + }; + + //************************************************************************* + /// Hash function. + //************************************************************************* +#if ETL_8BIT_SUPPORT + template <> + struct hash<etl::iu32string> + { + size_t operator()(const etl::iu32string& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; + + template <const size_t SIZE> + struct hash<etl::u32string<SIZE> > + { + size_t operator()(const etl::u32string<SIZE>& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; +#endif +} + +#if defined(ETL_COMPILER_MICROSOFT) + #define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unordered_map.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1395 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_UNORDERED_MAP__ +#define __ETL_UNORDERED_MAP__ + +#include <stddef.h> +#include <iterator> +#include <functional> +#include <algorithm> +#include <functional> +#include <utility> + +#include "platform.h" +#include "container.h" +#include "pool.h" +#include "array.h" +#include "intrusive_forward_list.h" +#include "hash.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "nullptr.h" +#include "vector.h" +#include "error_handler.h" +#include "exception.h" +#include "debug_count.h" + +#undef ETL_FILE +#define ETL_FILE "16" + +//***************************************************************************** +///\defgroup unordered_map unordered_map +/// A unordered_map with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the unordered_map. + ///\ingroup unordered_map + //*************************************************************************** + class unordered_map_exception : public etl::exception + { + public: + + unordered_map_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the unordered_map. + ///\ingroup unordered_map + //*************************************************************************** + class unordered_map_full : public etl::unordered_map_exception + { + public: + + unordered_map_full(string_type file_name_, numeric_type line_number_) + : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Out of range exception for the unordered_map. + ///\ingroup unordered_map + //*************************************************************************** + class unordered_map_out_of_range : public etl::unordered_map_exception + { + public: + + unordered_map_out_of_range(string_type file_name_, numeric_type line_number_) + : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:range", ETL_FILE"B"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// Iterator exception for the unordered_map. + ///\ingroup unordered_map + //*************************************************************************** + class unordered_map_iterator : public etl::unordered_map_exception + { + public: + + unordered_map_iterator(string_type file_name_, numeric_type line_number_) + : etl::unordered_map_exception(ETL_ERROR_TEXT("unordered_map:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized unordered_map. + /// Can be used as a reference type for all unordered_map containing a specific type. + ///\ingroup unordered_map + //*************************************************************************** + template <typename TKey, typename T, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > + class iunordered_map + { + public: + + typedef std::pair<const TKey, T> value_type; + + typedef TKey key_type; + typedef T mapped_type; + typedef THash hasher; + typedef TKeyEqual key_equal; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + typedef etl::forward_link<0> link_t; // Default link. + + // The nodes that store the elements. + struct node_t : public link_t + { + node_t(const value_type& key_value_pair_) + : key_value_pair(key_value_pair_) + { + } + + value_type key_value_pair; + }; + + private: + + typedef etl::intrusive_forward_list<node_t, link_t> bucket_t; + typedef etl::ipool pool_t; + + public: + + // Local iterators iterate over one bucket. + typedef typename bucket_t::iterator local_iterator; + typedef typename bucket_t::const_iterator local_const_iterator; + + //********************************************************************* + class iterator : public std::iterator<std::forward_iterator_tag, T> + { + public: + + typedef typename iunordered_map::value_type value_type; + typedef typename iunordered_map::key_type key_type; + typedef typename iunordered_map::mapped_type mapped_type; + typedef typename iunordered_map::hasher hasher; + typedef typename iunordered_map::key_equal key_equal; + typedef typename iunordered_map::reference reference; + typedef typename iunordered_map::const_reference const_reference; + typedef typename iunordered_map::pointer pointer; + typedef typename iunordered_map::const_pointer const_pointer; + typedef typename iunordered_map::size_type size_type; + + friend class iunordered_map; + + //********************************* + iterator() + { + } + + //********************************* + iterator(const iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + iterator operator ++(int) + { + iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + iterator operator =(const iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + std::pair<const TKey, T> operator *() + { + return inode->key_value_pair; + } + + //********************************* + const_reference operator *() const + { + return inode->key_value_pair; + } + + //********************************* + pointer operator &() + { + return &(inode->key_value_pair); + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key_value_pair); + } + + //********************************* + pointer operator ->() + { + return &(inode->key_value_pair); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key_value_pair); + } + + //********************************* + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) + : pbuckets_end(pbuckets_end_), + pbucket(pbucket_), + inode(inode_) + { + } + + //********************************* + bool compare(const iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t* get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + //********************************************************************* + class const_iterator : public std::iterator<std::forward_iterator_tag, const T> + { + public: + + typedef typename iunordered_map::value_type value_type; + typedef typename iunordered_map::key_type key_type; + typedef typename iunordered_map::mapped_type mapped_type; + typedef typename iunordered_map::hasher hasher; + typedef typename iunordered_map::key_equal key_equal; + typedef typename iunordered_map::reference reference; + typedef typename iunordered_map::const_reference const_reference; + typedef typename iunordered_map::pointer pointer; + typedef typename iunordered_map::const_pointer const_pointer; + typedef typename iunordered_map::size_type size_type; + + friend class iunordered_map; + friend class iterator; + + //********************************* + const_iterator() + { + } + + //********************************* + const_iterator(const typename iunordered_map::iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator(const const_iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + const_iterator operator ++(int) + { + const_iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + const_iterator operator =(const const_iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + const_reference operator *() const + { + return inode->key_value_pair; + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key_value_pair); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key_value_pair); + } + + //********************************* + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) + : pbuckets_end(pbuckets_end_), + pbucket(pbucket_), + inode(inode_) + { + } + + //********************************* + bool compare(const const_iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t* get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_map. + ///\return An iterator to the beginning of the unordered_map. + //********************************************************************* + iterator begin() + { + return iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_map. + ///\return A const iterator to the beginning of the unordered_map. + //********************************************************************* + const_iterator begin() const + { + return const_iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_map. + ///\return A const iterator to the beginning of the unordered_map. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_map bucket. + ///\return An iterator to the beginning of the unordered_map bucket. + //********************************************************************* + local_iterator begin(size_t i) + { + return (*pbuckets)[i].begin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_map bucket. + ///\return A const iterator to the beginning of the unordered_map bucket. + //********************************************************************* + local_const_iterator begin(size_t i) const + { + return (*pbuckets)[i].cbegin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_map bucket. + ///\return A const iterator to the beginning of the unordered_map bucket. + //********************************************************************* + local_const_iterator cbegin(size_t i) const + { + return (*pbuckets)[i].cbegin(); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_map. + ///\return An iterator to the end of the unordered_map. + //********************************************************************* + iterator end() + { + return iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_map. + ///\return A const iterator to the end of the unordered_map. + //********************************************************************* + const_iterator end() const + { + return const_iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_map. + ///\return A const iterator to the end of the unordered_map. + //********************************************************************* + const_iterator cend() const + { + return const_iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_map bucket. + ///\return An iterator to the end of the unordered_map bucket. + //********************************************************************* + local_iterator end(size_t i) + { + return (*pbuckets)[i].end(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_map bucket. + ///\return A const iterator to the end of the unordered_map bucket. + //********************************************************************* + local_const_iterator end(size_t i) const + { + return (*pbuckets)[i].cend(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_map bucket. + ///\return A const iterator to the end of the unordered_map bucket. + //********************************************************************* + local_const_iterator cend(size_t i) const + { + return (*pbuckets)[i].cend(); + } + + //********************************************************************* + /// Returns the bucket index for the key. + ///\return The bucket index for the key. + //********************************************************************* + size_type get_bucket_index(key_parameter_t key) const + { + return key_hash_function(key) % number_of_buckets; + } + + //********************************************************************* + /// Returns the size of the bucket key. + ///\return The bucket size of the bucket key. + //********************************************************************* + size_type bucket_size(key_parameter_t key) const + { + size_t index = bucket(key); + + return std::distance((*pbuckets)[index].begin(), (*pbuckets)[index].end()); + } + + //********************************************************************* + /// Returns the maximum number of the buckets the container can hold. + ///\return The maximum number of the buckets the container can hold. + //********************************************************************* + size_type max_bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Returns the number of the buckets the container holds. + ///\return The number of the buckets the container holds. + //********************************************************************* + size_type bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + ///\param key The key. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& operator [](key_parameter_t key) + { + // Find the bucket. + bucket_t* pbucket = pbuckets + get_bucket_index(key); + + // Find the first node in the bucket. + local_iterator inode = pbucket->begin(); + + // Walk the list looking for the right one. + while (inode != pbucket->end()) + { + // Equal keys? + if (key_equal_function(key, inode->key_value_pair.first)) + { + // Found a match. + return inode->key_value_pair.second; + } + else + { + ++inode; + } + } + + // Doesn't exist, so add a new one. + // Get a new node. + node_t& node = *pnodepool->allocate<node_t>(); + ::new (&node.key_value_pair) value_type(key, T()); + ++construct_count; + + pbucket->insert_after(pbucket->before_begin(), node); + + return pbucket->begin()->key_value_pair.second; + } + + //********************************************************************* + /// Returns a reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::unordered_map_out_of_range if the key is not in the range. + ///\param key The key. + ///\return A reference to the value at index 'key' + //********************************************************************* + mapped_type& at(key_parameter_t key) + { + // Find the bucket. + bucket_t* pbucket = pbuckets + get_bucket_index(key); + + // Find the first node in the bucket. + local_iterator inode = pbucket->begin(); + + // Walk the list looking for the right one. + while (inode != pbucket->end()) + { + // Equal keys? + if (key_equal_function(key, inode->key_value_pair.first)) + { + // Found a match. + return inode->key_value_pair.second; + } + else + { + ++inode; + } + } + + // Doesn't exist. + ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range)); + + return begin()->second; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'key' + /// If asserts or exceptions are enabled, emits an etl::unordered_map_out_of_range if the key is not in the range. + ///\param key The key. + ///\return A const reference to the value at index 'key' + //********************************************************************* + const mapped_type& at(key_parameter_t key) const + { + // Find the bucket. + bucket_t* pbucket = pbuckets + get_bucket_index(key); + + // Find the first node in the bucket. + local_iterator inode = pbucket->begin(); + + // Walk the list looking for the right one. + while (inode != pbucket->end()) + { + // Equal keys? + if (key_equal_function(key, inode->key_value_pair.first)) + { + // Found a match. + return inode->key_value_pair.second; + } + else + { + ++inode; + } + } + + // Doesn't exist. + ETL_ASSERT(false, ETL_ERROR(unordered_map_out_of_range)); + + return begin()->second; + } + + //********************************************************************* + /// Assigns values to the unordered_map. + /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map does not have enough free space. + /// If asserts or exceptions are enabled, emits unordered_map_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first_, TIterator last_) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first_, last_); + ETL_ASSERT(d >= 0, ETL_ERROR(unordered_map_iterator)); + ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_map_full)); +#endif + + clear(); + + while (first_ != last_) + { + insert(*first_++); + } + } + + //********************************************************************* + /// Inserts a value to the unordered_map. + /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(const value_type& key_value_pair) + { + std::pair<iterator, bool> result(end(), false); + + ETL_ASSERT(!full(), ETL_ERROR(unordered_map_full)); + + const key_type& key = key_value_pair.first; + const mapped_type& mapped = key_value_pair.second; + + // Get the hash index. + size_t index = get_bucket_index(key); + + // Get the bucket & bucket iterator. + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + size_t s = pbuckets->size(); + + // The first one in the bucket? + if (bucket.empty()) + { + // Get a new node. + node_t& node = *pnodepool->allocate<node_t>(); + ::new (&node.key_value_pair) value_type(key_value_pair); + ++construct_count; + + // Just add the pointer to the bucket; + bucket.insert_after(bucket.before_begin(), node); + + result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin()); + result.second = true; + + adjust_first_last_markers(pbucket); + } + else + { + // Step though the bucket looking for a place to insert. + local_iterator inode_previous = bucket.before_begin(); + local_iterator inode = bucket.begin(); + + while (inode != bucket.end()) + { + // Do we already have this key? + if (inode->key_value_pair.first == key) + { + break; + } + + ++inode_previous; + ++inode; + } + + // Not already there? + if (inode == bucket.end()) + { + // Get a new node. + node_t& node = *pnodepool->allocate<node_t>(); + ::new (&node.key_value_pair) value_type(key_value_pair); + ++construct_count; + + // Add the node to the end of the bucket; + bucket.insert_after(inode_previous, node); + ++inode_previous; + + result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous); + result.second = true; + } + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the unordered_map. + /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator position, const value_type& key_value_pair) + { + return insert(key_value_pair).first; + } + + //********************************************************************* + /// Inserts a range of values to the unordered_map. + /// If asserts or exceptions are enabled, emits unordered_map_full if the unordered_map does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first_, TIterator last_) + { + while (first_ != last_) + { + insert(*first_++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(key_parameter_t key) + { + size_t n = 0; + size_t index = get_bucket_index(key); + + bucket_t& bucket = pbuckets[index]; + + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = bucket.begin(); + + // Search for the key, if we have it. + while ((icurrent != bucket.end()) && (icurrent->key_value_pair.first != key)) + { + ++iprevious; + ++icurrent; + } + + // Did we find it? + if (icurrent != bucket.end()) + { + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key_value_pair.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + n = 1; + --construct_count; + } + + return n; + } + + //********************************************************************* + /// Erases an element. + ///\param ielement Iterator to the element. + //********************************************************************* + iterator erase(const_iterator ielement) + { + // Make a note of the next one. + iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator()); + ++inext; + + bucket_t& bucket = ielement.get_bucket(); + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = ielement.get_local_iterator(); + + // Find the node previous to the one we're interested in. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key_value_pair.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + return inext; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed to by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + iterator erase(const_iterator first_, const_iterator last_) + { + // Make a note of the last. + iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); + + // Get the starting point. + bucket_t* pbucket = first_.get_bucket_list_iterator(); + local_iterator iprevious = pbucket->before_begin(); + local_iterator icurrent = first_.get_local_iterator(); + local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. + + // Find the node previous to the first one. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + while (icurrent != iend) + { + + local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket. + icurrent->key_value_pair.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + icurrent = inext; + + // Are we there yet? + if (icurrent != iend) + { + // At the end of this bucket? + if ((icurrent == pbucket->end())) + { + // Find the next non-empty one. + do + { + ++pbucket; + } while (pbucket->empty()); + + iprevious = pbucket->before_begin(); + icurrent = pbucket->begin(); + } + } + } + + return result; + } + + //************************************************************************* + /// Clears the unordered_map. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_parameter_t key) const + { + return (find(key) == end()) ? 0 : 1; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + iterator find(key_parameter_t key) + { + size_t index = get_bucket_index(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key_value_pair.first)) + { + return iterator((pbuckets + number_of_buckets), pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + size_t index = get_bucket_index(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key_value_pair.first)) + { + return iterator((pbuckets + number_of_buckets), pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Returns a range containing all elements with key key in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return An iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + iterator f = find(key); + iterator l = f; + + if (l != end()) + { + ++l; + } + + return std::pair<iterator, iterator>(f, l); + } + + //********************************************************************* + /// Returns a range containing all elements with key key in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return A const iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + } + + return std::pair<const_iterator, const_iterator>(f, l); + } + + //************************************************************************* + /// Gets the size of the unordered_map. + //************************************************************************* + size_type size() const + { + return pnodepool->size(); + } + + //************************************************************************* + /// Gets the maximum possible size of the unordered_map. + //************************************************************************* + size_type max_size() const + { + return pnodepool->max_size(); + } + + //************************************************************************* + /// Checks to see if the unordered_map is empty. + //************************************************************************* + bool empty() const + { + return pnodepool->empty(); + } + + //************************************************************************* + /// Checks to see if the unordered_map is full. + //************************************************************************* + bool full() const + { + return pnodepool->full(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return pnodepool->available(); + } + + //************************************************************************* + /// Returns the load factor = size / bucket_count. + ///\return The load factor = size / bucket_count. + //************************************************************************* + float load_factor() const + { + return static_cast<float>(size()) / static_cast<float>(bucket_count()); + } + + //************************************************************************* + /// Returns the function that hashes the keys. + ///\return The function that hashes the keys.. + //************************************************************************* + hasher hash_function() const + { + return key_hash_function; + } + + //************************************************************************* + /// Returns the function that compares the keys. + ///\return The function that compares the keys.. + //************************************************************************* + key_equal key_eq() const + { + return key_equal_function; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iunordered_map& operator = (const iunordered_map& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iunordered_map(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_) + : pnodepool(&node_pool_), + pbuckets(pbuckets_), + number_of_buckets(number_of_buckets_) + { + } + + //********************************************************************* + /// Initialise the unordered_map. + //********************************************************************* + void initialise() + { + if (!empty()) + { + // For each bucket... + for (size_t i = 0; i < number_of_buckets; ++i) + { + bucket_t& bucket = pbuckets[i]; + + if (!bucket.empty()) + { + // For each item in the bucket... + local_iterator it = bucket.begin(); + + while (it != bucket.end()) + { + // Destroy the value contents. + it->key_value_pair.~value_type(); + --construct_count; + + ++it; + } + + // Now it's safe to clear the bucket. + bucket.clear(); + } + } + + // Now it's safe to clear the entire pool in one go. + pnodepool->release_all(); + } + + first = pbuckets; + last = first; + } + + private: + + //********************************************************************* + /// Adjust the first and last markers according to the new entry. + //********************************************************************* + void adjust_first_last_markers(bucket_t* pbucket) + { + if (pbucket < first) + { + first = pbucket; + } + else if (pbucket > last) + { + last = pbucket; + } + } + + // Disable copy construction. + iunordered_map(const iunordered_map&); + + /// The pool of data nodes used in the list. + pool_t* pnodepool; + + /// The bucket list. + bucket_t* pbuckets; + + /// The number of buckets. + const size_t number_of_buckets; + + /// The first and last pointers to buckets with values. + bucket_t* first; + bucket_t* last; + + /// The function that creates the hashes. + hasher key_hash_function; + + /// The function that compares the keys for equality. + key_equal key_equal_function; + + /// For library debugging purposes only. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first unordered_map. + ///\param rhs Reference to the second unordered_map. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup unordered_map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator ==(const etl::iunordered_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_map<TKey, TMapped, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first unordered_map. + ///\param rhs Reference to the second unordered_map. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup unordered_map + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator !=(const etl::iunordered_map<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_map<TKey, TMapped, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// A templated unordered_map implementation that uses a fixed size buffer. + //************************************************************************* + template <typename TKey, typename TValue, const size_t MAX_SIZE_, const size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > + class unordered_map : public etl::iunordered_map<TKey, TValue, THash, TKeyEqual> + { + private: + + typedef iunordered_map<TKey, TValue, THash, TKeyEqual> base; + + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + static const size_t MAX_BUCKETS = MAX_BUCKETS_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + unordered_map() + : base(node_pool, buckets, MAX_BUCKETS_) + { + base::initialise(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + unordered_map(const unordered_map& other) + : base(node_pool, buckets, MAX_BUCKETS_) + { + base::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + unordered_map(TIterator first_, TIterator last_) + : base(node_pool, buckets, MAX_BUCKETS_) + { + base::assign(first_, last_); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~unordered_map() + { + base::initialise(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + unordered_map& operator = (const unordered_map& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + base::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of nodes used for the unordered_map. + etl::pool<typename base::node_t, MAX_SIZE> node_pool; + + /// The buckets of node lists. + etl::intrusive_forward_list<typename base::node_t> buckets[MAX_BUCKETS_]; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unordered_multimap.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1305 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_UNORDERED_MULTIMAP__ +#define __ETL_UNORDERED_MULTIMAP__ + +#include <stddef.h> +#include <iterator> +#include <functional> +#include <algorithm> +#include <functional> +#include <utility> + +#include "platform.h" +#include "container.h" +#include "pool.h" +#include "vector.h" +#include "intrusive_forward_list.h" +#include "hash.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "nullptr.h" +#include "pool.h" +#include "error_handler.h" +#include "exception.h" +#include "debug_count.h" + +#undef ETL_FILE +#define ETL_FILE "25" + +//***************************************************************************** +///\defgroup unordered_multimap unordered_multimap +/// A unordered_multimap with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the unordered_multimap. + ///\ingroup unordered_multimap + //*************************************************************************** + class unordered_multimap_exception : public etl::exception + { + public: + + unordered_multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the unordered_multimap. + ///\ingroup unordered_multimap + //*************************************************************************** + class unordered_multimap_full : public etl::unordered_multimap_exception + { + public: + + unordered_multimap_full(string_type file_name_, numeric_type line_number_) + : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Out of range exception for the unordered_multimap. + ///\ingroup unordered_multimap + //*************************************************************************** + class unordered_multimap_out_of_range : public etl::unordered_multimap_exception + { + public: + + unordered_multimap_out_of_range(string_type file_name_, numeric_type line_number_) + : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:range", ETL_FILE"B"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// Iterator exception for the unordered_multimap. + ///\ingroup unordered_multimap + //*************************************************************************** + class unordered_multimap_iterator : public etl::unordered_multimap_exception + { + public: + + unordered_multimap_iterator(string_type file_name_, numeric_type line_number_) + : etl::unordered_multimap_exception(ETL_ERROR_TEXT("unordered_multimap:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized unordered_multimap. + /// Can be used as a reference type for all unordered_multimap containing a specific type. + ///\ingroup unordered_multimap + //*************************************************************************** + template <typename TKey, typename T, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > + class iunordered_multimap + { + public: + + typedef std::pair<const TKey, T> value_type; + + typedef TKey key_type; + typedef T mapped_type; + typedef THash hasher; + typedef TKeyEqual key_equal; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + typedef etl::forward_link<0> link_t; // Default link. + + struct node_t : public link_t // The nodes that store the elements. + { + node_t(const value_type& key_value_pair_) + : key_value_pair(key_value_pair_) + { + } + + value_type key_value_pair; + }; + + private: + + typedef etl::intrusive_forward_list<node_t, link_t> bucket_t; + typedef etl::ipool pool_t; + + public: + + // Local iterators iterate over one bucket. + typedef typename bucket_t::iterator local_iterator; + typedef typename bucket_t::const_iterator local_const_iterator; + + //********************************************************************* + class iterator : public std::iterator<std::forward_iterator_tag, T> + { + public: + + typedef typename iunordered_multimap::value_type value_type; + typedef typename iunordered_multimap::key_type key_type; + typedef typename iunordered_multimap::mapped_type mapped_type; + typedef typename iunordered_multimap::hasher hasher; + typedef typename iunordered_multimap::key_equal key_equal; + typedef typename iunordered_multimap::reference reference; + typedef typename iunordered_multimap::const_reference const_reference; + typedef typename iunordered_multimap::pointer pointer; + typedef typename iunordered_multimap::const_pointer const_pointer; + typedef typename iunordered_multimap::size_type size_type; + + friend class iunordered_multimap; + + //********************************* + iterator() + { + } + + //********************************* + iterator(const iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + iterator operator ++(int) + { + iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + iterator operator =(const iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + std::pair<const TKey, T> operator *() + { + return inode->key_value_pair; + } + + //********************************* + const_reference operator *() const + { + return inode->key_value_pair; + } + + //********************************* + pointer operator &() + { + return &(inode->key_value_pair); + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key_value_pair); + } + + //********************************* + pointer operator ->() + { + return &(inode->key_value_pair); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key_value_pair); + } + + //********************************* + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) + : pbuckets_end(pbuckets_end_), + pbucket(pbucket_), + inode(inode_) + { + } + + //********************************* + bool compare(const iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t*& get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + //********************************************************************* + class const_iterator : public std::iterator<std::forward_iterator_tag, const T> + { + public: + + typedef typename iunordered_multimap::value_type value_type; + typedef typename iunordered_multimap::key_type key_type; + typedef typename iunordered_multimap::mapped_type mapped_type; + typedef typename iunordered_multimap::hasher hasher; + typedef typename iunordered_multimap::key_equal key_equal; + typedef typename iunordered_multimap::reference reference; + typedef typename iunordered_multimap::const_reference const_reference; + typedef typename iunordered_multimap::pointer pointer; + typedef typename iunordered_multimap::const_pointer const_pointer; + typedef typename iunordered_multimap::size_type size_type; + + friend class iunordered_multimap; + friend class iterator; + + //********************************* + const_iterator() + { + } + + //********************************* + const_iterator(const typename iunordered_multimap::iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator(const const_iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + const_iterator operator ++(int) + { + const_iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + const_iterator operator =(const const_iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + const_reference operator *() const + { + return inode->key_value_pair; + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key_value_pair); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key_value_pair); + } + + //********************************* + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) + : pbuckets_end(pbuckets_end_), + pbucket(pbucket_), + inode(inode_) + { + } + + //********************************* + bool compare(const const_iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t*& get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_multimap. + ///\return An iterator to the beginning of the unordered_multimap. + //********************************************************************* + iterator begin() + { + return iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multimap. + ///\return A const iterator to the beginning of the unordered_multimap. + //********************************************************************* + const_iterator begin() const + { + return const_iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multimap. + ///\return A const iterator to the beginning of the unordered_multimap. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_multimap bucket. + ///\return An iterator to the beginning of the unordered_multimap bucket. + //********************************************************************* + local_iterator begin(size_t i) + { + return pbuckets[i].begin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multimap bucket. + ///\return A const iterator to the beginning of the unordered_multimap bucket. + //********************************************************************* + local_const_iterator begin(size_t i) const + { + return pbuckets[i].cbegin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multimap bucket. + ///\return A const iterator to the beginning of the unordered_multimap bucket. + //********************************************************************* + local_const_iterator cbegin(size_t i) const + { + return pbuckets[i].cbegin(); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_multimap. + ///\return An iterator to the end of the unordered_multimap. + //********************************************************************* + iterator end() + { + return iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multimap. + ///\return A const iterator to the end of the unordered_multimap. + //********************************************************************* + const_iterator end() const + { + return const_iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multimap. + ///\return A const iterator to the end of the unordered_multimap. + //********************************************************************* + const_iterator cend() const + { + return const_iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_multimap bucket. + ///\return An iterator to the end of the unordered_multimap bucket. + //********************************************************************* + local_iterator end(size_t i) + { + return pbuckets[i].end(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multimap bucket. + ///\return A const iterator to the end of the unordered_multimap bucket. + //********************************************************************* + local_const_iterator end(size_t i) const + { + return pbuckets[i].cend(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multimap bucket. + ///\return A const iterator to the end of the unordered_multimap bucket. + //********************************************************************* + local_const_iterator cend(size_t i) const + { + return pbuckets[i].cend(); + } + + //********************************************************************* + /// Returns the bucket index for the key. + ///\return The bucket index for the key. + //********************************************************************* + size_type get_bucket_index(key_parameter_t key) const + { + return key_hash_function(key) % number_of_buckets; + } + + //********************************************************************* + /// Returns the size of the bucket key. + ///\return The bucket size of the bucket key. + //********************************************************************* + size_type bucket_size(key_parameter_t key) const + { + size_t index = bucket(key); + + return std::distance(pbuckets[index].begin(), pbuckets[index].end()); + } + + //********************************************************************* + /// Returns the maximum number of the buckets the container can hold. + ///\return The maximum number of the buckets the container can hold. + //********************************************************************* + size_type max_bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Returns the number of the buckets the container holds. + ///\return The number of the buckets the container holds. + //********************************************************************* + size_type bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Assigns values to the unordered_multimap. + /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap does not have enough free space. + /// If asserts or exceptions are enabled, emits unordered_multimap_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first_, TIterator last_) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first_, last_); + ETL_ASSERT(d >= 0, ETL_ERROR(unordered_multimap_iterator)); + ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_multimap_full)); +#endif + + clear(); + + while (first_ != last_) + { + insert(*first_++); + } + } + + //********************************************************************* + /// Inserts a value to the unordered_multimap. + /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap is already full. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const value_type& key_value_pair) + { + iterator result = end(); + + ETL_ASSERT(!full(), ETL_ERROR(unordered_multimap_full)); + + const key_type& key = key_value_pair.first; + const mapped_type& mapped = key_value_pair.second; + + // Get the hash index. + size_t index = get_bucket_index(key); + + // Get the bucket & bucket iterator. + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // The first one in the bucket? + if (bucket.empty()) + { + // Get a new node. + node_t& node = *pnodepool->allocate<node_t>(); + ::new (&node.key_value_pair) value_type(key_value_pair); + ++construct_count; + + // Just add the pointer to the bucket; + bucket.insert_after(bucket.before_begin(), node); + + result = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin()); + + adjust_first_last_markers(pbucket); + } + else + { + // Step though the bucket looking for a place to insert. + local_iterator inode_previous = bucket.before_begin(); + local_iterator inode = bucket.begin(); + + while (inode != bucket.end()) + { + // Do we already have this key? + if (inode->key_value_pair.first == key) + { + break; + } + + ++inode_previous; + ++inode; + } + + // Get a new node. + node_t& node = *pnodepool->allocate<node_t>(); + ::new (&node.key_value_pair) value_type(key_value_pair); + ++construct_count; + + // Add the node to the end of the bucket; + bucket.insert_after(inode_previous, node); + ++inode_previous; + + result = iterator((pbuckets + number_of_buckets), pbucket, inode_previous); + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the unordered_multimap. + /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator position, const value_type& key_value_pair) + { + return insert(key_value_pair); + } + + //********************************************************************* + /// Inserts a range of values to the unordered_multimap. + /// If asserts or exceptions are enabled, emits unordered_multimap_full if the unordered_multimap does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first_, TIterator last_) + { + while (first_ != last_) + { + insert(*first_++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. + //********************************************************************* + size_t erase(key_parameter_t key) + { + size_t n = 0; + size_t bucket_id = get_bucket_index(key); + + bucket_t& bucket = pbuckets[bucket_id]; + + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = bucket.begin(); + + while (icurrent != bucket.end()) + { + if (icurrent->key_value_pair.first == key) + { + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key_value_pair.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + ++n; + icurrent = iprevious; + --construct_count; + } + else + { + ++iprevious; + } + + ++icurrent; + } + + return n; + } + + //********************************************************************* + /// Erases an element. + ///\param ielement Iterator to the element. + //********************************************************************* + iterator erase(const_iterator ielement) + { + // Make a note of the next one. + iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator()); + ++inext; + + bucket_t& bucket = ielement.get_bucket(); + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = ielement.get_local_iterator(); + + // Find the node previous to the one we're interested in. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key_value_pair.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + return inext; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed to by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + iterator erase(const_iterator first_, const_iterator last_) + { + // Make a note of the last. + iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); + + // Get the starting point. + bucket_t* pbucket = first_.get_bucket_list_iterator(); + local_iterator iprevious = pbucket->before_begin(); + local_iterator icurrent = first_.get_local_iterator(); + local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. + + // Find the node previous to the first one. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + while (icurrent != iend) + { + + local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket. + icurrent->key_value_pair.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + icurrent = inext; + + // Are we there yet? + if (icurrent != iend) + { + // At the end of this bucket? + if ((icurrent == pbucket->end())) + { + // Find the next non-empty one. + do + { + ++pbucket; + } while (pbucket->empty()); + + iprevious = pbucket->before_begin(); + icurrent = pbucket->begin(); + } + } + } + + return result; + } + + //************************************************************************* + /// Clears the unordered_multimap. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_parameter_t key) const + { + size_t n = 0; + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + ++n; + + while ((l != end()) && (key == l->first)) + { + ++l; + ++n; + } + } + + return n; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + iterator find(key_parameter_t key) + { + size_t index = get_bucket_index(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key_value_pair.first)) + { + return iterator((pbuckets + number_of_buckets), pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + size_t index = get_bucket_index(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key_value_pair.first)) + { + return const_iterator((pbuckets + number_of_buckets), pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Returns a range containing all elements with key key in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return An iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + iterator f = find(key); + iterator l = f; + + if (l != end()) + { + ++l; + + while ((l != end()) && (key == l->first)) + { + ++l; + } + } + + return std::pair<iterator, iterator>(f, l); + } + + //********************************************************************* + /// Returns a range containing all elements with key key in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return A const iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + + while ((l != end()) && (key == l->first)) + { + ++l; + } + } + + return std::pair<const_iterator, const_iterator>(f, l); + } + + //************************************************************************* + /// Gets the size of the unordered_multimap. + //************************************************************************* + size_type size() const + { + return pnodepool->size(); + } + + //************************************************************************* + /// Gets the maximum possible size of the unordered_multimap. + //************************************************************************* + size_type max_size() const + { + return pnodepool->max_size(); + } + + //************************************************************************* + /// Checks to see if the unordered_multimap is empty. + //************************************************************************* + bool empty() const + { + return pnodepool->empty(); + } + + //************************************************************************* + /// Checks to see if the unordered_multimap is full. + //************************************************************************* + bool full() const + { + return pnodepool->full(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return pnodepool->available(); + } + + //************************************************************************* + /// Returns the load factor = size / bucket_count. + ///\return The load factor = size / bucket_count. + //************************************************************************* + float load_factor() const + { + return static_cast<float>(size()) / static_cast<float>(bucket_count()); + } + + //************************************************************************* + /// Returns the function that hashes the keys. + ///\return The function that hashes the keys.. + //************************************************************************* + hasher hash_function() const + { + return key_hash_function; + } + + //************************************************************************* + /// Returns the function that compares the keys. + ///\return The function that compares the keys.. + //************************************************************************* + key_equal key_eq() const + { + return key_equal_function; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iunordered_multimap& operator = (const iunordered_multimap& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iunordered_multimap(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_) + : pnodepool(&node_pool_), + pbuckets(pbuckets_), + number_of_buckets(number_of_buckets_) + { + } + + //********************************************************************* + /// Initialise the unordered_multimap. + //********************************************************************* + void initialise() + { + if (!empty()) + { + // For each bucket... + for (size_t i = 0; i < number_of_buckets; ++i) + { + bucket_t& bucket = pbuckets[i]; + + if (!bucket.empty()) + { + // For each item in the bucket... + local_iterator it = bucket.begin(); + + while (it != bucket.end()) + { + // Destroy the value contents. + it->key_value_pair.~value_type(); + ++it; + --construct_count; + } + + // Now it's safe to clear the bucket. + bucket.clear(); + } + } + + // Now it's safe to clear the entire pool in one go. + pnodepool->release_all(); + } + + first = pbuckets; + last = first; + } + + private: + + //********************************************************************* + /// Adjust the first and last markers according to the new entry. + //********************************************************************* + void adjust_first_last_markers(bucket_t* pbucket) + { + if (pbucket < first) + { + first = pbucket; + } + else if (pbucket > last) + { + last = pbucket; + } + } + + // Disable copy construction. + iunordered_multimap(const iunordered_multimap&); + + /// The pool of data nodes used in the list. + pool_t* pnodepool; + + /// The bucket list. + bucket_t* pbuckets; + + /// The number of buckets. + const size_t number_of_buckets; + + /// The first and last iterators to buckets with values. + bucket_t* first; + bucket_t* last; + + /// The function that creates the hashes. + hasher key_hash_function; + + /// The function that compares the keys for equality. + key_equal key_equal_function; + + /// For library debugging purposes only. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first unordered_multimap. + ///\param rhs Reference to the second unordered_multimap. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup unordered_multimap + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator ==(const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first unordered_multimap. + ///\param rhs Reference to the second unordered_multimap. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup unordered_multimap + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator !=(const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multimap<TKey, TMapped, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// A templated unordered_multimap implementation that uses a fixed size buffer. + //************************************************************************* + template <typename TKey, typename TValue, const size_t MAX_SIZE_, const size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > + class unordered_multimap : public etl::iunordered_multimap<TKey, TValue, THash, TKeyEqual> + { + private: + + typedef etl::iunordered_multimap<TKey, TValue, THash, TKeyEqual> base; + + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + static const size_t MAX_BUCKETS = MAX_BUCKETS_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + unordered_multimap() + : base(node_pool, buckets, MAX_BUCKETS) + { + base::initialise(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + unordered_multimap(const unordered_multimap& other) + : base(node_pool, buckets, MAX_BUCKETS) + { + base::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + unordered_multimap(TIterator first_, TIterator last_) + : base(node_pool, buckets, MAX_BUCKETS) + { + base::assign(first_, last_); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~unordered_multimap() + { + base::initialise(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + unordered_multimap& operator = (const unordered_multimap& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + base::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of nodes used for the unordered_multimap. + etl::pool<typename base::node_t, MAX_SIZE> node_pool; + + /// The buckets of node lists. + etl::intrusive_forward_list<typename base::node_t> buckets[MAX_BUCKETS_]; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unordered_multiset.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1300 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_UNORDERED_MULTISET__ +#define __ETL_UNORDERED_MULTISET__ + +#include <stddef.h> +#include <iterator> +#include <functional> +#include <iterator> +#include <algorithm> +#include <utility> + +#include "platform.h" +#include "container.h" +#include "pool.h" +#include "vector.h" +#include "intrusive_forward_list.h" +#include "hash.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "debug_count.h" + +#undef ETL_FILE +#define ETL_FILE "26" + +//***************************************************************************** +///\defgroup unordered_multiset unordered_multiset +/// A unordered_multiset with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the unordered_multiset. + ///\ingroup unordered_multiset + //*************************************************************************** + class unordered_multiset_exception : public etl::exception + { + public: + + unordered_multiset_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the unordered_multiset. + ///\ingroup unordered_multiset + //*************************************************************************** + class unordered_multiset_full : public etl::unordered_multiset_exception + { + public: + + unordered_multiset_full(string_type file_name_, numeric_type line_number_) + : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Out of range exception for the unordered_multiset. + ///\ingroup unordered_multiset + //*************************************************************************** + class unordered_multiset_out_of_range : public etl::unordered_multiset_exception + { + public: + + unordered_multiset_out_of_range(string_type file_name_, numeric_type line_number_) + : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:range", ETL_FILE"B"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// Iterator exception for the unordered_multiset. + ///\ingroup unordered_multiset + //*************************************************************************** + class unordered_multiset_iterator : public etl::unordered_multiset_exception + { + public: + + unordered_multiset_iterator(string_type file_name_, numeric_type line_number_) + : etl::unordered_multiset_exception(ETL_ERROR_TEXT("unordered_multiset:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized unordered_multiset. + /// Can be used as a reference type for all unordered_multiset containing a specific type. + ///\ingroup unordered_multiset + //*************************************************************************** + template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > + class iunordered_multiset + { + public: + + typedef TKey value_type; + typedef TKey key_type; + typedef THash hasher; + typedef TKeyEqual key_equal; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + typedef etl::forward_link<0> link_t; + + // The nodes that store the elements. + struct node_t : public link_t + { + node_t(const value_type& key_) + : key(key_) + { + } + + value_type key; + }; + + private: + + typedef etl::intrusive_forward_list<node_t, link_t> bucket_t; + typedef etl::ipool pool_t; + + public: + + // Local iterators iterate over one bucket. + typedef typename bucket_t::iterator local_iterator; + typedef typename bucket_t::const_iterator local_const_iterator; + + //********************************************************************* + class iterator : public std::iterator<std::forward_iterator_tag, TKey> + { + public: + + typedef typename iunordered_multiset::value_type value_type; + typedef typename iunordered_multiset::key_type key_type; + typedef typename iunordered_multiset::hasher hasher; + typedef typename iunordered_multiset::key_equal key_equal; + typedef typename iunordered_multiset::reference reference; + typedef typename iunordered_multiset::const_reference const_reference; + typedef typename iunordered_multiset::pointer pointer; + typedef typename iunordered_multiset::const_pointer const_pointer; + typedef typename iunordered_multiset::size_type size_type; + + friend class iunordered_multiset; + + //********************************* + iterator() + { + } + + //********************************* + iterator(const iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + iterator operator ++(int) + { + iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + iterator operator =(const iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + reference operator *() + { + return inode->key; + } + + //********************************* + const_reference operator *() const + { + return inode->key; + } + + //********************************* + pointer operator &() + { + return &(inode->key); + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key); + } + + //********************************* + pointer operator ->() + { + return &(inode->key); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key); + } + + //********************************* + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) + : pbuckets_end(pbuckets_end_), + pbucket(pbucket_), + inode(inode_) + { + } + + //********************************* + bool compare(const iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t*& get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + //********************************************************************* + class const_iterator : public std::iterator<std::forward_iterator_tag, const TKey> + { + public: + + typedef typename iunordered_multiset::value_type value_type; + typedef typename iunordered_multiset::key_type key_type; + typedef typename iunordered_multiset::hasher hasher; + typedef typename iunordered_multiset::key_equal key_equal; + typedef typename iunordered_multiset::reference reference; + typedef typename iunordered_multiset::const_reference const_reference; + typedef typename iunordered_multiset::pointer pointer; + typedef typename iunordered_multiset::const_pointer const_pointer; + typedef typename iunordered_multiset::size_type size_type; + + friend class iunordered_multiset; + friend class iterator; + + //********************************* + const_iterator() + { + } + + //********************************* + const_iterator(const typename iunordered_multiset::iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator(const const_iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + const_iterator operator ++(int) + { + const_iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + const_iterator operator =(const const_iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + const_reference operator *() const + { + return inode->key; + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key); + } + + //********************************* + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) + : pbuckets_end(pbuckets_end_), + pbucket(pbucket_), + inode(inode_) + { + } + + //********************************* + bool compare(const const_iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t*& get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_multiset. + ///\return An iterator to the beginning of the unordered_multiset. + //********************************************************************* + iterator begin() + { + return iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multiset. + ///\return A const iterator to the beginning of the unordered_multiset. + //********************************************************************* + const_iterator begin() const + { + return const_iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multiset. + ///\return A const iterator to the beginning of the unordered_multiset. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator((pbuckets + number_of_buckets), first, first->begin()); + } + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_multiset bucket. + ///\return An iterator to the beginning of the unordered_multiset bucket. + //********************************************************************* + local_iterator begin(size_t i) + { + return pbuckets[i].begin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multiset bucket. + ///\return A const iterator to the beginning of the unordered_multiset bucket. + //********************************************************************* + local_const_iterator begin(size_t i) const + { + return pbuckets[i].cbegin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_multiset bucket. + ///\return A const iterator to the beginning of the unordered_multiset bucket. + //********************************************************************* + local_const_iterator cbegin(size_t i) const + { + return pbuckets[i].cbegin(); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_multiset. + ///\return An iterator to the end of the unordered_multiset. + //********************************************************************* + iterator end() + { + return iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multiset. + ///\return A const iterator to the end of the unordered_multiset. + //********************************************************************* + const_iterator end() const + { + return const_iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multiset. + ///\return A const iterator to the end of the unordered_multiset. + //********************************************************************* + const_iterator cend() const + { + return const_iterator((pbuckets + number_of_buckets), last, last->end()); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_multiset bucket. + ///\return An iterator to the end of the unordered_multiset bucket. + //********************************************************************* + local_iterator end(size_t i) + { + return pbuckets[i].end(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multiset bucket. + ///\return A const iterator to the end of the unordered_multiset bucket. + //********************************************************************* + local_const_iterator end(size_t i) const + { + return pbuckets[i].cend(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_multiset bucket. + ///\return A const iterator to the end of the unordered_multiset bucket. + //********************************************************************* + local_const_iterator cend(size_t i) const + { + return pbuckets[i].cend(); + } + + //********************************************************************* + /// Returns the bucket index for the key. + ///\return The bucket index for the key. + //********************************************************************* + size_type get_bucket_index(key_parameter_t key) const + { + return key_hash_function(key) % number_of_buckets; + } + + //********************************************************************* + /// Returns the size of the bucket key. + ///\return The bucket size of the bucket key. + //********************************************************************* + size_type bucket_size(key_parameter_t key) const + { + size_t index = bucket(key); + + return std::distance(pbuckets[index].begin(), pbuckets[index].end()); + } + + //********************************************************************* + /// Returns the maximum number of the buckets the container can hold. + ///\return The maximum number of the buckets the container can hold. + //********************************************************************* + size_type max_bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Returns the number of the buckets the container holds. + ///\return The number of the buckets the container holds. + //********************************************************************* + size_type bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Assigns values to the unordered_multiset. + /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset does not have enough free space. + /// If asserts or exceptions are enabled, emits unordered_multiset_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first_, TIterator last_) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first_, last_); + ETL_ASSERT(d >= 0, ETL_ERROR(unordered_multiset_iterator)); + ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_multiset_full)); +#endif + + clear(); + + while (first_ != last_) + { + insert(*first_++); + } + } + + //********************************************************************* + /// Inserts a value to the unordered_multiset. + /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(const value_type& key) + { + std::pair<iterator, bool> result(end(), false); + + ETL_ASSERT(!full(), ETL_ERROR(unordered_multiset_full)); + + // Get the hash index. + size_t index = get_bucket_index(key); + + // Get the bucket & bucket iterator. + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // The first one in the bucket? + if (bucket.empty()) + { + // Get a new node. + node_t& node = *pnodepool->allocate<node_t>(); + ::new (&node.key) value_type(key); + ++construct_count; + + // Just add the pointer to the bucket; + bucket.insert_after(bucket.before_begin(), node); + + result.first = iterator((pbuckets + number_of_buckets), pbucket, pbucket->begin()); + result.second = true; + + adjust_first_last_markers(pbucket); + } + else + { + // Step though the bucket looking for a place to insert. + local_iterator inode_previous = bucket.before_begin(); + local_iterator inode = bucket.begin(); + + while (inode != bucket.end()) + { + // Do we already have this key? + if (inode->key == key) + { + break; + } + + ++inode_previous; + ++inode; + } + + // Get a new node. + node_t& node = *pnodepool->allocate<node_t>(); + ::new (&node.key) value_type(key); + ++construct_count; + + // Add the node to the end of the bucket; + bucket.insert_after(inode_previous, node); + ++inode_previous; + + result.first = iterator((pbuckets + number_of_buckets), pbucket, inode_previous); + result.second = true; + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the unordered_multiset. + /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator position, const value_type& key) + { + return insert(key).first; + } + + //********************************************************************* + /// Inserts a range of values to the unordered_multiset. + /// If asserts or exceptions are enabled, emits unordered_multiset_full if the unordered_multiset does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first_, TIterator last_) + { + while (first_ != last_) + { + insert(*first_++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. + //********************************************************************* + size_t erase(key_parameter_t key) + { + size_t n = 0; + size_t bucket_id = get_bucket_index(key); + + bucket_t& bucket = pbuckets[bucket_id]; + + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = bucket.begin(); + + while (icurrent != bucket.end()) + { + if (icurrent->key == key) + { + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + ++n; + icurrent = iprevious; + --construct_count; + } + else + { + ++iprevious; + } + + ++icurrent; + } + + return n; + } + + //********************************************************************* + /// Erases an element. + ///\param ielement Iterator to the element. + //********************************************************************* + iterator erase(const_iterator ielement) + { + // Make a note of the next one. + iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator()); + ++inext; + + bucket_t& bucket = ielement.get_bucket(); + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = ielement.get_local_iterator(); + + // Find the node previous to the one we're interested in. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + return inext; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed to by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + iterator erase(const_iterator first_, const_iterator last_) + { + // Make a note of the last. + iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); + + // Get the starting point. + bucket_t* pbucket = first_.get_bucket_list_iterator(); + local_iterator iprevious = pbucket->before_begin(); + local_iterator icurrent = first_.get_local_iterator(); + local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. + + // Find the node previous to the first one. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + while (icurrent != iend) + { + + local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket. + icurrent->key.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + icurrent = inext; + + // Are we there yet? + if (icurrent != iend) + { + // At the end of this bucket? + if ((icurrent == pbucket->end())) + { + // Find the next non-empty one. + do + { + ++pbucket; + } while (pbucket->empty()); + + iprevious = pbucket->before_begin(); + icurrent = pbucket->begin(); + } + } + } + + return result; + } + + //************************************************************************* + /// Clears the unordered_multiset. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_parameter_t key) const + { + size_t n = 0; + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + ++n; + + while ((l != end()) && (key == *l)) + { + ++l; + ++n; + } + } + + return n; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + iterator find(key_parameter_t key) + { + size_t index = get_bucket_index(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key)) + { + return iterator((pbuckets + number_of_buckets), pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + size_t index = get_bucket_index(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key)) + { + return iterator((pbuckets + number_of_buckets), pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Returns a range containing all elements with key key in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return An iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + iterator f = find(key); + iterator l = f; + + if (l != end()) + { + ++l; + + while ((l != end()) && (key == *l)) + { + ++l; + } + } + + return std::pair<iterator, iterator>(f, l); + } + + //********************************************************************* + /// Returns a range containing all elements with key key in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return A const iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + + while ((l != end()) && (key == *l)) + { + ++l; + } + } + + return std::pair<const_iterator, const_iterator>(f, l); + } + + //************************************************************************* + /// Gets the size of the unordered_multiset. + //************************************************************************* + size_type size() const + { + return pnodepool->size(); + } + + //************************************************************************* + /// Gets the maximum possible size of the unordered_multiset. + //************************************************************************* + size_type max_size() const + { + return pnodepool->max_size(); + } + + //************************************************************************* + /// Checks to see if the unordered_multiset is empty. + //************************************************************************* + bool empty() const + { + return pnodepool->empty(); + } + + //************************************************************************* + /// Checks to see if the unordered_multiset is full. + //************************************************************************* + bool full() const + { + return pnodepool->full(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return pnodepool->available(); + } + + //************************************************************************* + /// Returns the load factor = size / bucket_count. + ///\return The load factor = size / bucket_count. + //************************************************************************* + float load_factor() const + { + return static_cast<float>(size()) / static_cast<float>(bucket_count()); + } + + //************************************************************************* + /// Returns the function that hashes the keys. + ///\return The function that hashes the keys.. + //************************************************************************* + hasher hash_function() const + { + return key_hash_function; + } + + //************************************************************************* + /// Returns the function that compares the keys. + ///\return The function that compares the keys.. + //************************************************************************* + key_equal key_eq() const + { + return key_equal_function; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iunordered_multiset& operator = (const iunordered_multiset& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iunordered_multiset(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_) + : pnodepool(&node_pool_), + pbuckets(pbuckets_), + number_of_buckets(number_of_buckets_) + { + } + + //********************************************************************* + /// Initialise the unordered_multiset. + //********************************************************************* + void initialise() + { + if (!empty()) + { + // For each bucket... + for (size_t i = 0; i < number_of_buckets; ++i) + { + bucket_t& bucket = pbuckets[i]; + + if (!bucket.empty()) + { + // For each item in the bucket... + local_iterator it = bucket.begin(); + + while (it != bucket.end()) + { + // Destroy the value contents. + it->key.~value_type(); + ++it; + --construct_count; + } + + // Now it's safe to clear the bucket. + bucket.clear(); + } + } + + // Now it's safe to clear the entire pool in one go. + pnodepool->release_all(); + } + + first = pbuckets; + last = first; + } + + private: + + //********************************************************************* + /// Adjust the first and last markers according to the new entry. + //********************************************************************* + void adjust_first_last_markers(bucket_t* pbucket) + { + if (pbucket < first) + { + first = pbucket; + } + else if (pbucket > last) + { + last = pbucket; + } + } + + // Disable copy construction. + iunordered_multiset(const iunordered_multiset&); + + /// The pool of data nodes used in the list. + pool_t* pnodepool; + + /// The bucket list. + bucket_t* pbuckets; + + /// The number of buckets. + const size_t number_of_buckets; + + /// The first and last iterators to buckets with values. + bucket_t* first; + bucket_t* last; + + /// The function that creates the hashes. + hasher key_hash_function; + + /// The function that compares the keys for equality. + key_equal key_equal_function; + + /// For library debugging purposes only. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first unordered_multiset. + ///\param rhs Reference to the second unordered_multiset. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup unordered_multiset + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator ==(const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first unordered_multiset. + ///\param rhs Reference to the second unordered_multiset. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup unordered_multiset + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator !=(const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_multiset<TKey, TMapped, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// A templated unordered_multiset implementation that uses a fixed size buffer. + //************************************************************************* + template <typename TKey, const size_t MAX_SIZE_, size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > + class unordered_multiset : public etl::iunordered_multiset<TKey, THash, TKeyEqual> + { + private: + + typedef etl::iunordered_multiset<TKey, THash, TKeyEqual> base; + + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + static const size_t MAX_BUCKETS = MAX_BUCKETS_; + + + //************************************************************************* + /// Default constructor. + //************************************************************************* + unordered_multiset() + : base(node_pool, buckets, MAX_BUCKETS) + { + base::initialise(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + unordered_multiset(const unordered_multiset& other) + : base(node_pool, buckets, MAX_BUCKETS) + { + base::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + unordered_multiset(TIterator first_, TIterator last_) + : base(node_pool, buckets, MAX_BUCKETS) + { + base::assign(first_, last_); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~unordered_multiset() + { + base::initialise(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + unordered_multiset& operator = (const unordered_multiset& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + base::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of nodes used for the unordered_multiset. + etl::pool<typename base::node_t, MAX_SIZE> node_pool; + + /// The buckets of node lists. + etl::intrusive_forward_list<typename base::node_t> buckets[MAX_BUCKETS_]; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unordered_set.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1276 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_UNORDERED_SET__ +#define __ETL_UNORDERED_SET__ + +#include <stddef.h> +#include <iterator> +#include <functional> +#include <algorithm> +#include <functional> +#include <utility> + +#include "platform.h" +#include "container.h" +#include "pool.h" +#include "vector.h" +#include "intrusive_forward_list.h" +#include "hash.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" + +#undef ETL_FILE +#define ETL_FILE "23" + +//***************************************************************************** +///\defgroup unordered_set unordered_set +/// A unordered_set with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// Exception for the unordered_set. + ///\ingroup unordered_set + //*************************************************************************** + class unordered_set_exception : public etl::exception + { + public: + + unordered_set_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Full exception for the unordered_set. + ///\ingroup unordered_set + //*************************************************************************** + class unordered_set_full : public etl::unordered_set_exception + { + public: + + unordered_set_full(string_type file_name_, numeric_type line_number_) + : etl::unordered_set_exception(ETL_ERROR_TEXT("unordered_set:full", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Out of range exception for the unordered_set. + ///\ingroup unordered_set + //*************************************************************************** + class unordered_set_out_of_range : public etl::unordered_set_exception + { + public: + + unordered_set_out_of_range(string_type file_name_, numeric_type line_number_) + : etl::unordered_set_exception(ETL_ERROR_TEXT("unordered_set:range", ETL_FILE"B"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// Iterator exception for the unordered_set. + ///\ingroup unordered_set + //*************************************************************************** + class unordered_set_iterator : public etl::unordered_set_exception + { + public: + + unordered_set_iterator(string_type file_name_, numeric_type line_number_) + : etl::unordered_set_exception(ETL_ERROR_TEXT("unordered_set:iterator", ETL_FILE"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// The base class for specifically sized unordered_set. + /// Can be used as a reference type for all unordered_set containing a specific type. + ///\ingroup unordered_set + //*************************************************************************** + template <typename TKey, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > + class iunordered_set + { + public: + + typedef TKey value_type; + typedef TKey key_type; + typedef THash hasher; + typedef TKeyEqual key_equal; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef size_t size_type; + + typedef typename etl::parameter_type<TKey>::type key_parameter_t; + + typedef etl::forward_link<0> link_t; + + // The nodes that store the elements. + struct node_t : public link_t + { + node_t(const value_type& key_) + : key(key_) + { + } + + value_type key; + }; + + private: + + typedef etl::intrusive_forward_list<node_t, link_t> bucket_t; + typedef etl::ipool pool_t; + + public: + + // Local iterators iterate over one bucket. + typedef typename bucket_t::iterator local_iterator; + typedef typename bucket_t::const_iterator local_const_iterator; + + //********************************************************************* + class iterator : public std::iterator<std::forward_iterator_tag, TKey> + { + public: + + typedef typename iunordered_set::value_type value_type; + typedef typename iunordered_set::key_type key_type; + typedef typename iunordered_set::hasher hasher; + typedef typename iunordered_set::key_equal key_equal; + typedef typename iunordered_set::reference reference; + typedef typename iunordered_set::const_reference const_reference; + typedef typename iunordered_set::pointer pointer; + typedef typename iunordered_set::const_pointer const_pointer; + typedef typename iunordered_set::size_type size_type; + + friend class iunordered_set; + + //********************************* + iterator() + { + } + + //********************************* + iterator(const iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + iterator operator ++(int) + { + iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + iterator operator =(const iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + reference operator *() + { + return inode->key; + } + + //********************************* + const_reference operator *() const + { + return inode->key; + } + + //********************************* + pointer operator &() + { + return &(inode->key); + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key); + } + + //********************************* + pointer operator ->() + { + return &(inode->key); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key); + } + + //********************************* + friend bool operator == (const iterator& lhs, const iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const iterator& lhs, const iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) + : pbuckets_end(pbuckets_end_), + pbucket(pbucket_), + inode(inode_) + { + } + + //********************************* + bool compare(const iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t*& get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + //********************************************************************* + class const_iterator : public std::iterator<std::forward_iterator_tag, const TKey> + { + public: + + typedef typename iunordered_set::value_type value_type; + typedef typename iunordered_set::key_type key_type; + typedef typename iunordered_set::hasher hasher; + typedef typename iunordered_set::key_equal key_equal; + typedef typename iunordered_set::reference reference; + typedef typename iunordered_set::const_reference const_reference; + typedef typename iunordered_set::pointer pointer; + typedef typename iunordered_set::const_pointer const_pointer; + typedef typename iunordered_set::size_type size_type; + + friend class iunordered_set; + friend class iterator; + + //********************************* + const_iterator() + { + } + + //********************************* + const_iterator(const typename iunordered_set::iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator(const const_iterator& other) + : pbuckets_end(other.pbuckets_end), + pbucket(other.pbucket), + inode(other.inode) + { + } + + //********************************* + const_iterator& operator ++() + { + ++inode; + + // The end of this node list? + if (inode == pbucket->end()) + { + // Search for the next non-empty bucket. + + ++pbucket; + while ((pbucket != pbuckets_end) && (pbucket->empty())) + { + ++pbucket; + } + + // If not past the end, get the first node in the bucket. + if (pbucket != pbuckets_end) + { + inode = pbucket->begin(); + } + } + + return *this; + } + + //********************************* + const_iterator operator ++(int) + { + const_iterator temp(*this); + operator++(); + return temp; + } + + //********************************* + const_iterator operator =(const const_iterator& other) + { + pbuckets_end = other.pbuckets_end; + pbucket = other.pbucket; + inode = other.inode; + return *this; + } + + //********************************* + const_reference operator *() const + { + return inode->key; + } + + //********************************* + const_pointer operator &() const + { + return &(inode->key); + } + + //********************************* + const_pointer operator ->() const + { + return &(inode->key); + } + + //********************************* + friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) + { + return lhs.compare(rhs); + } + + //********************************* + friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs == rhs); + } + + private: + + //********************************* + const_iterator(bucket_t* pbuckets_end_, bucket_t* pbucket_, local_iterator inode_) + : pbuckets_end(pbuckets_end_), + pbucket(pbucket_), + inode(inode_) + { + } + + //********************************* + bool compare(const const_iterator& rhs) const + { + return rhs.inode == inode; + } + + //********************************* + bucket_t& get_bucket() + { + return *pbucket; + } + + //********************************* + bucket_t*& get_bucket_list_iterator() + { + return pbucket; + } + + //********************************* + local_iterator get_local_iterator() + { + return inode; + } + + bucket_t* pbuckets_end; + bucket_t* pbucket; + local_iterator inode; + }; + + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_set. + ///\return An iterator to the beginning of the unordered_set. + //********************************************************************* + iterator begin() + { + return iterator(pbuckets + number_of_buckets, first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_set. + ///\return A const iterator to the beginning of the unordered_set. + //********************************************************************* + const_iterator begin() const + { + return const_iterator(pbuckets + number_of_buckets, first, first->begin()); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_set. + ///\return A const iterator to the beginning of the unordered_set. + //********************************************************************* + const_iterator cbegin() const + { + return const_iterator(pbuckets + number_of_buckets, first, first->begin()); + } + + //********************************************************************* + /// Returns an iterator to the beginning of the unordered_set bucket. + ///\return An iterator to the beginning of the unordered_set bucket. + //********************************************************************* + local_iterator begin(size_t i) + { + return pbuckets[i].begin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_set bucket. + ///\return A const iterator to the beginning of the unordered_set bucket. + //********************************************************************* + local_const_iterator begin(size_t i) const + { + return pbuckets[i].cbegin(); + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the unordered_set bucket. + ///\return A const iterator to the beginning of the unordered_set bucket. + //********************************************************************* + local_const_iterator cbegin(size_t i) const + { + return pbuckets[i].cbegin(); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_set. + ///\return An iterator to the end of the unordered_set. + //********************************************************************* + iterator end() + { + return iterator(pbuckets + number_of_buckets, last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_set. + ///\return A const iterator to the end of the unordered_set. + //********************************************************************* + const_iterator end() const + { + return const_iterator(pbuckets + number_of_buckets, last, last->end()); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_set. + ///\return A const iterator to the end of the unordered_set. + //********************************************************************* + const_iterator cend() const + { + return const_iterator(pbuckets + number_of_buckets, last, last->end()); + } + + //********************************************************************* + /// Returns an iterator to the end of the unordered_set bucket. + ///\return An iterator to the end of the unordered_set bucket. + //********************************************************************* + local_iterator end(size_t i) + { + return pbuckets[i].end(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_set bucket. + ///\return A const iterator to the end of the unordered_set bucket. + //********************************************************************* + local_const_iterator end(size_t i) const + { + return pbuckets[i].cend(); + } + + //********************************************************************* + /// Returns a const_iterator to the end of the unordered_set bucket. + ///\return A const iterator to the end of the unordered_set bucket. + //********************************************************************* + local_const_iterator cend(size_t i) const + { + return pbuckets[i].cend(); + } + + //********************************************************************* + /// Returns the bucket index for the key. + ///\return The bucket index for the key. + //********************************************************************* + size_type get_bucket_index(key_parameter_t key) const + { + return key_hash_function(key) % number_of_buckets; + } + + //********************************************************************* + /// Returns the size of the bucket key. + ///\return The bucket size of the bucket key. + //********************************************************************* + size_type bucket_size(key_parameter_t key) const + { + size_t index = bucket(key); + + return std::distance(pbuckets[index].begin(), pbuckets[index].end()); + } + + //********************************************************************* + /// Returns the maximum number of the buckets the container can hold. + ///\return The maximum number of the buckets the container can hold. + //********************************************************************* + size_type max_bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Returns the number of the buckets the container holds. + ///\return The number of the buckets the container holds. + //********************************************************************* + size_type bucket_count() const + { + return number_of_buckets; + } + + //********************************************************************* + /// Assigns values to the unordered_set. + /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set does not have enough free space. + /// If asserts or exceptions are enabled, emits unordered_set_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first_, TIterator last_) + { +#if defined(ETL_DEBUG) + difference_type d = std::distance(first_, last_); + ETL_ASSERT(d >= 0, ETL_ERROR(unordered_set_iterator)); + ETL_ASSERT(size_t(d) <= max_size(), ETL_ERROR(unordered_set_full)); +#endif + + clear(); + + while (first_ != last_) + { + insert(*first_++); + } + } + + //********************************************************************* + /// Inserts a value to the unordered_set. + /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set is already full. + ///\param value The value to insert. + //********************************************************************* + std::pair<iterator, bool> insert(const value_type& key) + { + std::pair<iterator, bool> result(end(), false); + + ETL_ASSERT(!full(), ETL_ERROR(unordered_set_full)); + + // Get the hash index. + size_t index = get_bucket_index(key); + + // Get the bucket & bucket iterator. + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // The first one in the bucket? + if (bucket.empty()) + { + // Get a new node. + node_t& node = *pnodepool->allocate<node_t>(); + ::new (&node.key) value_type(key); + ++construct_count; + + // Just add the pointer to the bucket; + bucket.insert_after(bucket.before_begin(), node); + + result.first = iterator(pbuckets + number_of_buckets, pbucket, pbucket->begin()); + result.second = true; + + adjust_first_last_markers(pbucket); + } + else + { + // Step though the bucket looking for a place to insert. + local_iterator inode_previous = bucket.before_begin(); + local_iterator inode = bucket.begin(); + + while (inode != bucket.end()) + { + // Do we already have this key? + if (inode->key == key) + { + break; + } + + ++inode_previous; + ++inode; + } + + // Not already there? + if (inode == bucket.end()) + { + // Get a new node. + node_t& node = *pnodepool->allocate<node_t>(); + ::new (&node.key) value_type(key); + ++construct_count; + + // Add the node to the end of the bucket; + bucket.insert_after(inode_previous, node); + ++inode_previous; + + result.first = iterator(pbuckets + number_of_buckets, pbucket, inode_previous); + result.second = true; + } + } + + return result; + } + + //********************************************************************* + /// Inserts a value to the unordered_set. + /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set is already full. + ///\param position The position to insert at. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator position, const value_type& key) + { + return insert(key).first; + } + + //********************************************************************* + /// Inserts a range of values to the unordered_set. + /// If asserts or exceptions are enabled, emits unordered_set_full if the unordered_set does not have enough free space. + ///\param position The position to insert at. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(TIterator first_, TIterator last_) + { + while (first_ != last_) + { + insert(*first_++); + } + } + + //********************************************************************* + /// Erases an element. + ///\param key The key to erase. + ///\return The number of elements erased. 0 or 1. + //********************************************************************* + size_t erase(key_parameter_t key) + { + size_t n = 0; + size_t index = get_bucket_index(key); + + bucket_t& bucket = pbuckets[index]; + + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = bucket.begin(); + + // Search for the key, if we have it. + while ((icurrent != bucket.end()) && (icurrent->key != key)) + { + ++iprevious; + ++icurrent; + } + + // Did we find it? + if (icurrent != bucket.end()) + { + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + n = 1; + --construct_count; + } + + return n; + } + + //********************************************************************* + /// Erases an element. + ///\param ielement Iterator to the element. + //********************************************************************* + iterator erase(const_iterator ielement) + { + // Make a note of the next one. + iterator inext((pbuckets + number_of_buckets), ielement.get_bucket_list_iterator(), ielement.get_local_iterator()); + ++inext; + + bucket_t& bucket = ielement.get_bucket(); + local_iterator iprevious = bucket.before_begin(); + local_iterator icurrent = ielement.get_local_iterator(); + + // Find the node previous to the one we're interested in. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + bucket.erase_after(iprevious); // Unlink from the bucket. + icurrent->key.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + return inext; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed to by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + //********************************************************************* + iterator erase(const_iterator first_, const_iterator last_) + { + // Make a note of the last. + iterator result((pbuckets + number_of_buckets), last_.get_bucket_list_iterator(), last_.get_local_iterator()); + + // Get the starting point. + bucket_t* pbucket = first_.get_bucket_list_iterator(); + local_iterator iprevious = pbucket->before_begin(); + local_iterator icurrent = first_.get_local_iterator(); + local_iterator iend = last_.get_local_iterator(); // Note: May not be in the same bucket as icurrent. + + // Find the node previous to the first one. + while (iprevious->etl_next != &*icurrent) + { + ++iprevious; + } + + while (icurrent != iend) + { + + local_iterator inext = pbucket->erase_after(iprevious); // Unlink from the bucket. + icurrent->key.~value_type(); // Destroy the value. + pnodepool->release(&*icurrent); // Release it back to the pool. + --construct_count; + + icurrent = inext; + + // Are we there yet? + if (icurrent != iend) + { + // At the end of this bucket? + if ((icurrent == pbucket->end())) + { + // Find the next non-empty one. + do + { + ++pbucket; + } while (pbucket->empty()); + + iprevious = pbucket->before_begin(); + icurrent = pbucket->begin(); + } + } + } + + return result; + } + + //************************************************************************* + /// Clears the unordered_set. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Counts an element. + ///\param key The key to search for. + ///\return 1 if the key exists, otherwise 0. + //********************************************************************* + size_t count(key_parameter_t key) const + { + return (find(key) == end()) ? 0 : 1; + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + iterator find(key_parameter_t key) + { + size_t index = get_bucket_index(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key)) + { + return iterator(pbuckets + number_of_buckets, pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Finds an element. + ///\param key The key to search for. + ///\return An iterator to the element if the key exists, otherwise end(). + //********************************************************************* + const_iterator find(key_parameter_t key) const + { + size_t index = get_bucket_index(key); + + bucket_t* pbucket = pbuckets + index; + bucket_t& bucket = *pbucket; + + // Is the bucket not empty? + if (!bucket.empty()) + { + // Step though the list until we find the end or an equivalent key. + local_iterator inode = bucket.begin(); + local_iterator iend = bucket.end(); + + while (inode != iend) + { + // Do we have this one? + if (key_equal_function(key, inode->key)) + { + return iterator(pbuckets + number_of_buckets, pbucket, inode); + } + + ++inode; + } + } + + return end(); + } + + //********************************************************************* + /// Returns a range containing all elements with key 'key' in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return An iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair<iterator, iterator> equal_range(key_parameter_t key) + { + iterator f = find(key); + iterator l = f; + + if (l != end()) + { + ++l; + } + + return std::pair<iterator, iterator>(f, l); + } + + //********************************************************************* + /// Returns a range containing all elements with key 'key' in the container. + /// The range is defined by two iterators, the first pointing to the first + /// element of the wanted range and the second pointing past the last + /// element of the range. + ///\param key The key to search for. + ///\return A const iterator pair to the range of elements if the key exists, otherwise end(). + //********************************************************************* + std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const + { + const_iterator f = find(key); + const_iterator l = f; + + if (l != end()) + { + ++l; + } + + return std::pair<const_iterator, const_iterator>(f, l); + } + + //************************************************************************* + /// Gets the size of the unordered_set. + //************************************************************************* + size_type size() const + { + return pnodepool->size(); + } + + //************************************************************************* + /// Gets the maximum possible size of the unordered_set. + //************************************************************************* + size_type max_size() const + { + return pnodepool->max_size(); + } + + //************************************************************************* + /// Checks to see if the unordered_set is empty. + //************************************************************************* + bool empty() const + { + return pnodepool->empty(); + } + + //************************************************************************* + /// Checks to see if the unordered_set is full. + //************************************************************************* + bool full() const + { + return pnodepool->full(); + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return pnodepool->available(); + } + + //************************************************************************* + /// Returns the load factor = size / bucket_count. + ///\return The load factor = size / bucket_count. + //************************************************************************* + float load_factor() const + { + return static_cast<float>(size()) / static_cast<float>(bucket_count()); + } + + //************************************************************************* + /// Returns the function that hashes the keys. + ///\return The function that hashes the keys.. + //************************************************************************* + hasher hash_function() const + { + return key_hash_function; + } + + //************************************************************************* + /// Returns the function that compares the keys. + ///\return The function that compares the keys.. + //************************************************************************* + key_equal key_eq() const + { + return key_equal_function; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + iunordered_set& operator = (const iunordered_set& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + iunordered_set(pool_t& node_pool_, bucket_t* pbuckets_, size_t number_of_buckets_) + : pnodepool(&node_pool_), + pbuckets(pbuckets_), + number_of_buckets(number_of_buckets_) + { + } + + //********************************************************************* + /// Initialise the unordered_set. + //********************************************************************* + void initialise() + { + if (!empty()) + { + // For each bucket... + for (size_t i = 0; i < number_of_buckets; ++i) + { + bucket_t& bucket = pbuckets[i]; + + if (!bucket.empty()) + { + // For each item in the bucket... + local_iterator it = bucket.begin(); + + while (it != bucket.end()) + { + // Destroy the value contents. + it->key.~value_type(); + ++it; + --construct_count; + } + + // Now it's safe to clear the bucket. + bucket.clear(); + } + } + + // Now it's safe to clear the entire pool in one go. + pnodepool->release_all(); + } + + first = pbuckets; + last = first; + } + + private: + + //********************************************************************* + /// Adjust the first and last markers according to the new entry. + //********************************************************************* + void adjust_first_last_markers(bucket_t* pbucket) + { + if (pbucket < first) + { + first = pbucket; + } + else if (pbucket > last) + { + last = pbucket; + } + } + + // Disable copy construction. + iunordered_set(const iunordered_set&); + + /// The pool of data nodes used in the list. + pool_t* pnodepool; + + /// The bucket list. + bucket_t* pbuckets; + + /// The number of buckets. + const size_t number_of_buckets; + + /// The first and last iterators to buckets with values. + bucket_t* first; + bucket_t* last; + + /// The function that creates the hashes. + hasher key_hash_function; + + /// The function that compares the keys for equality. + key_equal key_equal_function; + + /// For library debugging purposes only. + etl::debug_count construct_count; + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first unordered_set. + ///\param rhs Reference to the second unordered_set. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup unordered_set + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator ==(const etl::iunordered_set<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_set<TKey, TMapped, TKeyCompare>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first unordered_set. + ///\param rhs Reference to the second unordered_set. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup unordered_set + //*************************************************************************** + template <typename TKey, typename TMapped, typename TKeyCompare> + bool operator !=(const etl::iunordered_set<TKey, TMapped, TKeyCompare>& lhs, const etl::iunordered_set<TKey, TMapped, TKeyCompare>& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// A templated unordered_set implementation that uses a fixed size buffer. + //************************************************************************* + template <typename TKey, const size_t MAX_SIZE_, size_t MAX_BUCKETS_ = MAX_SIZE_, typename THash = etl::hash<TKey>, typename TKeyEqual = std::equal_to<TKey> > + class unordered_set : public etl::iunordered_set<TKey, THash, TKeyEqual> + { + private: + + typedef etl::iunordered_set<TKey, THash, TKeyEqual> base; + + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + static const size_t MAX_BUCKETS = MAX_BUCKETS_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + unordered_set() + : base(node_pool, buckets, MAX_BUCKETS) + { + base::initialise(); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + unordered_set(const unordered_set& other) + : base(node_pool, buckets, MAX_BUCKETS) + { + base::assign(other.cbegin(), other.cend()); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + unordered_set(TIterator first_, TIterator last_) + : base(node_pool, buckets, MAX_BUCKETS) + { + base::assign(first_, last_); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~unordered_set() + { + base::initialise(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + unordered_set& operator = (const unordered_set& rhs) + { + // Skip if doing self assignment + if (this != &rhs) + { + base::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + private: + + /// The pool of nodes used for the unordered_set. + etl::pool<typename base::node_t, MAX_SIZE> node_pool; + + /// The buckets of node lists. + etl::intrusive_forward_list<typename base::node_t> buckets[MAX_BUCKETS_]; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/user_type.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,126 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_USER_TYPE__ +#define __ETL_USER_TYPE__ + +#include "platform.h" + +///\defgroup user_type user_type +/// Smart enumerations.<br> +/// A method of declaring a user type that also contains a set of constants, +/// but are not constrained to just those values. +/// This contrasts with 'enum_type', where the values are expected to <b>only</b> contain +/// those defined as constants. +/// <b>Declaring the enumeration.</b> +///\code +/// ETL_DECLARE_USER_TYPE(CompassDirection, int) +/// ETL_USER_TYPE(North, 0) +/// ETL_USER_TYPE(South, 180) +/// ETL_USER_TYPE(East, 90) +/// ETL_USER_TYPE(West, 270) +/// ETL_END_USER_TYPE(CompassDirection) +///\endcode +/// <b>Using the enumeration.</b> +///\code +/// CompassDirection direction; // Default construction. +/// +/// direction = CompassDirection::North; // Assignment from an enumeration constant; +/// +/// int value = int(direction); // Explicit conversion to 'int'. +/// int value = direction.get(); +/// +/// int& value = direction.get(); // Bind to internal value. +/// const int& value = direction.get(); +/// +/// direction = CompassDirection(value); // Explicit conversion from 'int'. +/// +/// direction = CompassDirection(3); // Explicit conversion from a value. +/// +/// ++direction; // Manipulate the value; +/// direction -= CompassDirection(20); +/// +/// direction = value; // Implicit conversion from 'int'. **** Compilation error **** +/// +///\endcode +///\ingroup utilities + +//***************************************************************************** +// The declaration of the structure. +//***************************************************************************** +#define ETL_DECLARE_USER_TYPE(TypeName, ValueType) \ + struct TypeName \ + { \ + /* Non-volatile definitions.*/ \ + typedef ValueType value_type; \ + TypeName() {} \ + TypeName(const TypeName &other) : value(other.value) {} \ + TypeName& operator=(const TypeName &other) { value = other.value; return *this; } \ + explicit TypeName(ValueType value_) : value(value_) {} \ + operator ValueType() const { return value; } \ + ValueType& get() { return value; } \ + const ValueType& get() const { return value; } \ + TypeName& operator ++() { ++value; return *this; } \ + TypeName operator ++(int) { TypeName temp(*this); TypeName::operator ++(); return temp; } \ + TypeName& operator --() { --value; return *this; } \ + TypeName operator --(int) { TypeName temp(*this); TypeName::operator --(); return temp; } \ + TypeName& operator +=(const ValueType& rhs) { value += rhs; return *this; } \ + TypeName& operator -=(const ValueType& rhs) { value -= rhs; return *this; } \ + TypeName& operator *=(const ValueType& rhs) { value *= rhs; return *this; } \ + TypeName& operator /=(const ValueType& rhs) { value /= rhs; return *this; } \ + TypeName& operator %=(const ValueType& rhs) { value %= rhs; return *this; } \ + TypeName& operator &=(const ValueType& rhs) { value &= rhs; return *this; } \ + TypeName& operator |=(const ValueType& rhs) { value |= rhs; return *this; } \ + TypeName& operator ^=(const ValueType& rhs) { value ^= rhs; return *this; } \ + TypeName& operator <<=(ValueType distance) { value <<= distance; return *this; } \ + TypeName& operator >>=(ValueType distance) { value >>= distance; return *this; } \ + private: \ + ValueType value; \ + public: \ + enum enum_type \ + { + +//***************************************************************************** +// The predefined constants. +//***************************************************************************** +#define ETL_USER_TYPE(enum_name, value) \ + enum_name = value, + +//***************************************************************************** +// The final section of the structure. +//***************************************************************************** +#define ETL_END_USER_TYPE(TypeName) \ + }; \ + TypeName(enum_type value_) : value(static_cast<value_type>(value_)) {} \ + }; + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,76 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_UTILITY__ +#define __ETL_UTILITY__ + +#include "platform.h" +#include "type_traits.h" + +///\defgroup utility utility +///\ingroup utilities + +namespace etl +{ + //*************************************************************************** + /// exchange + //*************************************************************************** + template <typename T, typename U = T> + T exchange(T& object, U& new_value) + { + T old_value = object; + object = new_value; + return old_value; + } + + //*************************************************************************** + /// exchange (const) + //*************************************************************************** + template <typename T, typename U = T> + T exchange(T& object, const U& new_value) + { + T old_value = object; + object = new_value; + return old_value; + } + + //*************************************************************************** + /// as_const + //*************************************************************************** + template <typename T> + typename etl::add_const<T>::type& as_const(T& t) + { + return t; + } +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/variant.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,941 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_VARIANT__ +#define __ETL_VARIANT__ + +#include <stdint.h> + +#include "platform.h" +#include "array.h" +#include "largest.h" +#include "exception.h" +#include "type_traits.h" +#include "integral_limits.h" +#include "static_assert.h" +#include "alignment.h" +#include "error_handler.h" + +#if defined(ETL_COMPILER_KEIL) + #pragma diag_suppress 940 + #pragma diag_suppress 111 +#endif + +#undef ETL_FILE +#define ETL_FILE "24" + +//***************************************************************************** +///\defgroup variant variant +/// A class that can contain one a several specified types in a type safe manner. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + namespace __private_variant__ + { + //************************************************************************* + /// Placeholder for unused template parameters. + /// This class is never instantiated. + //************************************************************************* + template <const size_t ID> + struct no_type + { + }; + } + + //*************************************************************************** + /// Base exception for the variant class. + ///\ingroup variant + //*************************************************************************** + class variant_exception : public exception + { + public: + variant_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// 'Unsupported type' exception for the variant class. + ///\ingroup variant + //*************************************************************************** + class variant_incorrect_type_exception : public variant_exception + { + public: + variant_incorrect_type_exception(string_type file_name_, numeric_type line_number_) + : variant_exception(ETL_ERROR_TEXT("variant: unsupported type", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// A template class that can store any of the types defined in the template parameter list. + /// Supports up to 8 types. + ///\ingroup variant + //*************************************************************************** + template <typename T1, + typename T2 = __private_variant__::no_type<2>, + typename T3 = __private_variant__::no_type<3>, + typename T4 = __private_variant__::no_type<4>, + typename T5 = __private_variant__::no_type<5>, + typename T6 = __private_variant__::no_type<6>, + typename T7 = __private_variant__::no_type<7>, + typename T8 = __private_variant__::no_type<8> > + class variant + { + private: + + // All types of variant are friends. + template <typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7, typename U8> + friend class variant; + + //*************************************************************************** + /// The largest type. + //*************************************************************************** + typedef typename largest_type<T1, T2, T3, T4, T5, T6, T7, T8>::type largest_t; + + //*************************************************************************** + /// The largest size. + //*************************************************************************** + static const size_t SIZE = sizeof(largest_t); + + //*************************************************************************** + /// The largest alignment. + //*************************************************************************** + static const size_t ALIGNMENT = etl::largest_alignment<T1, T2, T3, T4, T5, T6, T7, T8>::value; + + //*************************************************************************** + /// The type used for ids. + //*************************************************************************** + typedef uint_least8_t type_id_t; + + //*************************************************************************** + /// The id a unsupported types. + //*************************************************************************** + static const type_id_t UNSUPPORTED_TYPE_ID = integral_limits<type_id_t>::max; + + //*************************************************************************** + /// Short form of no_type placeholders. + //*************************************************************************** + typedef __private_variant__::no_type<2> no_type2; + typedef __private_variant__::no_type<3> no_type3; + typedef __private_variant__::no_type<4> no_type4; + typedef __private_variant__::no_type<5> no_type5; + typedef __private_variant__::no_type<6> no_type6; + typedef __private_variant__::no_type<7> no_type7; + typedef __private_variant__::no_type<8> no_type8; + + //*************************************************************************** + /// Lookup the id of type. + //*************************************************************************** + template <typename T> + struct Type_Id_Lookup + { + static const uint_least8_t type_id = etl::is_same<T, T1>::value ? 0 : + etl::is_same<T, T2>::value ? 1 : + etl::is_same<T, T3>::value ? 2 : + etl::is_same<T, T4>::value ? 3 : + etl::is_same<T, T5>::value ? 4 : + etl::is_same<T, T6>::value ? 5 : + etl::is_same<T, T7>::value ? 6 : + etl::is_same<T, T8>::value ? 7 : + UNSUPPORTED_TYPE_ID; + }; + + //*************************************************************************** + /// Lookup for the id of type. + //*************************************************************************** + template <typename T> + struct Type_Is_Supported : public integral_constant<bool, + is_same<T, T1>::value || + is_same<T, T2>::value || + is_same<T, T3>::value || + is_same<T, T4>::value || + is_same<T, T5>::value || + is_same<T, T6>::value || + is_same<T, T7>::value || + is_same<T, T8>::value> + { + }; + + public: + + //*************************************************************************** + /// Destructor. + //*************************************************************************** + ~variant() + { + destruct_current(); + } + + //************************************************************************* + //**** Reader types ******************************************************* + //************************************************************************* + + //************************************************************************* + /// Base reader type functor class. + /// Allows for typesafe access to the stored value types. + /// Define the reader type for 8 types. + //************************************************************************* + template <typename R1, typename R2 = no_type2, typename R3 = no_type3, typename R4 = no_type4, typename R5 = no_type5, typename R6 = no_type6, typename R7 = no_type7, typename R8 = no_type8> + class reader_type + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + virtual void read(typename etl::parameter_type<R5>::type value) = 0; + virtual void read(typename etl::parameter_type<R6>::type value) = 0; + virtual void read(typename etl::parameter_type<R7>::type value) = 0; + virtual void read(typename etl::parameter_type<R8>::type value) = 0; + }; + + //************************************************************************* + /// Define the reader type for 7 types. + //************************************************************************* + template <typename R1, typename R2, typename R3, typename R4, typename R5, typename R6, typename R7> + class reader_type<R1, R2, R3, R4, R5, R6, R7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + virtual void read(typename etl::parameter_type<R5>::type value) = 0; + virtual void read(typename etl::parameter_type<R6>::type value) = 0; + virtual void read(typename etl::parameter_type<R7>::type value) = 0; + + private: + + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 6 types. + //************************************************************************* + template <typename R1, typename R2, typename R3, typename R4, typename R5, typename R6> + class reader_type<R1, R2, R3, R4, R5, R6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + virtual void read(typename etl::parameter_type<R5>::type value) = 0; + virtual void read(typename etl::parameter_type<R6>::type value) = 0; + + private: + + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 5 types. + //************************************************************************* + template <typename R1, typename R2, typename R3, typename R4, typename R5> + class reader_type<R1, R2, R3, R4, R5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + virtual void read(typename etl::parameter_type<R5>::type value) = 0; + + private: + + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 4 types. + //************************************************************************* + template <typename R1, typename R2, typename R3, typename R4> + class reader_type<R1, R2, R3, R4, no_type5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + virtual void read(typename etl::parameter_type<R4>::type value) = 0; + + private: + + void read(no_type5&) {}; + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 3 types. + //************************************************************************* + template <typename R1, typename R2, typename R3> + class reader_type<R1, R2, R3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + virtual void read(typename etl::parameter_type<R3>::type value) = 0; + + private: + + void read(no_type4&) {}; + void read(no_type5&) {}; + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 2 types. + //************************************************************************* + template <typename R1, typename R2> + class reader_type<R1, R2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + virtual void read(typename etl::parameter_type<R2>::type value) = 0; + + private: + + void read(no_type3&) {}; + void read(no_type4&) {}; + void read(no_type5&) {}; + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + /// Define the reader type for 1 type. + //************************************************************************* + template <typename R1> + class reader_type<R1, no_type2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + friend class variant; + + virtual void read(typename etl::parameter_type<R1>::type value) = 0; + + private: + + void read(no_type2&) {}; + void read(no_type3&) {}; + void read(no_type4&) {}; + void read(no_type5&) {}; + void read(no_type6&) {}; + void read(no_type7&) {}; + void read(no_type8&) {}; + }; + + //************************************************************************* + //**** Up-cast functors *************************************************** + //************************************************************************* + + //************************************************************************* + /// Base upcast_functor for eight types. + //************************************************************************* + template <typename TBase, typename U1, typename U2 = no_type2, typename U3 = no_type3, typename U4 = no_type4, typename U5 = no_type5, typename U6 = no_type6, typename U7 = no_type7, typename U8 = no_type8> + class upcast_functor + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + case 4: return reinterpret_cast<U5&>(*p_data); + case 5: return reinterpret_cast<U6&>(*p_data); + case 6: return reinterpret_cast<U7&>(*p_data); + case 7: return reinterpret_cast<U8&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + case 4: return reinterpret_cast<const U5&>(*p_data); + case 5: return reinterpret_cast<const U6&>(*p_data); + case 6: return reinterpret_cast<const U7&>(*p_data); + case 7: return reinterpret_cast<const U8&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for seven types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7> + class upcast_functor<TBase, U1, U2, U3, U4, U5, U6, U7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + case 4: return reinterpret_cast<U5&>(*p_data); + case 5: return reinterpret_cast<U6&>(*p_data); + case 6: return reinterpret_cast<U7&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + case 4: return reinterpret_cast<const U5&>(*p_data); + case 5: return reinterpret_cast<const U6&>(*p_data); + case 6: return reinterpret_cast<const U7&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for six types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5, typename U6> + class upcast_functor<TBase, U1, U2, U3, U4, U5, U6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + case 4: return reinterpret_cast<U5&>(*p_data); + case 5: return reinterpret_cast<U6&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + case 4: return reinterpret_cast<const U5&>(*p_data); + case 5: return reinterpret_cast<const U6&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for five types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3, typename U4, typename U5> + class upcast_functor<TBase, U1, U2, U3, U4, U5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + case 4: return reinterpret_cast<U5&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + case 4: return reinterpret_cast<const U5&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for four types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3, typename U4> + class upcast_functor<TBase, U1, U2, U3, U4, no_type5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + case 3: return reinterpret_cast<U4&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + case 3: return reinterpret_cast<const U4&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for three types. + //************************************************************************* + template <typename TBase, typename U1, typename U2, typename U3> + class upcast_functor<TBase, U1, U2, U3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + case 2: return reinterpret_cast<U3&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + case 2: return reinterpret_cast<const U3&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for two types. + //************************************************************************* + template <typename TBase, typename U1, typename U2> + class upcast_functor<TBase, U1, U2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + switch (typeId) + { + case 0: return reinterpret_cast<U1&>(*p_data); + case 1: return reinterpret_cast<U2&>(*p_data); + default: return reinterpret_cast<TBase&>(*reinterpret_cast<TBase*>(0)); + } + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + switch (typeId) + { + case 0: return reinterpret_cast<const U1&>(*p_data); + case 1: return reinterpret_cast<const U2&>(*p_data); + default: return reinterpret_cast<const TBase&>(*reinterpret_cast<const TBase*>(0)); + } + } + }; + + //************************************************************************* + /// Upcast_functor for one type. + //************************************************************************* + template <typename TBase, typename U1> + class upcast_functor<TBase, U1, no_type2, no_type3, no_type4, no_type5, no_type6, no_type7, no_type8> + { + public: + + TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) + { + return reinterpret_cast<U1&>(*p_data); + } + + const TBase& operator()(uint_least8_t* p_data, uint_least8_t typeId) const + { + return reinterpret_cast<const U1&>(*p_data); + } + }; + + //*************************************************************************** + /// The base type for derived readers. + //*************************************************************************** + typedef reader_type<T1, T2, T3, T4, T5, T6, T7, T8> reader; + + //*************************************************************************** + /// Default constructor. + /// Sets the state of the instance to containing no valid data. + //*************************************************************************** + variant() + : type_id(UNSUPPORTED_TYPE_ID) + { + } + + //*************************************************************************** + /// Constructor that catches any types that are not supported. + /// Forces a STATIC_ASSERT. + //*************************************************************************** + template <typename T> + variant(const T& value) + { + STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type"); + + ::new (static_cast<T*>(data)) T(value); + type_id = Type_Id_Lookup<T>::type_id; + } + + //*************************************************************************** + /// Copy constructor. + ///\param other The other variant object to copy. + //*************************************************************************** + variant(const variant& other) + { + switch (other.type_id) + { + case 0: ::new (static_cast<T1*>(data)) T1(other.get<T1>()); break; + case 1: ::new (static_cast<T2*>(data)) T2(other.get<T2>()); break; + case 2: ::new (static_cast<T3*>(data)) T3(other.get<T3>()); break; + case 3: ::new (static_cast<T4*>(data)) T4(other.get<T4>()); break; + case 4: ::new (static_cast<T5*>(data)) T5(other.get<T5>()); break; + case 5: ::new (static_cast<T6*>(data)) T6(other.get<T6>()); break; + case 6: ::new (static_cast<T7*>(data)) T7(other.get<T7>()); break; + case 7: ::new (static_cast<T8*>(data)) T8(other.get<T8>()); break; + default: break; + } + + type_id = other.type_id; + } + + //*************************************************************************** + /// Assignment operator for T1 type. + ///\param value The value to assign. + //*************************************************************************** + template <typename T> + variant& operator =(const T& value) + { + STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type"); + + destruct_current(); + ::new (static_cast<T*>(data)) T(value); + type_id = Type_Id_Lookup<T>::type_id; + + return *this; + } + + //*************************************************************************** + /// Assignment operator for variant type. + ///\param other The variant to assign. + //*************************************************************************** + variant& operator =(const variant& other) + { + if (this != &other) + { + destruct_current(); + + switch (other.type_id) + { + case 0: ::new (static_cast<T1*>(data)) T1(other.get<T1>()); break; + case 1: ::new (static_cast<T2*>(data)) T2(other.get<T2>()); break; + case 2: ::new (static_cast<T3*>(data)) T3(other.get<T3>()); break; + case 3: ::new (static_cast<T4*>(data)) T4(other.get<T4>()); break; + case 4: ::new (static_cast<T5*>(data)) T5(other.get<T5>()); break; + case 5: ::new (static_cast<T6*>(data)) T6(other.get<T6>()); break; + case 6: ::new (static_cast<T7*>(data)) T7(other.get<T7>()); break; + case 7: ::new (static_cast<T8*>(data)) T8(other.get<T8>()); break; + default: break; + } + + type_id = other.type_id; + } + + return *this; + } + + //*************************************************************************** + /// Checks if the type is the same as the current stored type. + /// For variants with the same type declarations. + ///\return <b>true</b> if the types are the same, otherwise <b>false</b>. + //*************************************************************************** + bool is_same_type(const variant& other) const + { + return type_id == other.type_id; + } + + //*************************************************************************** + /// Checks if the type is the same as the current stored type. + /// For variants with differing declarations. + ///\return <b>true</b> if the types are the same, otherwise <b>false</b>. + //*************************************************************************** + template <typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7, typename U8> + bool is_same_type(const variant<U1, U2, U3, U4, U5, U6, U7, U8>& other) const + { + bool is_same = false; + + switch (other.type_id) + { + case 0: is_same = (type_id == Type_Id_Lookup<U1>::type_id); break; + case 1: is_same = (type_id == Type_Id_Lookup<U2>::type_id); break; + case 2: is_same = (type_id == Type_Id_Lookup<U3>::type_id); break; + case 3: is_same = (type_id == Type_Id_Lookup<U4>::type_id); break; + case 4: is_same = (type_id == Type_Id_Lookup<U5>::type_id); break; + case 5: is_same = (type_id == Type_Id_Lookup<U6>::type_id); break; + case 6: is_same = (type_id == Type_Id_Lookup<U7>::type_id); break; + case 7: is_same = (type_id == Type_Id_Lookup<U8>::type_id); break; + default: break; + } + + return is_same; + } + + //*************************************************************************** + /// Calls the supplied reader instance. + /// The 'read' function appropriate to the current type is called with the stored value. + //*************************************************************************** + void call(reader& reader) + { + switch (type_id) + { + case 0: reader.read(static_cast<T1&>(data)); break; + case 1: reader.read(static_cast<T2&>(data)); break; + case 2: reader.read(static_cast<T3&>(data)); break; + case 3: reader.read(static_cast<T4&>(data)); break; + case 4: reader.read(static_cast<T5&>(data)); break; + case 5: reader.read(static_cast<T6&>(data)); break; + case 6: reader.read(static_cast<T7&>(data)); break; + case 7: reader.read(static_cast<T8&>(data)); break; + default: break; + } + } + + //*************************************************************************** + /// Checks whether a valid value is currently stored. + ///\return <b>true</b> if the value is valid, otherwise <b>false</b>. + //*************************************************************************** + bool is_valid() const + { + return type_id != UNSUPPORTED_TYPE_ID; + } + + //*************************************************************************** + /// Checks to see if the type currently stored is the same as that specified in the template parameter. + ///\return <b>true</b> if it is the specified type, otherwise <b>false</b>. + //*************************************************************************** + template <typename T> + bool is_type() const + { + return type_id == Type_Id_Lookup<T>::type_id; + } + + //*************************************************************************** + /// Clears the value to 'no valid stored value'. + //*************************************************************************** + void clear() + { + destruct_current(); + } + + //*************************************************************************** + /// Gets the value stored as the specified template type. + /// Throws a variant_incorrect_type_exception if the actual type is not that specified. + ///\return A reference to the value. + //*************************************************************************** + template <typename T> + T& get() + { + STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type"); + ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception)); + + return static_cast<T&>(data); + } + + //*************************************************************************** + /// Gets the value stored as the specified template type. + /// Throws a variant_incorrect_type_exception if the actual type is not that specified. + ///\return A const reference to the value. + //*************************************************************************** + template <typename T> + const T& get() const + { + STATIC_ASSERT(Type_Is_Supported<T>::value, "Unsupported type"); + ETL_ASSERT(is_type<T>(), ETL_ERROR(variant_incorrect_type_exception)); + + return static_cast<const T&>(data); + } + + //*************************************************************************** + /// Gets the value stored as the specified template type. + ///\return A reference to the value. + //*************************************************************************** + template <typename TBase> + TBase& upcast() + { + return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id); + } + + //*************************************************************************** + /// Gets the value stored as the specified template type. + ///\return A const reference to the value. + //*************************************************************************** + template <typename TBase> + const TBase& upcast() const + { + return upcast_functor<TBase, T1, T2, T3, T4, T5, T6, T7, T8>()(data, type_id); + } + + //*************************************************************************** + /// Conversion operators for each type. + //*************************************************************************** + operator T1&() { return get<T1>(); } + operator T2&() { return get<T2>(); } + operator T3&() { return get<T3>(); } + operator T4&() { return get<T4>(); } + operator T5&() { return get<T5>(); } + operator T6&() { return get<T6>(); } + operator T7&() { return get<T7>(); } + operator T8&() { return get<T8>(); } + + //*************************************************************************** + /// Checks if the template type is supported by the implementation of variant.. + ///\return <b>true</b> if the type is supported, otherwise <b>false</b>. + //*************************************************************************** + template <typename T> + static bool is_supported_type() + { + return Type_Is_Supported<T>::value; + } + + private: + + //*************************************************************************** + /// Destruct the current occupant of the variant. + //*************************************************************************** + void destruct_current() + { + switch (type_id) + { + case 0: { static_cast<T1*>(data)->~T1(); break; } + case 1: { static_cast<T2*>(data)->~T2(); break; } + case 2: { static_cast<T3*>(data)->~T3(); break; } + case 3: { static_cast<T4*>(data)->~T4(); break; } + case 4: { static_cast<T5*>(data)->~T5(); break; } + case 5: { static_cast<T6*>(data)->~T6(); break; } + case 6: { static_cast<T7*>(data)->~T7(); break; } + case 7: { static_cast<T8*>(data)->~T8(); break; } + default: { break; } + } + + type_id = UNSUPPORTED_TYPE_ID; + } + + //*************************************************************************** + /// The internal storage. + /// Aligned on a suitable boundary, which should be good for all types. + //*************************************************************************** + typename etl::aligned_storage<SIZE, ALIGNMENT>::type data; + + //*************************************************************************** + /// The id of the current stored type. + //*************************************************************************** + type_id_t type_id; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/variant_pool.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,375 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +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_VARIANT_POOL__ +#define __ETL_VARIANT_POOL__ + +#include <stdint.h> +#include <utility> + +#include "platform.h" +#include "error_handler.h" +#include "exception.h" +#include "largest.h" +#include "type_traits.h" +#include "alignment.h" +#include "static_assert.h" +#include "type_lookup.h" +#include <pool.h> + +#undef ETL_FILE +#define ETL_FILE "40" + +namespace etl +{ + //*************************************************************************** + class variant_pool_exception : public etl::exception + { + public: + + variant_pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + class variant_pool_cannot_create : public etl::variant_pool_exception + { + public: + + variant_pool_cannot_create(string_type file_name_, numeric_type line_number_) + : variant_pool_exception(ETL_ERROR_TEXT("variant_pool:cannot create", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + class variant_pool_did_not_create : public etl::variant_pool_exception + { + public: + + variant_pool_did_not_create(string_type file_name_, numeric_type line_number_) + : variant_pool_exception(ETL_ERROR_TEXT("variant_pool:did not create", ETL_FILE"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + template <const size_t MAX_SIZE_, + typename T1, + typename T2 = void, + typename T3 = void, + typename T4 = void, + typename T5 = void, + typename T6 = void, + typename T7 = void, + typename T8 = void, + typename T9 = void, + typename T10 = void, + typename T11 = void, + typename T12 = void, + typename T13 = void, + typename T14 = void, + typename T15 = void, + typename T16 = void> + class variant_pool + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Default constructor. + //************************************************************************* + variant_pool() + { + } + +#if !ETL_CPP11_SUPPORTED + //************************************************************************* + /// Creates the object. Default constructor. + //************************************************************************* + template <typename T> + T* create() + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object. One parameter constructor. + //************************************************************************* + template <typename T, typename TP1> + T* create(const TP1& p1) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(p1); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object. Two parameter constructor. + //************************************************************************* + template <typename T, typename TP1, typename TP2> + T* create(const TP1& p1, const TP2& p2) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(p1, p2); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object. Three parameter constructor. + //************************************************************************* + template <typename T, typename TP1, typename TP2, typename TP3> + T* create(const TP1& p1, const TP2& p2, const TP3& p3) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(p1, p2, p3); + } + } + + return p; + } + + //************************************************************************* + /// Creates the object. Four parameter constructor. + //************************************************************************* + template <typename T, typename TP1, typename TP2, typename TP3, typename TP4> + T* create(const TP1& p1, const TP2& p2, const TP3& p3, const TP4& p4) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(p1, p2, p3, p4); + } + } + + return p; + } +#else + //************************************************************************* + /// Creates the object from a type. Variadic parameter constructor. + //************************************************************************* + template <typename T, typename... Args> + T* create(Args&&... args) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type"); + + T* p = std::nullptr; + + if (pool.full()) + { + ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); + } + else + { + p = pool.template allocate<T>(); + + if (p != std::nullptr) + { + new (p) T(std::forward<Args>(args)...); + } + } + + return p; + } +#endif + + //************************************************************************* + /// Destroys the object. + //************************************************************************* + template <typename T> + bool destroy(const T* const p) + { + STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value || + etl::is_base_of<T, T1>::value || + etl::is_base_of<T, T2>::value || + etl::is_base_of<T, T3>::value || + etl::is_base_of<T, T4>::value || + etl::is_base_of<T, T5>::value || + etl::is_base_of<T, T6>::value || + etl::is_base_of<T, T7>::value || + etl::is_base_of<T, T8>::value || + etl::is_base_of<T, T9>::value || + etl::is_base_of<T, T10>::value || + etl::is_base_of<T, T11>::value || + etl::is_base_of<T, T12>::value || + etl::is_base_of<T, T13>::value || + etl::is_base_of<T, T14>::value || + etl::is_base_of<T, T15>::value || + etl::is_base_of<T, T16>::value), "Invalid type"); + + p->~T(); + + void* vp = reinterpret_cast<char*>(const_cast<T*>(p)); + + if (pool.is_in_pool(vp)) + { + pool.release(vp); + return true; + } + else + { + ETL_ASSERT(false, ETL_ERROR(variant_pool_did_not_create)); + return false; + } + } + + //************************************************************************* + /// Returns the maximum number of items in the variant_pool. + //************************************************************************* + size_t max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns the number of free items in the variant_pool. + //************************************************************************* + size_t available() const + { + return pool.available(); + } + + //************************************************************************* + /// Returns the number of allocated items in the variant_pool. + //************************************************************************* + size_t size() const + { + return pool.size(); + } + + //************************************************************************* + /// Checks to see if there are no allocated items in the variant_pool. + /// \return <b>true</b> if there are none allocated. + //************************************************************************* + bool empty() const + { + return pool.empty(); + } + + //************************************************************************* + /// Checks to see if there are no free items in the variant_pool. + /// \return <b>true</b> if there are none free. + //************************************************************************* + bool full() const + { + return pool.full(); + } + + private: + + variant_pool(const variant_pool&); + variant_pool& operator =(const variant_pool&); + + // The pool. + etl::generic_pool<etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size, + etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::alignment, + MAX_SIZE> pool; + }; +} + +#undef ETL_FILE + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vector.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,1242 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_VECTOR__ +#define __ETL_VECTOR__ + +#define __ETL_IN_VECTOR_H__ + +#include <stddef.h> +#include <stdint.h> +#include <iterator> +#include <algorithm> +#include <functional> +#include <stddef.h> + +#include "platform.h" +#include "algorithm.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "error_handler.h" +#include "memory.h" +#include "container.h" +#include "alignment.h" +#include "array.h" +#include "exception.h" +#include "debug_count.h" +#include "private/vector_base.h" + +#ifdef ETL_COMPILER_GCC +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +//***************************************************************************** +///\defgroup vector vector +/// A vector with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// The base class for specifically sized vectors. + /// Can be used as a reference type for all vectors containing a specific type. + ///\ingroup vector + //*************************************************************************** + template <typename T> + class ivector : public etl::vector_base + { + public: + + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef T* iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef size_t size_type; + typedef typename std::iterator_traits<iterator>::difference_type difference_type; + + protected: + + typedef typename etl::parameter_type<T>::type parameter_t; + + public: + + //********************************************************************* + /// Returns an iterator to the beginning of the vector. + ///\return An iterator to the beginning of the vector. + //********************************************************************* + iterator begin() + { + return p_buffer; + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the vector. + ///\return A const iterator to the beginning of the vector. + //********************************************************************* + const_iterator begin() const + { + return p_buffer; + } + + //********************************************************************* + /// Returns an iterator to the end of the vector. + ///\return An iterator to the end of the vector. + //********************************************************************* + iterator end() + { + return p_end; + } + + //********************************************************************* + /// Returns a const_iterator to the end of the vector. + ///\return A const iterator to the end of the vector. + //********************************************************************* + const_iterator end() const + { + return p_end; + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the vector. + ///\return A const iterator to the beginning of the vector. + //********************************************************************* + const_iterator cbegin() const + { + return p_buffer; + } + + //********************************************************************* + /// Returns a const_iterator to the end of the vector. + ///\return A const iterator to the end of the vector. + //********************************************************************* + const_iterator cend() const + { + return p_end; + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the vector. + ///\return Iterator to the reverse beginning of the vector. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the vector. + ///\return Const iterator to the reverse beginning of the vector. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the vector. + ///\return Reverse iterator to the end + 1 of the vector. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the vector. + ///\return Const reverse iterator to the end + 1 of the vector. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the vector. + ///\return Const reverse iterator to the reverse beginning of the vector. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the vector. + ///\return Const reverse iterator to the end + 1 of the vector. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + //********************************************************************* + /// Resizes the vector. + /// If asserts or exceptions are enabled and the new size is larger than the + /// maximum then a vector_full is thrown. + ///\param new_size The new size. + //********************************************************************* + void resize(size_t new_size) + { + resize(new_size, T()); + } + + //********************************************************************* + /// Resizes the vector. + /// If asserts or exceptions are enabled and the new size is larger than the + /// maximum then a vector_full is thrown. + ///\param new_size The new size. + ///\param value The value to fill new elements with. Default = default constructed value. + //********************************************************************* + void resize(size_t new_size, T value) + { + ETL_ASSERT(new_size <= CAPACITY, ETL_ERROR(vector_full)); + + const size_t current_size = size(); + size_t delta = (current_size < new_size) ? new_size - current_size : current_size - new_size; + + if (current_size < new_size) + { + etl::uninitialized_fill_n(p_end, delta, value); +#if defined(ETL_DEBUG) + construct_count += delta; +#endif + } + else + { + etl::destroy_n(p_end - delta, delta); +#if defined(ETL_DEBUG) + construct_count -= delta; +#endif + } + + p_end = p_buffer + new_size; + } + + //********************************************************************* + /// Does nothing. + //********************************************************************* + void reserve(size_t) + { + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference operator [](size_t i) + { + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference operator [](size_t i) const + { + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference at(size_t i) + { + ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds)); + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::vector_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference at(size_t i) const + { + ETL_ASSERT(i < size(), ETL_ERROR(vector_out_of_bounds)); + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a reference to the first element. + ///\return A reference to the first element. + //********************************************************************* + reference front() + { + return *p_buffer; + } + + //********************************************************************* + /// Returns a const reference to the first element. + ///\return A const reference to the first element. + //********************************************************************* + const_reference front() const + { + return *p_buffer; + } + + //********************************************************************* + /// Returns a reference to the last element. + ///\return A reference to the last element. + //********************************************************************* + reference back() + { + return *(p_end - 1); + } + + //********************************************************************* + /// Returns a const reference to the last element. + ///\return A const reference to the last element. + //********************************************************************* + const_reference back() const + { + return *(p_end - 1); + } + + //********************************************************************* + /// Returns a pointer to the beginning of the vector data. + ///\return A pointer to the beginning of the vector data. + //********************************************************************* + pointer data() + { + return p_buffer; + } + + //********************************************************************* + /// Returns a const pointer to the beginning of the vector data. + ///\return A const pointer to the beginning of the vector data. + //********************************************************************* + const_pointer data() const + { + return p_buffer; + } + + //********************************************************************* + /// Assigns values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + /// If asserts or exceptions are enabled, emits vector_iterator if the iterators are reversed. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template <typename TIterator> + void assign(TIterator first, TIterator last) + { + STATIC_ASSERT((etl::is_same<typename etl::remove_cv<T>::type, typename etl::remove_cv<typename std::iterator_traits<TIterator>::value_type>::type>::value), "Iterator type does not match container type"); + +#if defined(ETL_DEBUG) + difference_type d = std::distance(first, last); + ETL_ASSERT(static_cast<size_t>(d) <= CAPACITY, ETL_ERROR(vector_full)); +#endif + + initialise(); + +#if defined(ETL_DEBUG) + p_end = etl::uninitialized_copy(first, last, p_buffer, construct_count); +#else + p_end = etl::uninitialized_copy(first, last, p_buffer); +#endif + } + + //********************************************************************* + /// Assigns values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + ///\param n The number of elements to add. + ///\param value The value to insert for each element. + //********************************************************************* + void assign(size_t n, parameter_t value) + { + ETL_ASSERT(n <= CAPACITY, ETL_ERROR(vector_full)); + + initialise(); + +#if defined(ETL_DEBUG) + p_end = etl::uninitialized_fill_n(p_buffer, n, value, construct_count); +#else + p_end = etl::uninitialized_fill_n(p_buffer, n, value); +#endif + } + + //************************************************************************* + /// Clears the vector. + //************************************************************************* + void clear() + { + initialise(); + } + + //************************************************************************* + /// Increases the size of the vector by one, but does not initialise the new element. + /// If asserts or exceptions are enabled, throws a vector_full if the vector is already full. + //************************************************************************* + void push_back() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); +#endif + + create_back(); + } + + //********************************************************************* + /// Inserts a value at the end of the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param value The value to add. + //********************************************************************* + void push_back(parameter_t value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); +#endif + create_back(value); + } + + //********************************************************************* + /// Constructs a value at the end of the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param value The value to add. + //********************************************************************* + template <typename T1> + void emplace_back(const T1& value1) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); +#endif + ::new (p_end) T(value1); + ++p_end; + ++construct_count; + } + + //********************************************************************* + /// Constructs a value at the end of the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param value The value to add. + //********************************************************************* + template <typename T1, typename T2> + void emplace_back(const T1& value1, const T2& value2) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); +#endif + ::new (p_end) T(value1, value2); + ++p_end; + ++construct_count; + } + + //********************************************************************* + /// Constructs a value at the end of the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param value The value to add. + //********************************************************************* + template <typename T1, typename T2, typename T3> + void emplace_back(const T1& value1, const T2& value2, const T3& value3) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); +#endif + ::new (p_end) T(value1, value2, value3); + ++p_end; + ++construct_count; + } + + //********************************************************************* + /// Constructs a value at the end of the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param value The value to add. + //********************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + void emplace_back(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() != CAPACITY, ETL_ERROR(vector_full)); +#endif + ::new (p_end) T(value1, value2, value3, value4); + ++p_end; + ++construct_count; + } + + //************************************************************************* + /// Removes an element from the end of the vector. + /// Does nothing if the vector is empty. + //************************************************************************* + void pop_back() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(size() > 0, ETL_ERROR(vector_empty)); +#endif + destroy_back(); + } + + //********************************************************************* + /// Inserts a value to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector is already full. + ///\param position The position to insert before. + ///\param value The value to insert. + //********************************************************************* + iterator insert(iterator position, parameter_t value) + { + ETL_ASSERT(size() + 1 <= CAPACITY, ETL_ERROR(vector_full)); + + if (position == end()) + { + create_back(value); + } + else + { + create_back(back()); + std::copy_backward(position, p_end - 1, p_end); + *position = value; + } + + return position; + } + + //************************************************************************* + /// Emplaces a value to the vextor at the specified position. + //************************************************************************* + template <typename T1> + iterator emplace(iterator position, const T1& value1) + { + ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + + void* p; + + if (position == end()) + { + p = p_end++; + ++construct_count; + } + else + { + p = etl::addressof(*position); + create_back(back()); + std::copy_backward(position, p_end - 1, p_end); + (*position).~T(); + } + + ::new (p) T(value1); + + return position; + } + + //************************************************************************* + /// Emplaces a value to the vextor at the specified position. + //************************************************************************* + template <typename T1, typename T2> + iterator emplace(iterator position, const T1& value1, const T2& value2) + { + ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + + void* p; + + if (position == end()) + { + p = p_end++; + ++construct_count; + } + else + { + p = etl::addressof(*position); + create_back(back()); + std::copy_backward(position, p_end - 1, p_end); + (*position).~T(); + } + + ::new (p) T(value1, value2); + + return position; + } + + //************************************************************************* + /// Emplaces a value to the vextor at the specified position. + //************************************************************************* + template <typename T1, typename T2, typename T3> + iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3) + { + ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + + void* p; + + if (position == end()) + { + p = p_end++; + ++construct_count; + } + else + { + p = etl::addressof(*position); + create_back(back()); + std::copy_backward(position, p_end - 1, p_end); + (*position).~T(); + } + + ::new (p) T(value1, value2, value3); + + return position; + } + + //************************************************************************* + /// Emplaces a value to the vextor at the specified position. + //************************************************************************* + template <typename T1, typename T2, typename T3, typename T4> + iterator emplace(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + ETL_ASSERT(!full(), ETL_ERROR(vector_full)); + + void* p; + + if (position == end()) + { + p = p_end++; + ++construct_count; + } + else + { + p = etl::addressof(*position); + create_back(back()); + std::copy_backward(position, p_end - 1, p_end); + (*position).~T(); + } + + ::new (p) T(value1, value2, value3, value4); + + return position; + } + + //********************************************************************* + /// Inserts 'n' values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + ///\param position The position to insert before. + ///\param n The number of elements to add. + ///\param value The value to insert. + //********************************************************************* + void insert(iterator position, size_t n, parameter_t value) + { + ETL_ASSERT((size() + n) <= CAPACITY, ETL_ERROR(vector_full)); + + size_t insert_n = n; + size_t insert_begin = std::distance(begin(), position); + size_t insert_end = insert_begin + insert_n; + + // Copy old data. + size_t copy_old_n; + size_t construct_old_n; + iterator p_construct_old; + + if (insert_end > size()) + { + copy_old_n = 0; + construct_old_n = size() - insert_begin; + p_construct_old = p_buffer + insert_end; + } + else + { + copy_old_n = size() - insert_begin - insert_n; + construct_old_n = insert_n; + p_construct_old = p_end; + } + + size_t copy_new_n = construct_old_n; + size_t construct_new_n = insert_n - copy_new_n; + +#if defined(ETL_DEBUG) + // Construct old. + etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old, construct_count); + + // Copy old. + etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end); + + // Construct new. + etl::uninitialized_fill_n(p_end, construct_new_n, value, construct_count); + + // Copy new. + std::fill_n(p_buffer + insert_begin, copy_new_n, value); +#else + // Construct old. + etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old); + + // Copy old. + etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end); + + // Construct new. + etl::uninitialized_fill_n(p_end, construct_new_n, value); + + // Copy new. + std::fill_n(p_buffer + insert_begin, copy_new_n, value); +#endif + + p_end += n; + } + + //********************************************************************* + /// Inserts a range of values to the vector. + /// If asserts or exceptions are enabled, emits vector_full if the vector does not have enough free space. + /// For fundamental and pointer types. + ///\param position The position to insert before. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template <class TIterator> + void insert(iterator position, TIterator first, TIterator last) + { + size_t count = std::distance(first, last); + + ETL_ASSERT((size() + count) <= CAPACITY, ETL_ERROR(vector_full)); + + size_t insert_n = count; + size_t insert_begin = std::distance(begin(), position); + size_t insert_end = insert_begin + insert_n; + + // Copy old data. + size_t copy_old_n; + size_t construct_old_n; + iterator p_construct_old; + + if (insert_end > size()) + { + copy_old_n = 0; + construct_old_n = size() - insert_begin; + p_construct_old = p_buffer + insert_end; + } + else + { + copy_old_n = size() - insert_begin - insert_n; + construct_old_n = insert_n; + p_construct_old = p_end; + } + + size_t copy_new_n = construct_old_n; + size_t construct_new_n = insert_n - copy_new_n; + +#if defined(ETL_DEBUG) + // Construct old. + etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old, construct_count); + + // Copy old. + etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end); + + // Construct new. + etl::uninitialized_copy_n(first + copy_new_n, construct_new_n, p_end, construct_count); + + // Copy new. + etl::copy_n(first, copy_new_n, p_buffer + insert_begin); +#else + // Construct old. + etl::uninitialized_copy_n(p_end - construct_old_n, construct_old_n, p_construct_old); + + // Copy old. + etl::copy_n(p_buffer + insert_begin, copy_old_n, p_buffer + insert_end); + + // Construct new. + etl::uninitialized_copy_n(first + copy_new_n, construct_new_n, p_end); + + // Copy new. + etl::copy_n(first, copy_new_n, p_buffer + insert_begin); +#endif + + p_end += count; + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(iterator i_element) + { + std::copy(i_element + 1, end(), i_element); + destroy_back(); + + return i_element; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(iterator first, iterator last) + { + if (first == begin() && last == end()) + { + clear(); + } + else + { + std::copy(last, end(), first); + size_t n_delete = std::distance(first, last); + + // Destroy the elements left over at the end. +#if defined(ETL_DEBUG) + etl::destroy(p_end - n_delete, p_end, construct_count); +#else + etl::destroy(p_end - n_delete, p_end); +#endif + p_end -= n_delete; + } + + return first; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + ivector& operator = (const ivector& rhs) + { + if (&rhs != this) + { + assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Gets the current size of the vector. + ///\return The current size of the vector. + //************************************************************************* + size_type size() const + { + return size_t(p_end - p_buffer); + } + + //************************************************************************* + /// Checks the 'empty' state of the vector. + ///\return <b>true</b> if empty. + //************************************************************************* + bool empty() const + { + return (p_end == p_buffer); + } + + //************************************************************************* + /// Checks the 'full' state of the vector. + ///\return <b>true</b> if full. + //************************************************************************* + bool full() const + { + return size() == CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + +#ifdef ETL_IVECTOR_REPAIR_ENABLE + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + virtual void repair() = 0; +#endif + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + ivector(T* p_buffer_, size_t MAX_SIZE) + : vector_base(MAX_SIZE), + p_buffer(p_buffer_), + p_end(p_buffer_) + { + } + + //********************************************************************* + /// Initialise the vector. + //********************************************************************* + void initialise() + { +#if defined(ETL_DEBUG) + etl::destroy(p_buffer, p_end, construct_count); +#else + etl::destroy(p_buffer, p_end); +#endif + + p_end = p_buffer; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair(T* p_buffer_) + { + uintptr_t length = p_end - p_buffer; + p_buffer = p_buffer_; + p_end = p_buffer_ + length; + } + + private: + + pointer p_buffer; ///< Pointer to the start of the buffer. + pointer p_end; ///< Pointer to one past the last element in the buffer. + + //********************************************************************* + /// Create a new element with a default value at the back. + //********************************************************************* + inline void create_back() + { +#if defined(ETL_DEBUG) + etl::create_value_at(p_end, construct_count); +#else + etl::create_value_at(p_end); +#endif + ++p_end; + } + + //********************************************************************* + /// Create a new element with a value at the back + //********************************************************************* + inline void create_back(parameter_t value) + { +#if defined(ETL_DEBUG) + etl::create_copy_at(p_end, value, construct_count); +#else + etl::create_copy_at(p_end, value); +#endif + ++p_end; + } + + //********************************************************************* + /// Destroy an element at the back. + //********************************************************************* + inline void destroy_back() + { + --p_end; + +#if defined(ETL_DEBUG) + etl::destroy_at(p_end, construct_count); +#else + etl::destroy_at(p_end); +#endif + } + + // Disable copy construction. + ivector(const ivector&); + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator ==(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs) + { + return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator !=(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Less than operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically less than the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator <(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //*************************************************************************** + /// Greater than operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically greater than the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator >(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs) + { + return (rhs < lhs); + } + + //*************************************************************************** + /// Less than or equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically less than or equal to the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator <=(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs) + { + return !(lhs > rhs); + } + + //*************************************************************************** + /// Greater than or equal operator. + ///\param lhs Reference to the first vector. + ///\param rhs Reference to the second vector. + ///\return <b>true</b> if the first vector is lexicographically greater than or equal to the second, otherwise <b>false</b> + ///\ingroup vector + //*************************************************************************** + template <typename T> + bool operator >=(const etl::ivector<T>& lhs, const etl::ivector<T>& rhs) + { + return !(lhs < rhs); + } + + //*************************************************************************** + /// A vector implementation that uses a fixed size buffer. + ///\tparam T The element type. + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup vector + //*************************************************************************** + template <typename T, const size_t MAX_SIZE_> + class vector : public etl::ivector<T> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + vector() + : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE) + { + etl::ivector<T>::initialise(); + } + + //************************************************************************* + /// Constructor, with size. + ///\param initial_size The initial size of the vector. + //************************************************************************* + explicit vector(size_t initial_size) + : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE) + { + etl::ivector<T>::initialise(); + etl::ivector<T>::resize(initial_size); + } + + //************************************************************************* + /// Constructor, from initial size and value. + ///\param initial_size The initial size of the vector. + ///\param value The value to fill the vector with. + //************************************************************************* + vector(size_t initial_size, typename etl::ivector<T>::parameter_t value) + : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE) + { + etl::ivector<T>::initialise(); + etl::ivector<T>::resize(initial_size, value); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + vector(TIterator first, TIterator last) + : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE) + { + etl::ivector<T>::assign(first, last); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + vector(const vector& other) + : etl::ivector<T>(reinterpret_cast<T*>(&buffer), MAX_SIZE) + { + etl::ivector<T>::assign(other.begin(), other.end()); + } + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~vector() + { + etl::ivector<T>::clear(); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + vector& operator = (const vector& rhs) + { + if (&rhs != this) + { + etl::ivector<T>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair() + { + #if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED + ETL_ASSERT(std::is_trivially_copyable<T>::value, ETL_ERROR(etl::vector_incompatible_type)); + #endif + + etl::ivector<T>::repair(buffer); + } + + private: + + typename etl::aligned_storage<sizeof(T) * MAX_SIZE, etl::alignment_of<T>::value>::type buffer; + }; + + //*************************************************************************** + /// A vector implementation that uses a fixed size buffer. + ///\tparam T The element type. + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup vector + //*************************************************************************** + template <typename T, const size_t MAX_SIZE_> + class vector<T*, MAX_SIZE_> : public etl::ivector<T*> + { + public: + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + vector() + : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE) + { + etl::ivector<T*>::initialise(); + } + + //************************************************************************* + /// Constructor, with size. + ///\param initial_size The initial size of the vector. + //************************************************************************* + explicit vector(size_t initial_size) + : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE) + { + etl::ivector<T*>::initialise(); + etl::ivector<T*>::resize(initial_size); + } + + //************************************************************************* + /// Constructor, from initial size and value. + ///\param initial_size The initial size of the vector. + ///\param value The value to fill the vector with. + //************************************************************************* + vector(size_t initial_size, typename etl::ivector<T*>::parameter_t value) + : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE) + { + etl::ivector<T*>::initialise(); + etl::ivector<T*>::resize(initial_size, value); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + vector(TIterator first, TIterator last) + : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE) + { + etl::ivector<T*>::assign(first, last); + } + + //************************************************************************* + /// Copy constructor. + //************************************************************************* + vector(const vector& other) + : etl::ivector<T*>(reinterpret_cast<T**>(&buffer), MAX_SIZE) + { + etl::ivector<T*>::assign(other.begin(), other.end()); + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + vector& operator = (const vector& rhs) + { + if (&rhs != this) + { + etl::ivector<T*>::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair() + { + etl::ivector<T*>::repair(buffer); + } + + private: + + typename etl::aligned_storage<sizeof(T*) * MAX_SIZE, etl::alignment_of<T*>::value>::type buffer; + }; +} + +#include "private/ivectorpointer.h" + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/visitor.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,465 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +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_VISITOR__ +#define __ETL_VISITOR__ + +#include "platform.h" + +//***************************************************************************** +///\defgroup visitor visitor +/// A set of template classes for easy implementation of the visitor pattern.<br> +/// The visitor design pattern is a way of separating an algorithm from an object +/// structure on which it operates. A practical result of this separation is the +/// ability to add new operations to existing object structures without modifying +/// those structures. It is one way to easily follow the open/closed principle. +/// In essence, the visitor allows one to add new virtual functions to a family +/// of classes without modifying the classes themselves; instead, one creates a +/// visitor class that implements all of the appropriate specialisations of the +/// virtual function. The visitor takes the instance as input, and implements +/// the goal through double dispatch.<br> +/// \ingroup patterns +//***************************************************************************** + +namespace etl +{ + //***************************************************************** + /// The visitable base class for four visitor types. + /// Derive visitable classes from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void> + class visitable + { + public: + + virtual void accept(T1&) = 0; + virtual void accept(T2&) = 0; + virtual void accept(T3&) = 0; + virtual void accept(T4&) = 0; + }; + + //***************************************************************** + /// The visitable base class for three visitor types. + /// Derive visitable classes from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3> + class visitable<T1, T2, T3> + { + public: + + virtual void accept(T1&) = 0; + virtual void accept(T2&) = 0; + virtual void accept(T3&) = 0; + }; + + //***************************************************************** + /// The visitable base class for two visitor types. + /// Derive visitable classes from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2> + class visitable<T1, T2> + { + public: + + virtual void accept(T1&) = 0; + virtual void accept(T2&) = 0; + }; + + //***************************************************************** + /// The visitable base class for one visitor type. + /// Derive visitable classes from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1> + class visitable<T1> + { + public: + + virtual void accept(T1&) = 0; + }; + + //***************************************************************** + /// The visitor base class for sixteen types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2 = void, typename T3 = void, typename T4 = void, + typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, + typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, + typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void> + class visitor + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + virtual void visit(T8&) = 0; + virtual void visit(T9&) = 0; + virtual void visit(T10&) = 0; + virtual void visit(T11&) = 0; + virtual void visit(T12&) = 0; + virtual void visit(T13&) = 0; + virtual void visit(T14&) = 0; + virtual void visit(T15&) = 0; + virtual void visit(T16&) = 0; + }; + + //***************************************************************** + /// The visitor base class for fifteen types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13, typename T14, typename T15> + class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + virtual void visit(T8&) = 0; + virtual void visit(T9&) = 0; + virtual void visit(T10&) = 0; + virtual void visit(T11&) = 0; + virtual void visit(T12&) = 0; + virtual void visit(T13&) = 0; + virtual void visit(T14&) = 0; + virtual void visit(T15&) = 0; + }; + + //***************************************************************** + /// The visitor base class for fourteen types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13, typename T14> + class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + virtual void visit(T8&) = 0; + virtual void visit(T9&) = 0; + virtual void visit(T10&) = 0; + virtual void visit(T11&) = 0; + virtual void visit(T12&) = 0; + virtual void visit(T13&) = 0; + virtual void visit(T14&) = 0; + }; + + //***************************************************************** + /// The visitor base class for thirteen types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12, + typename T13> + class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + virtual void visit(T8&) = 0; + virtual void visit(T9&) = 0; + virtual void visit(T10&) = 0; + virtual void visit(T11&) = 0; + virtual void visit(T12&) = 0; + virtual void visit(T13&) = 0; + }; + + //***************************************************************** + /// The visitor base class for twelve types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11, typename T12> + class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + virtual void visit(T8&) = 0; + virtual void visit(T9&) = 0; + virtual void visit(T10&) = 0; + virtual void visit(T11&) = 0; + virtual void visit(T12&) = 0; + }; + + //***************************************************************** + /// The visitor base class for eleven types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10, typename T11> + class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + virtual void visit(T8&) = 0; + virtual void visit(T9&) = 0; + virtual void visit(T10&) = 0; + virtual void visit(T11&) = 0; + }; + + //***************************************************************** + /// The visitor base class for ten types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9, typename T10> + class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + virtual void visit(T8&) = 0; + virtual void visit(T9&) = 0; + virtual void visit(T10&) = 0; + }; + + //***************************************************************** + /// The visitor base class for nine types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8, + typename T9> + class visitor<T1, T2, T3, T4, T5, T6, T7, T8, T9> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + virtual void visit(T8&) = 0; + virtual void visit(T9&) = 0; + }; + + //***************************************************************** + /// The visitor base class for eight types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7, typename T8> + class visitor<T1, T2, T3, T4, T5, T6, T7, T8> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + virtual void visit(T8&) = 0; + }; + + //***************************************************************** + /// The visitor base class for seven types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6, typename T7> + class visitor<T1, T2, T3, T4, T5, T6, T7> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + virtual void visit(T7&) = 0; + }; + + //***************************************************************** + /// The visitor base class for six types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5, typename T6> + class visitor<T1, T2, T3, T4, T5, T6> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + virtual void visit(T6&) = 0; + }; + + //***************************************************************** + /// The visitor base class for five types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4, + typename T5> + class visitor<T1, T2, T3, T4, T5> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + virtual void visit(T5&) = 0; + }; + + //***************************************************************** + /// The visitor base class for four types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3, typename T4> + class visitor<T1, T2, T3, T4> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + virtual void visit(T4&) = 0; + }; + + //***************************************************************** + /// The visitor base class for three types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2, typename T3> + class visitor<T1, T2, T3> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + virtual void visit(T3&) = 0; + }; + + //***************************************************************** + /// The visitor base class for two types. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1, typename T2> + class visitor<T1, T2> + { + public: + + virtual void visit(T1&) = 0; + virtual void visit(T2&) = 0; + }; + + //***************************************************************** + /// The visitor base class for one type. + /// Derive visitors from this. + ///\ingroup visitor + //***************************************************************** + template <typename T1> + class visitor<T1> + { + public: + + virtual void visit(T1&) = 0; + }; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wstring.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,225 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_WSTRING__ +#define __ETL_WSTRING__ + +#include "platform.h" +#include "basic_string.h" +#include "hash.h" + +#if defined(ETL_COMPILER_MICROSOFT) + #undef min +#endif + +namespace etl +{ + typedef ibasic_string<wchar_t> iwstring; + + //*************************************************************************** + /// A wstring implementation that uses a fixed size buffer. + ///\tparam MAX_SIZE_ The maximum number of elements that can be stored. + ///\ingroup wstring + //*************************************************************************** + template <const size_t MAX_SIZE_> + class wstring : public iwstring + { + public: + + typedef iwstring::value_type value_type; + + static const size_t MAX_SIZE = MAX_SIZE_; + + //************************************************************************* + /// Constructor. + //************************************************************************* + wstring() + : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iwstring::initialise(); + } + + //************************************************************************* + /// Copy constructor. + ///\param other The other string. + //************************************************************************* + wstring(const etl::wstring<MAX_SIZE_>& other) + : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + wstring::initialise(); + wstring::assign(other.begin(), other.end()); + } + + + //************************************************************************* + /// From other string, position, length. + ///\param other The other string. + ///\param position The position of the first character. + ///\param length The number of characters. Default = npos. + //************************************************************************* + wstring(const etl::wstring<MAX_SIZE_>& other, size_t position, size_t length_ = npos) + : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + ETL_ASSERT(position < other.size(), ETL_ERROR(string_out_of_bounds)); + + // Set the length to the exact amount. + length_ = (length_ > MAX_SIZE_) ? MAX_SIZE_ : length_; + + iwstring::initialise(); + iwstring::assign(other.begin() + position, other.begin() + position + length_); + } + + //************************************************************************* + /// Constructor, from null terminated text. + ///\param text The initial text of the wstring. + //************************************************************************* + wstring(const value_type* text) + : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iwstring::initialise(); + iwstring::assign(text, text + etl::char_traits<value_type>::length(text)); + } + + //************************************************************************* + /// Constructor, from null terminated text and count. + ///\param text The initial text of the wstring. + ///\param count The number of characters to copy. + //************************************************************************* + wstring(const value_type* text, size_t count) + : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iwstring::initialise(); + iwstring::assign(text, text + count); + } + + //************************************************************************* + /// Constructor, from initial size and value. + ///\param initialSize The initial size of the wstring. + ///\param value The value to fill the wstring with. + //************************************************************************* + wstring(size_t count, value_type c) + : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iwstring::initialise(); + iwstring::resize(count, c); + } + + //************************************************************************* + /// Constructor, from an iterator range. + ///\tparam TIterator The iterator type. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //************************************************************************* + template <typename TIterator> + wstring(TIterator first, TIterator last) + : iwstring(reinterpret_cast<value_type*>(&buffer), MAX_SIZE) + { + iwstring::assign(first, last); + } + + //************************************************************************* + /// Returns a sub-string. + ///\param position The position of the first character. Default = 0. + ///\param length The number of characters. Default = npos. + //************************************************************************* + etl::wstring<MAX_SIZE_> substr(size_t position = 0, size_t length_ = npos) const + { + etl::wstring<MAX_SIZE_> new_string; + + if (position != size()) + { + ETL_ASSERT(position < size(), ETL_ERROR(string_out_of_bounds)); + + length_ = std::min(length_, size() - position); + + new_string.assign(buffer + position, buffer + position + length_); + } + + return new_string; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + wstring& operator = (const wstring& rhs) + { + if (&rhs != this) + { + iwstring::assign(rhs.cbegin(), rhs.cend()); + } + + return *this; + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair() + { + etl::iwstring::repair(buffer); + } + + private: + + value_type buffer[MAX_SIZE + 1]; + }; + + //************************************************************************* + /// Hash function. + //************************************************************************* +#if ETL_8BIT_SUPPORT + template <> + struct hash<etl::iwstring> + { + size_t operator()(const etl::iwstring& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; + + template <const size_t SIZE> + struct hash<etl::wstring<SIZE> > + { + size_t operator()(const etl::wstring<SIZE>& text) const + { + return etl::__private_hash__::generic_hash<size_t>(reinterpret_cast<const uint8_t*>(&text[0]), + reinterpret_cast<const uint8_t*>(&text[text.size()])); + } + }; +#endif +} + +#if defined(ETL_COMPILER_MICROSOFT) + #define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#endif +