Skip to content

Commit

Permalink
Added specialisations of etl::rotate for different iterator types
Browse files Browse the repository at this point in the history
  • Loading branch information
John Wellbelove committed May 13, 2024
1 parent 959b83e commit f9867c2
Showing 1 changed file with 97 additions and 9 deletions.
106 changes: 97 additions & 9 deletions include/etl/algorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ SOFTWARE.
#include "iterator.h"
#include "functional.h"
#include "utility.h"
#include "gcd.h"

#include <stdint.h>
#include <string.h>
Expand Down Expand Up @@ -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)
{
TIterator next = middle;
if (first == middle || middle == last)
{
return first;
}

while (first != next)
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++)
{
using ETL_OR_STD::swap; // Allow ADL
auto temp = *(first + i);
int j = i;

while (true)
{
int k = j + m;

if (k >= n)
{
k = k - n;
}

if (k == i)
{
break;
}

swap(*first, *next);
*(first + j) = *(first + k);
j = k;
}

++first;
++next;
*(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;
swap(*first++, *next++);

if (next == last)
{
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit f9867c2

Please sign in to comment.