From f9867c2281218340b0962ddce257f3c8a1eb5456 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 13 May 2024 09:07:30 +0100 Subject: [PATCH] Added specialisations of etl::rotate for different iterator types --- include/etl/algorithm.h | 106 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 9 deletions(-) diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index 43ec1668..ff785df4 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -43,6 +43,7 @@ SOFTWARE. #include "iterator.h" #include "functional.h" #include "utility.h" +#include "gcd.h" #include #include @@ -1157,20 +1158,94 @@ namespace etl namespace private_algorithm { //********************************* + // For random access iterators template ETL_CONSTEXPR14 - TIterator rotate_general(TIterator first, TIterator middle, TIterator last) + typename etl::enable_if::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 + ETL_CONSTEXPR14 + typename etl::enable_if::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 + ETL_CONSTEXPR14 + typename etl::enable_if::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 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 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::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);