IVGCVSW-863 Move clamp, for_each, foldl to misc/utility.h

Also, improve for_each, foldl, and related changes.

Change-Id: I0cf0c7dbf88f26bb70cc734ba9fb5725d405585f
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/114014
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com>
Tested-by: Jenkins <bsgcomp@arm.com>
diff --git a/arm_compute/core/Helpers.h b/arm_compute/core/Helpers.h
index c02f14a..3575fcf 100644
--- a/arm_compute/core/Helpers.h
+++ b/arm_compute/core/Helpers.h
@@ -253,72 +253,6 @@
  */
 inline uint8_t pixel_area_c1u8_clamp(const uint8_t *first_pixel_ptr, size_t stride, size_t width, size_t height, float wr, float hr, int x, int y);
 
-/** Performs clamping among a lower and upper value.
- *
- * @param[in] n     Value to clamp.
- * @param[in] lower Lower threshold.
- * @param[in] upper Upper threshold.
- *
- *  @return Clamped value.
- */
-template <typename T>
-inline T clamp(const T &n, const T &lower, const T &upper)
-{
-    return std::max(lower, std::min(n, upper));
-}
-
-/** Base case of for_each. Does nothing. */
-template <typename F>
-inline void for_each(F &&)
-{
-}
-
-/** Call the function for each of the arguments
- *
- * @param[in] func Function to be called
- * @param[in] arg  Argument passed to the function
- * @param[in] args Remaining arguments
- */
-template <typename F, typename T, typename... Ts>
-inline void for_each(F &&func, T &&arg, Ts &&... args)
-{
-    func(arg);
-    for_each(func, args...);
-}
-
-/** Base case of foldl.
- *
- * @return value.
- */
-template <typename F, typename T>
-inline T foldl(F &&, const T &value)
-{
-    return value;
-}
-
-/** Base case of foldl.
- *
- * @return Function evaluation for value1 and value2
- */
-template <typename F, typename T, typename U>
-inline auto foldl(F &&func, T &&value1, U &&value2) -> decltype(func(value1, value2))
-{
-    return func(value1, value2);
-}
-
-/** Fold left.
- *
- * @param[in] func    Function to be called
- * @param[in] initial Initial value
- * @param[in] value   Argument passed to the function
- * @param[in] values  Remaining arguments
- */
-template <typename F, typename I, typename T, typename... Vs>
-inline I foldl(F &&func, I &&initial, T &&value, Vs &&... values)
-{
-    return foldl(std::forward<F>(func), func(std::forward<I>(initial), std::forward<T>(value)), std::forward<Vs>(values)...);
-}
-
 /** Iterator updated by @ref execute_window_loop for each window element */
 class Iterator
 {
@@ -408,7 +342,7 @@
 {
     bool window_changed = false;
 
-    for_each([&](const IAccessWindow & w)
+    utility::for_each([&](const IAccessWindow & w)
     {
         window_changed |= w.update_window_if_needed(win);
     },
@@ -416,7 +350,7 @@
 
     bool padding_changed = false;
 
-    for_each([&](const IAccessWindow & w)
+    utility::for_each([&](const IAccessWindow & w)
     {
         padding_changed |= w.update_padding_if_needed(win);
     },
@@ -464,7 +398,7 @@
  * @return Intersection of all regions.
  */
 template <typename... Ts>
-ValidRegion intersect_valid_regions(Ts &&... regions)
+ValidRegion intersect_valid_regions(const Ts &... regions)
 {
     auto intersect = [](const ValidRegion & r1, const ValidRegion & r2) -> ValidRegion
     {
@@ -483,7 +417,7 @@
         return region;
     };
 
-    return foldl(intersect, std::forward<Ts>(regions)...);
+    return utility::foldl(intersect, regions...);
 }
 
 /** Create a strides object based on the provided strides and the tensor dimensions.
diff --git a/arm_compute/core/Helpers.inl b/arm_compute/core/Helpers.inl
index 3672692..4121fb1 100644
--- a/arm_compute/core/Helpers.inl
+++ b/arm_compute/core/Helpers.inl
@@ -80,17 +80,12 @@
     template <typename T, typename... Ts>
     static void unroll(T &&it, Ts &&... iterators)
     {
-        it.increment(dimension);
-        IncrementIterators<dimension>::unroll<Ts...>(std::forward<Ts>(iterators)...);
+        auto increment = [](T && it)
+        {
+            it.increment(dimension);
+        };
+        utility::for_each(increment, std::forward<T>(it), std::forward<Ts>(iterators)...);
     }
-
-    template <typename T>
-    static void unroll(T &&it)
-    {
-        it.increment(dimension);
-        // End of recursion
-    }
-
     static void unroll()
     {
         // End of recursion
diff --git a/arm_compute/core/utils/misc/utility.h b/arm_compute/core/utils/misc/utility.h
index 898d0cd..45b3b52 100644
--- a/arm_compute/core/utils/misc/utility.h
+++ b/arm_compute/core/utils/misc/utility.h
@@ -67,6 +67,62 @@
 {
     return detail::make_array(first, index_sequence_t<N> {});
 }
-} // namespace misc
+
+/** Performs clamping among a lower and upper value.
+ *
+ * @param[in] n     Value to clamp.
+ * @param[in] lower Lower threshold.
+ * @param[in] upper Upper threshold.
+ *
+ *  @return Clamped value.
+ */
+template <typename T>
+inline T clamp(const T &n, const T &lower, const T &upper)
+{
+    return std::max(lower, std::min(n, upper));
+}
+
+/** Base case of for_each. Does nothing. */
+template <typename F>
+inline void for_each(F &&)
+{
+}
+
+/** Call the function for each of the arguments
+ *
+ * @param[in] func Function to be called
+ * @param[in] arg  Argument passed to the function
+ * @param[in] args Remaining arguments
+ */
+template <typename F, typename T, typename... Ts>
+inline void for_each(F &&func, T &&arg, Ts &&... args)
+{
+    func(std::forward<T>(arg));
+    for_each(std::forward<F>(func), std::forward<Ts>(args)...);
+}
+
+/** Base case of foldl.
+ *
+ * @return value.
+ */
+template <typename F, typename T>
+inline T &&foldl(F &&, T &&value)
+{
+    return std::forward<T>(value);
+}
+
+/** Fold left.
+ *
+ * @param[in] func    Function to be called
+ * @param[in] initial Initial value
+ * @param[in] value   Argument passed to the function
+ * @param[in] values  Remaining arguments
+ */
+template <typename F, typename T, typename U, typename... Us>
+inline auto foldl(F &&func, T &&initial, U &&value, Us &&... values) -> decltype(func(std::forward<T>(initial), std::forward<U>(value)))
+{
+    return foldl(std::forward<F>(func), func(std::forward<T>(initial), std::forward<U>(value)), std::forward<Us>(values)...);
+}
+} // namespace utility
 } // namespace arm_compute
 #endif /* __ARM_COMPUTE_MISC_UTILITY_H__ */
diff --git a/arm_compute/graph/nodes/BranchLayer.h b/arm_compute/graph/nodes/BranchLayer.h
index dd05315..5e4a8d9 100644
--- a/arm_compute/graph/nodes/BranchLayer.h
+++ b/arm_compute/graph/nodes/BranchLayer.h
@@ -31,7 +31,7 @@
 #include "arm_compute/graph/SubTensor.h"
 #include "arm_compute/graph/Types.h"
 
-#include "arm_compute/core/Helpers.h"
+#include "arm_compute/core/utils/misc/utility.h"
 
 #include <vector>
 
@@ -58,7 +58,7 @@
         _sub_graphs.push_back(arm_compute::support::cpp14::make_unique<SubGraph>(std::move(sub_graph1)));
         _sub_graphs.push_back(arm_compute::support::cpp14::make_unique<SubGraph>(std::move(sub_graph2)));
 
-        for_each([&](SubGraph & sub_graph)
+        utility::for_each([&](SubGraph && sub_graph)
         {
             _sub_graphs.push_back(arm_compute::support::cpp14::make_unique<SubGraph>(std::move(sub_graph)));
         },
diff --git a/src/core/NEON/kernels/NEWarpKernel.cpp b/src/core/NEON/kernels/NEWarpKernel.cpp
index ab8ab14..0fa8278 100644
--- a/src/core/NEON/kernels/NEWarpKernel.cpp
+++ b/src/core/NEON/kernels/NEWarpKernel.cpp
@@ -287,10 +287,10 @@
                     break;
                 case InterpolationPolicy::BILINEAR:
                 {
-                    const auto xi   = clamp<int>(std::floor(x0), min_x - 1, max_x);
-                    const auto yi   = clamp<int>(std::floor(y0), min_y - 1, max_y);
-                    const auto xi_1 = clamp<int>(std::floor(x0 + 1), min_x - 1, max_x);
-                    const auto yi_1 = clamp<int>(std::floor(y0 + 1), min_y - 1, max_y);
+                    const auto xi   = utility::clamp<int>(std::floor(x0), min_x - 1, max_x);
+                    const auto yi   = utility::clamp<int>(std::floor(y0), min_y - 1, max_y);
+                    const auto xi_1 = utility::clamp<int>(std::floor(x0 + 1), min_x - 1, max_x);
+                    const auto yi_1 = utility::clamp<int>(std::floor(y0 + 1), min_y - 1, max_y);
 
                     const float dx  = x0 - std::floor(x0);
                     const float dy  = y0 - std::floor(y0);
@@ -396,8 +396,8 @@
         else
         {
             // Clamp coordinates
-            const auto xi = clamp<int>(std::floor(x0), min_x, max_x - 1);
-            const auto yi = clamp<int>(std::floor(y0), min_y, max_y - 1);
+            const auto xi = utility::clamp<int>(std::floor(x0), min_x, max_x - 1);
+            const auto yi = utility::clamp<int>(std::floor(y0), min_y, max_y - 1);
             switch(interpolation)
             {
                 case InterpolationPolicy::NEAREST_NEIGHBOR:
@@ -405,8 +405,8 @@
                     break;
                 case InterpolationPolicy::BILINEAR:
                 {
-                    const auto xi_1 = clamp<int>(std::floor(x0 + 1), min_x, max_x - 1);
-                    const auto yi_1 = clamp<int>(std::floor(y0 + 1), min_y, max_y - 1);
+                    const auto xi_1 = utility::clamp<int>(std::floor(x0 + 1), min_x, max_x - 1);
+                    const auto yi_1 = utility::clamp<int>(std::floor(y0 + 1), min_y, max_y - 1);
 
                     const float dx  = x0 - std::floor(x0);
                     const float dy  = y0 - std::floor(y0);
@@ -636,10 +636,10 @@
                     break;
                 case InterpolationPolicy::BILINEAR:
                 {
-                    const auto xi   = clamp<int>(std::floor(xn), min_x - 1, max_x);
-                    const auto yi   = clamp<int>(std::floor(yn), min_y - 1, max_y);
-                    const auto xi_1 = clamp<int>(std::floor(xn + 1), min_x - 1, max_x);
-                    const auto yi_1 = clamp<int>(std::floor(yn + 1), min_y - 1, max_y);
+                    const auto xi   = utility::clamp<int>(std::floor(xn), min_x - 1, max_x);
+                    const auto yi   = utility::clamp<int>(std::floor(yn), min_y - 1, max_y);
+                    const auto xi_1 = utility::clamp<int>(std::floor(xn + 1), min_x - 1, max_x);
+                    const auto yi_1 = utility::clamp<int>(std::floor(yn + 1), min_y - 1, max_y);
 
                     const float dx  = xn - std::floor(xn);
                     const float dy  = yn - std::floor(yn);
@@ -762,8 +762,8 @@
         else
         {
             // Clamp coordinates
-            const auto xi = clamp<int>(std::floor(xn), min_x, max_x - 1);
-            const auto yi = clamp<int>(std::floor(yn), min_y, max_y - 1);
+            const auto xi = utility::clamp<int>(std::floor(xn), min_x, max_x - 1);
+            const auto yi = utility::clamp<int>(std::floor(yn), min_y, max_y - 1);
             switch(interpolation)
             {
                 case InterpolationPolicy::NEAREST_NEIGHBOR:
@@ -771,8 +771,8 @@
                     break;
                 case InterpolationPolicy::BILINEAR:
                 {
-                    const auto xi_1 = clamp<int>(std::floor(xn + 1), min_x, max_x - 1);
-                    const auto yi_1 = clamp<int>(std::floor(yn + 1), min_y, max_y - 1);
+                    const auto xi_1 = utility::clamp<int>(std::floor(xn + 1), min_x, max_x - 1);
+                    const auto yi_1 = utility::clamp<int>(std::floor(yn + 1), min_y, max_y - 1);
 
                     const float dx  = xn - std::floor(xn);
                     const float dy  = yn - std::floor(yn);
diff --git a/tests/validation/reference/ConvolutionLayer.cpp b/tests/validation/reference/ConvolutionLayer.cpp
index 1066411..567fac0 100644
--- a/tests/validation/reference/ConvolutionLayer.cpp
+++ b/tests/validation/reference/ConvolutionLayer.cpp
@@ -210,7 +210,7 @@
 
     acc = asymm_rounding_divide_by_pow2(asymm_int_mult(acc, output_multiplier), output_shift);
     acc += output_offset;
-    acc = clamp<int32_t>(acc, 0, 255);
+    acc = utility::clamp<int32_t>(acc, 0, 255);
 
     // Store the result
     *out_ptr = acc;
diff --git a/tests/validation/reference/FullyConnectedLayer.cpp b/tests/validation/reference/FullyConnectedLayer.cpp
index c24881e..5384715 100644
--- a/tests/validation/reference/FullyConnectedLayer.cpp
+++ b/tests/validation/reference/FullyConnectedLayer.cpp
@@ -138,7 +138,7 @@
 
         acc = asymm_rounding_divide_by_pow2(asymm_int_mult(acc, output_multiplier), output_shift);
         acc += output_offset;
-        acc = clamp<int32_t>(acc, 0, 255);
+        acc = utility::clamp<int32_t>(acc, 0, 255);
 
         // Store the result
         dst_ptr[y] = static_cast<uint8_t>(acc);
diff --git a/tests/validation/reference/Scale.cpp b/tests/validation/reference/Scale.cpp
index 727325f..0cc96ab 100644
--- a/tests/validation/reference/Scale.cpp
+++ b/tests/validation/reference/Scale.cpp
@@ -22,10 +22,9 @@
  * SOFTWARE.
  */
 
-#include "arm_compute/core/Helpers.h"
-
 #include "Scale.h"
 #include "Utils.h"
+#include "arm_compute/core/utils/misc/utility.h"
 #include "support/ToolchainSupport.h"
 
 namespace arm_compute
@@ -119,8 +118,8 @@
                     }
                     else if(border_mode == BorderMode::REPLICATE)
                     {
-                        id.set(0, clamp(static_cast<int>(x_src), 0, width - 1));
-                        id.set(1, clamp(static_cast<int>(y_src), 0, height - 1));
+                        id.set(0, utility::clamp<int>(x_src, 0, width - 1));
+                        id.set(1, utility::clamp<int>(y_src, 0, height - 1));
                         out[element_idx] = in[coord2index(in.shape(), id)];
                     }
                 }