Added specialisations of etl::rotate for different iterator types

This commit is contained in:
John Wellbelove 2024-05-13 09:07:30 +01:00
parent 17a4e8d934
commit 384c08f25b

View File

@ -43,6 +43,7 @@ SOFTWARE.
#include "iterator.h"
#include "functional.h"
#include "utility.h"
#include "gcd.h"
#include <stdint.h>
#include <string.h>
@ -1157,20 +1158,94 @@ namespace etl
namespace private_algorithm
{
//*********************************
// For random access iterators
template <typename TIterator>
ETL_CONSTEXPR14
TIterator rotate_general(TIterator first, TIterator middle, TIterator last)
typename etl::enable_if<etl::is_random_access_iterator<TIterator>::value, TIterator>::type
rotate_general(TIterator first, TIterator middle, TIterator last)
{
if (first == middle || middle == last)
{
return first;
}
int n = last - first;
int m = middle - first;
int gcd_nm = etl::gcd(n, m);
TIterator result = first + (last - middle);
for (int i = 0; i < gcd_nm; i++)
{
auto temp = *(first + i);
int j = i;
while (true)
{
int k = j + m;
if (k >= n)
{
k = k - n;
}
if (k == i)
{
break;
}
*(first + j) = *(first + k);
j = k;
}
*(first + j) = temp;
}
return result;
}
//*********************************
// For bidirectional iterators
template <typename TIterator>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_bidirectional_iterator<TIterator>::value, TIterator>::type
rotate_general(TIterator first, TIterator middle, TIterator last)
{
if (first == middle || middle == last)
{
return first;
}
TIterator result = first;
etl::advance(result, etl::distance(middle, last));
reverse(first, middle);
reverse(middle, last);
reverse(first, last);
return result;
}
//*********************************
// For forward iterators
template <typename TIterator>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_forward_iterator<TIterator>::value, TIterator>::type
rotate_general(TIterator first, TIterator middle, TIterator last)
{
if (first == middle || middle == last)
{
return first;
}
TIterator next = middle;
TIterator result = first;
std::advance(result, std::distance(middle, last));
while (first != next)
{
using ETL_OR_STD::swap; // Allow ADL
swap(*first, *next);
++first;
++next;
using ETL_OR_STD::swap;
swap(*first++, *next++);
if (next == last)
{
@ -1182,10 +1257,11 @@ namespace etl
}
}
return first;
return result;
}
//*********************************
// Simplified algorithm for rotate left by one
template <typename TIterator>
ETL_CONSTEXPR14
TIterator rotate_left_by_one(TIterator first, TIterator last)
@ -1206,6 +1282,7 @@ namespace etl
}
//*********************************
// Simplified for algorithm rotate right by one
template <typename TIterator>
ETL_CONSTEXPR14
TIterator rotate_right_by_one(TIterator first, TIterator last)
@ -1239,7 +1316,18 @@ namespace etl
if (etl::next(middle) == last)
{
return private_algorithm::rotate_right_by_one(first, last);
#if ETL_USING_CPP20
if ETL_IF_CONSTEXPR(etl::is_forward_iterator<TIterator>::value)
{
return private_algorithm::rotate_general(first, middle, last);
}
else
{
return private_algorithm::rotate_right_by_one(first, last);
}
#else
return private_algorithm::rotate_general(first, middle, last);
#endif
}
return private_algorithm::rotate_general(first, middle, last);