[libsigc++2/variadic_bind4] Update tuple-utils from murrayc-tuple-utils.



commit 5cc67149749061edd4f6d12cdf75afc91358a907
Author: Murray Cumming <murrayc murrayc com>
Date:   Thu Mar 3 22:13:27 2016 +0100

    Update tuple-utils from murrayc-tuple-utils.
    
    tuple_transform_each() now iterates in order, instead of in reverse,
    though that didn't seem to matter to how we used it in libsigc++.

 sigc++/tuple-utils/tuple_transform_each.h |   41 +++++++++++++++++++++--------
 tests/test_tuple_transform_each.cc        |   31 ++++++++++++++++++++++
 2 files changed, 61 insertions(+), 11 deletions(-)
---
diff --git a/sigc++/tuple-utils/tuple_transform_each.h b/sigc++/tuple-utils/tuple_transform_each.h
index abd3977..77b48df 100644
--- a/sigc++/tuple-utils/tuple_transform_each.h
+++ b/sigc++/tuple-utils/tuple_transform_each.h
@@ -89,13 +89,20 @@ struct tuple_type_transform_each {
 
 namespace detail {
 
-template <template <typename> class T_transformer, std::size_t index>
+template <template <typename> class T_transformer, std::size_t size_from_index>
 struct tuple_transform_each_impl {
   // TODO: Avoid the need to pass t_original all the way into the recursion?
   template <typename T_current, typename T_original>
   static decltype(auto)
   tuple_transform_each(T_current&& t, T_original& t_original) {
-    using from_element_type = typename std::tuple_element<index, std::decay_t<T_current>>::type;
+    //We use std::decay_t<> because tuple_size is not defined for references.
+    constexpr auto size = std::tuple_size<std::decay_t<T_current>>::value;
+    static_assert(size > 1, "size must be more than 0.");
+
+    constexpr auto index = size - size_from_index;
+    static_assert(index >= 0, "unexpected index.");
+
+    using from_element_type = typename std::tuple_element<index, std::decay_t<T_original>>::type;
     using to_element_type = typename std::result_of<decltype (
       &T_transformer<from_element_type>::transform)(from_element_type&)>::type;
     const auto t_element =
@@ -103,8 +110,6 @@ struct tuple_transform_each_impl {
 
     const auto t_start = tuple_start<index>(std::forward<T_current>(t));
 
-    constexpr auto size = std::tuple_size<std::decay_t<T_current>>::value;
-
     // t_end's elements will be copies of the elements in t, so this method's
     // caller won't see the changes made in the subsequent call of
     // tuple_transform_each() on those copies. That's why we pass t_original
@@ -115,16 +120,21 @@ struct tuple_transform_each_impl {
 
     auto t_with_transformed_element = std::tuple_cat(t_start, t_element, t_end);
     return tuple_transform_each_impl<T_transformer,
-      index - 1>::tuple_transform_each(t_with_transformed_element, t_original);
+      size_from_index - 1>::tuple_transform_each(t_with_transformed_element, t_original);
   }
 };
 
 template <template <typename> class T_transformer>
-struct tuple_transform_each_impl<T_transformer, 0> {
+struct tuple_transform_each_impl<T_transformer, 1> {
   template <typename T_current, typename T_original>
   static decltype(auto)
   tuple_transform_each(T_current&& t, T_original& t_original) {
-    constexpr std::size_t index = 0;
+    //We use std::decay_t<> because tuple_size is not defined for references.
+    constexpr auto size = std::tuple_size<std::decay_t<T_current>>::value;
+    static_assert(size > 0, "size must be more than 0.");
+
+    constexpr auto index = size - 1;
+    static_assert(index >= 0, "unexpected index.");
 
     using from_element_type = typename std::tuple_element<index, T_original>::type;
     using to_element_type = typename std::result_of<decltype (
@@ -132,8 +142,18 @@ struct tuple_transform_each_impl<T_transformer, 0> {
     const auto tuple_element =
       std::tuple<to_element_type>(T_transformer<from_element_type>::transform(std::get<index>(t_original)));
 
-    const auto tuple_rest = tuple_cdr(std::forward<T_current>(t));
-    return std::tuple_cat(tuple_element, tuple_rest);
+    const auto tuple_rest = tuple_start<size - 1>(std::forward<T_current>(t));
+    return std::tuple_cat(tuple_rest, tuple_element);
+  }
+};
+
+template <template <typename> class T_transformer>
+struct tuple_transform_each_impl<T_transformer, 0> {
+  template <typename T_current, typename T_original>
+  static decltype(auto)
+  tuple_transform_each(T_current&& t, T_original& /* t_original */) {
+      //Do nothing because the tuple has no elements.
+      return std::forward<T_current>(t);
   }
 };
 
@@ -148,10 +168,9 @@ decltype(auto)
 tuple_transform_each(T&& t) {
   //We use std::decay_t<> because tuple_size is not defined for references.
   constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
-  static_assert(size > 0, "The tuple size must be more than zero.");
 
   return detail::tuple_transform_each_impl<T_transformer,
-    size - 1>::tuple_transform_each(std::forward<T>(t), t);
+    size>::tuple_transform_each(std::forward<T>(t), t);
 }
 
 } // namespace internal
diff --git a/tests/test_tuple_transform_each.cc b/tests/test_tuple_transform_each.cc
index 00e76a0..b1ff020 100644
--- a/tests/test_tuple_transform_each.cc
+++ b/tests/test_tuple_transform_each.cc
@@ -261,6 +261,33 @@ test_tuple_transform_each_stdref_non_copyable() {
     "unexpected transform_each()ed tuple type");
 }
 
+static std::string correct_sequence_output;
+
+template <class T_element_from>
+class transform_each_correct_sequence {
+public:
+  static decltype(auto)
+  transform(int from) {
+    correct_sequence_output += std::to_string(from);
+    return std::to_string(from);
+  }
+};
+
+void
+test_tuple_transform_each_correct_sequence() {
+  correct_sequence_output.clear();
+  auto t = std::make_tuple(1, 2, 3);
+  sigc::internal::tuple_transform_each<transform_each_correct_sequence>(t);
+  //std::cout << "correct_sequence_output: " << correct_sequence_output << std::endl;
+  assert(correct_sequence_output == "123");
+}
+
+void
+test_tuple_transform_each_empty_tuple() {
+  auto t = std::tuple<>();
+  sigc::internal::tuple_transform_each<transform_to_string>(t);
+}
+
 int
 main() {
   test_tuple_type_transform_each_same_types();
@@ -274,5 +301,9 @@ main() {
   test_tuple_transform_each_stdref();
   test_tuple_transform_each_stdref_non_copyable();
 
+  test_tuple_transform_each_correct_sequence();
+
+  test_tuple_transform_each_empty_tuple();
+
   return EXIT_SUCCESS;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]