[libsigc++2/variadic_bind4: 1/18] Add tuple utils from murrayc-tuple-utils.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsigc++2/variadic_bind4: 1/18] Add tuple utils from murrayc-tuple-utils.
- Date: Wed, 2 Mar 2016 20:26:39 +0000 (UTC)
commit ac213fb1798c81efed6f4c3a9794e7bc4feb4e90
Author: Murray Cumming <murrayc murrayc com>
Date: Wed Mar 2 10:46:01 2016 +0100
Add tuple utils from murrayc-tuple-utils.
sigc++/filelist.am | 6 +
sigc++/tuple_cat.h | 54 +++++++
sigc++/tuple_cdr.h | 68 +++++++++
sigc++/tuple_end.h | 93 ++++++++++++
sigc++/tuple_for_each.h | 103 +++++++++++++
sigc++/tuple_start.h | 80 ++++++++++
sigc++/tuple_transform_each.h | 157 ++++++++++++++++++++
tests/.gitignore | 4 +
tests/Makefile.am | 10 ++
tests/test_tuple_cat.cc | 71 +++++++++
tests/test_tuple_cdr.cc | 76 ++++++++++
tests/test_tuple_end.cc | 132 +++++++++++++++++
tests/test_tuple_for_each.cc | 219 ++++++++++++++++++++++++++++
tests/test_tuple_start.cc | 123 ++++++++++++++++
tests/test_tuple_transform_each.cc | 278 ++++++++++++++++++++++++++++++++++++
15 files changed, 1474 insertions(+), 0 deletions(-)
---
diff --git a/sigc++/filelist.am b/sigc++/filelist.am
index 3c57660..49bbb55 100644
--- a/sigc++/filelist.am
+++ b/sigc++/filelist.am
@@ -55,6 +55,12 @@ sigc_public_h = \
signal_base.h \
slot.h \
trackable.h \
+ tuple_cat.h \
+ tuple_cdr.h \
+ tuple_end.h \
+ tuple_for_each.h \
+ tuple_start.h \
+ tuple_transform_each.h \
type_traits.h \
visit_each.h \
adaptors/adaptor_base.h \
diff --git a/sigc++/tuple_cat.h b/sigc++/tuple_cat.h
new file mode 100644
index 0000000..8cb8d25
--- /dev/null
+++ b/sigc++/tuple_cat.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#ifndef SIGC_TUPLE_UTILS_TUPLE_CAT_H
+#define SIGC_TUPLE_UTILS_TUPLE_CAT_H
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace sigc {
+
+namespace detail {
+
+template <typename T1, typename T2, typename Seq1, typename Seq2>
+struct tuple_type_cat_impl;
+
+template <typename T1, typename T2, std::size_t... I1, std::size_t... I2>
+struct tuple_type_cat_impl<T1, T2, std::index_sequence<I1...>,
+ std::index_sequence<I2...>> {
+ using type = std::tuple<typename std::tuple_element<I1, T1>::type...,
+ typename std::tuple_element<I2, T2>::type...>;
+};
+
+} // detail namespace
+
+/**
+ * Get the type of a tuple without the first item.
+ */
+template <typename T1, typename T2>
+struct tuple_type_cat
+ : detail::tuple_type_cat_impl<T1, T2,
+ std::make_index_sequence<std::tuple_size<T1>::value>,
+ std::make_index_sequence<std::tuple_size<T2>::value>> {};
+
+// There is no tuple_cat() here because std::tuple_cat() exists already in
+// the C++ standard library.
+
+} // namespace sigc
+
+#endif //SIGC_TUPLE_UTILS_TUPLE_CAT_H
diff --git a/sigc++/tuple_cdr.h b/sigc++/tuple_cdr.h
new file mode 100644
index 0000000..580296b
--- /dev/null
+++ b/sigc++/tuple_cdr.h
@@ -0,0 +1,68 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#ifndef SIGC_TUPLE_UTILS_TUPLE_CDR_H
+#define SIGC_TUPLE_UTILS_TUPLE_CDR_H
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace sigc {
+
+/**
+ * Get the type of a tuple without the first item.
+ */
+template <typename T>
+struct tuple_type_cdr; // primary template is not defined
+
+// Partial specialization for tuples of at least one element:
+template <typename H, typename... T>
+struct tuple_type_cdr<std::tuple<H, T...>>
+{
+ using type = std::tuple<T...>;
+};
+
+namespace detail {
+
+template <typename T, std::size_t... I>
+decltype(auto)
+tuple_cdr_impl(T&& t, std::index_sequence<0, I...>)
+{
+ using cdr = typename tuple_type_cdr<std::decay_t<T>>::type;
+ return cdr(std::get<I>(std::forward<T>(t))...);
+}
+
+} // detail namespace
+
+/**
+ * Get the a tuple without the first item.
+ * This is analogous to std::tuple_cat().
+ */
+template <typename T>
+decltype(auto)
+tuple_cdr(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, "tuple size must be non-zero");
+ using seq = std::make_index_sequence<size>;
+ return detail::tuple_cdr_impl(std::forward<T>(t), seq{});
+}
+
+} // namespace sigc
+
+#endif //SIGC_TUPLE_UTILS_TUPLE_CDR_H
diff --git a/sigc++/tuple_end.h b/sigc++/tuple_end.h
new file mode 100644
index 0000000..d36afdd
--- /dev/null
+++ b/sigc++/tuple_end.h
@@ -0,0 +1,93 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#ifndef SIGC_TUPLE_UTILS_TUPLE_END_H
+#define SIGC_TUPLE_UTILS_TUPLE_END_H
+
+#include <sigc++/tuple_cdr.h>
+
+namespace sigc {
+
+namespace detail {
+
+template <typename T, std::size_t remove_from_start>
+struct tuple_type_end_impl {
+ using type = typename tuple_type_end_impl<typename tuple_type_cdr<std::decay_t<T>>::type,
+ remove_from_start - 1>::type;
+};
+
+template <typename T>
+struct tuple_type_end_impl<T, 0> {
+ using type = T;
+};
+
+} // detail namespace
+
+/**
+ * Get the type of a tuple with the last @a len types of the original.
+ */
+template <typename T, std::size_t len>
+struct tuple_type_end
+ : detail::tuple_type_end_impl<T, std::tuple_size<T>::value - len> {};
+
+namespace detail {
+
+template <typename T, std::size_t remove_from_start>
+struct tuple_end_impl {
+ static decltype(auto) // typename tuple_type_end<T, size - remove_from_start>::type
+ tuple_end(T&& t) {
+ static_assert(remove_from_start > 0, "remove_from_start must be more than zero.");
+
+ using cdr = typename tuple_type_cdr<std::decay_t<T>>::type;
+ return tuple_end_impl<cdr, remove_from_start - 1>::tuple_end(
+ tuple_cdr(std::forward<T>(t)));
+ }
+};
+
+template <typename T>
+struct tuple_end_impl<T, 1> {
+ static decltype(auto)
+ tuple_end(T&& t) {
+ return tuple_cdr(std::forward<T>(t));
+ }
+};
+
+template <typename T>
+struct tuple_end_impl<T, 0> {
+ static decltype(auto)
+ tuple_end(T&& t) {
+ return std::forward<T>(t);
+ }
+};
+
+} // detail namespace
+
+/**
+ * Get the tuple with the last @a len items of the original.
+ */
+template <std::size_t len, typename T>
+decltype(auto) // typename tuple_type_end<T, len>::type
+ tuple_end(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(len <= size, "The tuple size must be less than or equal to the length.");
+ constexpr auto size_start = size - len;
+ return detail::tuple_end_impl<T, size_start>::tuple_end(std::forward<T>(t));
+}
+
+} // namespace sigc;
+
+#endif //SIGC_TUPLE_UTILS_TUPLE_END_H
diff --git a/sigc++/tuple_for_each.h b/sigc++/tuple_for_each.h
new file mode 100644
index 0000000..1bf98bd
--- /dev/null
+++ b/sigc++/tuple_for_each.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#ifndef SIGC_TUPLE_UTILS_TUPLE_FOR_EACH_H
+#define SIGC_TUPLE_UTILS_TUPLE_FOR_EACH_H
+
+#include <tuple>
+
+namespace sigc {
+
+namespace detail {
+
+template <template <typename> class T_visitor, std::size_t size_from_index,
+ typename... T_extras>
+struct tuple_for_each_impl {
+ template <typename T>
+ static void
+ tuple_for_each(T&& t, T_extras&&... extras) {
+ //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 > 1, "size must be more than 0.");
+
+ constexpr auto index = size - size_from_index;
+ static_assert(index >= 0, "unexpected index.");
+
+ using element_type = typename std::tuple_element<index, std::decay_t<T>>::type;
+ T_visitor<element_type>::visit(std::get<index>(t), std::forward<T_extras>(extras)...);
+
+ tuple_for_each_impl<T_visitor, size_from_index - 1, T_extras...>::tuple_for_each(
+ std::forward<T>(t), std::forward<T_extras>(extras)...);
+ }
+};
+
+template <template <typename> class T_visitor, typename... T_extras>
+struct tuple_for_each_impl<T_visitor, 1, T_extras...> {
+ template <typename T>
+ static void
+ tuple_for_each(T&& t, T_extras&&... extras) {
+ //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, "size must be more than 0.");
+
+ constexpr auto index = size - 1;
+ static_assert(index >= 0, "unexpected index.");
+
+ using element_type = typename std::tuple_element<index, std::decay_t<T>>::type;
+ T_visitor<element_type>::visit(std::get<index>(std::forward<T>(t)), std::forward<T_extras>(extras)...);
+ }
+};
+
+template <template <typename> class T_visitor, typename... T_extras>
+struct tuple_for_each_impl<T_visitor, 0, T_extras...> {
+ template <typename T>
+ static void
+ tuple_for_each(T&& /* t */, T_extras&&... /* extras */) {
+ //Do nothing because the tuple has no elements.
+ }
+};
+
+} // detail namespace
+
+
+/**
+ * Call the @e T_Visitor functors visit() method for each element,
+ * from the first to the last.
+ *
+ * @tparam T_visitor should be a template that has a static visit() method.
+ * @tparam T the tuple type.
+ * @tparam T_extras the types of any extra arguments to pass to @e T_Visitor's
+ * visit() method.
+ * @param t The tuple whose elements should be visited.
+ * @param extras Any extra arguments to pass to @e T_Visitor's visit() method.
+ */
+template <template <typename> class T_visitor, typename T, typename... T_extras>
+void
+tuple_for_each(T&& t, T_extras&&... extras) {
+ //We use std::decay_t<> because tuple_size is not defined for references.
+ constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
+
+ if(size == 0) {
+ return;
+ }
+
+ detail::tuple_for_each_impl<T_visitor, size, T_extras...>::tuple_for_each(
+ std::forward<T>(t), std::forward<T_extras>(extras)...);
+}
+
+} // namespace sigc
+
+#endif //SIGC_TUPLE_UTILS_TUPLE_FOR_EACH_H
diff --git a/sigc++/tuple_start.h b/sigc++/tuple_start.h
new file mode 100644
index 0000000..95fda2e
--- /dev/null
+++ b/sigc++/tuple_start.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#ifndef SIGC_TUPLE_UTILS_TUPLE_START_H
+#define SIGC_TUPLE_UTILS_TUPLE_START_H
+
+#include <tuple>
+#include <utility>
+
+namespace sigc {
+
+namespace detail {
+
+template <typename T, typename Seq>
+struct tuple_type_start_impl;
+
+template <typename T, std::size_t... I>
+struct tuple_type_start_impl<T, std::index_sequence<I...>> {
+ using type = std::tuple<typename std::tuple_element<I, T>::type...>;
+};
+
+} // detail namespace
+
+/**
+ * Get the type of a tuple with just the first @len items.
+ */
+template <typename T, std::size_t len>
+struct tuple_type_start
+ : detail::tuple_type_start_impl<T, std::make_index_sequence<len>> {};
+
+namespace detail {
+
+template <typename T, typename Seq>
+struct tuple_start_impl;
+
+template <typename T, std::size_t... I>
+struct tuple_start_impl<T, std::index_sequence<I...>> {
+ static decltype(auto)
+ tuple_start(T&& t) {
+ constexpr auto size = std::tuple_size<std::decay_t<T>>::value;
+ constexpr auto len = sizeof...(I);
+ static_assert(len <= size, "The tuple size must be less than or equal to the length.");
+
+ using start = typename tuple_type_start<std::decay_t<T>, len>::type;
+ return start(std::get<I>(std::forward<T>(t))...);
+ }
+};
+
+} // detail namespace
+
+/**
+ * Get the tuple with the last @a len items of the original.
+ */
+template <std::size_t len, typename T>
+decltype(auto) // typename tuple_type_end<T, len>::type
+ tuple_start(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(len <= size, "The tuple size must be less than or equal to the length.");
+
+ return detail::tuple_start_impl<T, std::make_index_sequence<len>>::tuple_start(
+ std::forward<T>(t));
+}
+
+} // namespace sigc;
+
+#endif //SIGC_TUPLE_UTILS_TUPLE_START_H
diff --git a/sigc++/tuple_transform_each.h b/sigc++/tuple_transform_each.h
new file mode 100644
index 0000000..ec95aab
--- /dev/null
+++ b/sigc++/tuple_transform_each.h
@@ -0,0 +1,157 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#ifndef SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
+#define SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
+
+#include <sigc++/tuple_cat.h>
+#include <sigc++/tuple_cdr.h>
+#include <sigc++/tuple_end.h>
+#include <sigc++/tuple_start.h>
+#include <type_traits>
+
+namespace sigc {
+
+namespace detail {
+
+template <typename T, template <typename> class T_transformer,
+ std::size_t index>
+struct tuple_type_transform_each_impl {
+private:
+ using from_element_type = typename std::tuple_element<index, T>::type;
+
+ using to_element_type = typename std::result_of<decltype (
+ &T_transformer<from_element_type>::transform)(from_element_type&)>::type;
+
+ using t_element_type = std::tuple<to_element_type>;
+
+ using t_type_start = typename tuple_type_start<T, index>::type;
+
+ using t_type_end =
+ typename tuple_type_end<T, std::tuple_size<T>::value - index - 1>::type;
+
+ using t_type_with_transformed_element = typename tuple_type_cat<
+ typename tuple_type_cat<t_type_start, t_element_type>::type,
+ t_type_end>::type;
+
+public:
+ using type =
+ typename tuple_type_transform_each_impl<t_type_with_transformed_element,
+ T_transformer, index - 1>::type;
+};
+
+template <typename T, template <typename> class T_transformer>
+struct tuple_type_transform_each_impl<T, T_transformer, 0> {
+private:
+ static constexpr std::size_t index = 0;
+ using from_element_type = typename std::tuple_element<index, T>::type;
+ using to_element_type = typename std::result_of<decltype (
+ &T_transformer<from_element_type>::transform)(from_element_type&)>::type;
+ using t_element_type = std::tuple<to_element_type>;
+
+ using t_type_end =
+ typename tuple_type_end<T, std::tuple_size<std::decay_t<T>>::value - index - 1>::type;
+
+ using t_type_with_transformed_element =
+ typename tuple_type_cat<t_element_type, t_type_end>::type;
+
+public:
+ using type = t_type_with_transformed_element;
+};
+
+} // detail namespace
+
+/**
+ * Get a tuple with each element having the transformed value of the element
+ * in the original tuple.
+ */
+
+template <typename T, template <typename> class T_transformer>
+struct tuple_type_transform_each {
+ using type = typename detail::tuple_type_transform_each_impl<T, T_transformer,
+ std::tuple_size<T>::value - 1>::type;
+};
+
+namespace detail {
+
+template <template <typename> class T_transformer, std::size_t 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;
+ using to_element_type = typename std::result_of<decltype (
+ &T_transformer<from_element_type>::transform)(from_element_type&)>::type;
+ const auto t_element =
+ std::tuple<to_element_type>(T_transformer<from_element_type>::transform(std::get<index>(t_original)));
+
+ 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
+ // through too, so we can modify that directly.
+ // the const version (tuple_transform_each_const()) doesn't have to worry
+ // about this, though avoiding copying would be more efficient.
+ const auto t_end = tuple_end<size - index - 1>(t);
+
+ 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);
+ }
+};
+
+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) {
+ constexpr std::size_t index = 0;
+
+ using from_element_type = typename std::tuple_element<index, T_original>::type;
+ using to_element_type = typename std::result_of<decltype (
+ &T_transformer<from_element_type>::transform)(from_element_type&)>::type;
+ 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);
+ }
+};
+
+} // detail namespace
+
+/**
+ * Get a tuple with each element having the transformed value of the element
+ * in the original tuple.
+ */
+template <template <typename> class T_transformer, typename T>
+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);
+}
+
+} // namespace sigc
+
+#endif //SIGC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H
diff --git a/tests/.gitignore b/tests/.gitignore
index be803fc..ff35316 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -30,4 +30,8 @@
/test_trackable
/test_trackable_move
/test_track_obj
+/test_tuple_cat
+/test_tuple_cdr
+/test_tuple_end
+/test_tuple_start
/test_visit_each
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a429c40..d00e1be 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -50,6 +50,11 @@ check_PROGRAMS = \
test_trackable \
test_trackable_move \
test_track_obj \
+ test_tuple_cat \
+ test_tuple_cdr \
+ test_tuple_end \
+ test_tuple_start \
+ test_tuple_transform_each \
test_visit_each
TESTS = $(check_PROGRAMS)
@@ -86,4 +91,9 @@ test_slot_move_SOURCES = test_slot_move.cc $(sigc_test_util)
test_trackable_SOURCES = test_trackable.cc $(sigc_test_util)
test_trackable_move_SOURCES = test_trackable_move.cc $(sigc_test_util)
test_track_obj_SOURCES = test_track_obj.cc $(sigc_test_util)
+test_tuple_cat_SOURCES = test_tuple_cat.cc $(sigc_test_util)
+test_tuple_cdr_SOURCES = test_tuple_cdr.cc $(sigc_test_util)
+test_tuple_end_SOURCES = test_tuple_end.cc $(sigc_test_util)
+test_tuple_start_SOURCES = test_tuple_start.cc $(sigc_test_util)
+test_tuple_transform_each_SOURCES = test_tuple_transform_each.cc $(sigc_test_util)
test_visit_each_SOURCES = test_visit_each.cc $(sigc_test_util)
diff --git a/tests/test_tuple_cat.cc b/tests/test_tuple_cat.cc
new file mode 100644
index 0000000..d266483
--- /dev/null
+++ b/tests/test_tuple_cat.cc
@@ -0,0 +1,71 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#include <cassert>
+#include <cstdlib>
+#include <sigc++/tuple_cat.h>
+#include <utility>
+//#include <functional>
+
+void
+test_tuple_type_cat() {
+ using type_tuple_is = std::tuple<int, short>;
+ using type_tuple_dc = std::tuple<double, char>;
+ using type_tuple_cat =
+ sigc::tuple_type_cat<type_tuple_is, type_tuple_dc>::type;
+ using type_tuple_expected = std::tuple<int, short, double, char>;
+
+ static_assert(std::tuple_size<type_tuple_cat>::value == 4,
+ "unexpected tuple_cat()ed tuple size.");
+ static_assert(std::is_same<type_tuple_cat, type_tuple_expected>::value,
+ "unexpected tuple_cat()ed tuple type");
+}
+
+/** We don't want to test std::tuple_cat() here,
+ * but this a demonstration that std::ref() works with std::tuple_cat().
+void
+test_tuple_cat_stdref() {
+ std::string a = "yadda1";
+ std::string b = "yaddayadda1";
+ auto t_one =
+ std::make_tuple(std::ref(a), std::ref(b));
+ int c = 2;
+ char d = 'a';
+ auto t_two =
+ std::make_tuple(std::ref(c), std::ref(d));
+ auto t_both = std::tuple_cat(t_one, t_two);
+ a = "hello";
+ b = "world";
+ c = 3;
+ d = 'b';
+
+ assert(std::get<0>(t_both) == "hello");
+ assert(std::get<1>(t_both) == "world");
+ assert(std::get<2>(t_both) == 3);
+ assert(std::get<3>(t_both) == 'b');
+}
+*/
+
+int
+main() {
+ test_tuple_type_cat();
+ // There is no typeutils::tuple_cat() because std::tuple_cat() exists:
+ // test_tuple_cat();
+
+ //test_tuple_cat_stdref();
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/test_tuple_cdr.cc b/tests/test_tuple_cdr.cc
new file mode 100644
index 0000000..b0d74f3
--- /dev/null
+++ b/tests/test_tuple_cdr.cc
@@ -0,0 +1,76 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#include <cassert>
+#include <cstdlib>
+#include <sigc++/tuple_cdr.h>
+#include <utility>
+#include <functional>
+
+void
+test_tuple_type_cdr() {
+ using type_tuple_isd = std::tuple<int, short, double>;
+ using type_tuple_sd = std::tuple<short, double>;
+ using type_tuple_suffix = sigc::tuple_type_cdr<type_tuple_isd>::type;
+
+ static_assert(std::tuple_size<type_tuple_suffix>::value == 2,
+ "unexpected tuple_cdr()ed tuple size.");
+ static_assert(std::is_same<type_tuple_suffix, type_tuple_sd>::value,
+ "unexpected tuple_cdr()ed tuple type");
+}
+
+void
+test_tuple_cdr() {
+ auto t_larger =
+ std::make_tuple(nullptr, std::string("hello"), std::string("world"));
+ auto t_suffix = sigc::tuple_cdr(t_larger);
+ assert(std::get<0>(t_suffix) == "hello");
+ assert(std::get<1>(t_suffix) == "world");
+
+ using type_tuple_suffix = std::tuple<std::string, std::string>;
+
+ static_assert(std::tuple_size<decltype(t_suffix)>::value == 2,
+ "unexpected cdr()ed tuple size.");
+ static_assert(std::is_same<decltype(t_suffix), type_tuple_suffix>::value,
+ "unexpected cdr()ed tuple type");
+}
+
+void
+test_tuple_cdr_stdref() {
+ std::string b = "yadda";
+ std::string c = "yaddayadda";
+ auto t_larger = std::make_tuple(1, std::ref(b), std::ref(c));
+
+ //std::cout << "debug: " << type(std::get<1>(t_larger)) << std::endl;
+
+ auto t_suffix = sigc::tuple_cdr(t_larger);
+ b = "hello";
+ c = "world";
+ //This works, but it's not what we are testing here:
+ //assert(std::get<1>(t_larger) == "hello");
+
+ assert(std::get<0>(t_suffix) == "hello");
+ assert(std::get<1>(t_suffix) == "world");
+}
+
+int
+main() {
+ test_tuple_type_cdr();
+ test_tuple_cdr();
+ test_tuple_cdr_stdref();
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/test_tuple_end.cc b/tests/test_tuple_end.cc
new file mode 100644
index 0000000..ad4b063
--- /dev/null
+++ b/tests/test_tuple_end.cc
@@ -0,0 +1,132 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#include <cassert>
+#include <cstdlib>
+#include <sigc++/tuple_end.h>
+#include <functional>
+
+void
+test_tuple_type_end() {
+ {
+ using type_tuple = std::tuple<int, short, double>;
+ using type_tuple_end = sigc::tuple_type_end<type_tuple, 1>::type;
+ using type_tuple_expected = std::tuple<double>;
+
+ static_assert(std::tuple_size<type_tuple_end>::value == 1,
+ "unexpected tuple_end()ed tuple size.");
+ static_assert(std::is_same<type_tuple_end, type_tuple_expected>::value,
+ "unexpected type_tuple_end type");
+ }
+
+ {
+ using type_tuple = std::tuple<int, short, double>;
+ using type_tuple_end = sigc::tuple_type_end<type_tuple, 2>::type;
+ using type_tuple_expected = std::tuple<short, double>;
+
+ static_assert(std::tuple_size<type_tuple_end>::value == 2,
+ "unexpected tuple_end()ed tuple size.");
+ static_assert(std::is_same<type_tuple_end, type_tuple_expected>::value,
+ "unexpected type_tuple_end type");
+ }
+
+ {
+ using type_tuple = std::tuple<int, short, double>;
+ using type_tuple_end = sigc::tuple_type_end<type_tuple, 3>::type;
+ using type_tuple_expected = std::tuple<int, short, double>;
+
+ static_assert(std::tuple_size<type_tuple_end>::value == 3,
+ "unexpected tuple_end()ed tuple size.");
+ static_assert(std::is_same<type_tuple_end, type_tuple_expected>::value,
+ "unexpected type_tuple_end type");
+ }
+}
+
+void
+test_tuple_end() {
+ {
+ auto t_original =
+ std::make_tuple(nullptr, std::string("hello"), std::string("world"));
+ auto t_suffix = sigc::tuple_end<3>(t_original);
+
+ static_assert(std::tuple_size<decltype(t_suffix)>::value == 3,
+ "unexpected tuple_end()ed tuple size.");
+
+ assert(std::get<0>(t_suffix) == nullptr);
+ assert(std::get<1>(t_suffix) == "hello");
+ assert(std::get<2>(t_suffix) == "world");
+
+ static_assert(std::is_same<decltype(t_suffix), decltype(t_original)>::value,
+ "unexpected end()ed tuple type");
+ }
+
+ {
+ auto t_original =
+ std::make_tuple(nullptr, std::string("hello"), std::string("world"));
+ auto t_suffix = sigc::tuple_end<2>(t_original);
+
+ static_assert(std::tuple_size<decltype(t_suffix)>::value == 2,
+ "unexpected tuple_end()ed tuple size.");
+
+ assert(std::get<0>(t_suffix) == "hello");
+ assert(std::get<1>(t_suffix) == "world");
+
+ using type_tuple_suffix = std::tuple<std::string, std::string>;
+ static_assert(std::is_same<decltype(t_suffix), type_tuple_suffix>::value,
+ "unexpected end()ed tuple type");
+ }
+
+ {
+ auto t_original =
+ std::make_tuple(nullptr, std::string("hello"), std::string("world"));
+ auto t_suffix = sigc::tuple_end<1>(t_original);
+
+ static_assert(std::tuple_size<decltype(t_suffix)>::value == 1,
+ "unexpected tuple_end()ed tuple size.");
+
+ assert(std::get<0>(t_suffix) == "world");
+
+ using type_tuple_suffix = std::tuple<std::string>;
+ static_assert(std::is_same<decltype(t_suffix), type_tuple_suffix>::value,
+ "unexpected end()ed tuple type");
+ }
+}
+
+void
+test_tuple_end_stdref() {
+ std::string c = "yadda";
+ std::string d = "yaddayadda";
+ auto t_larger = std::make_tuple(1, 2, std::ref(c), std::ref(d));
+
+ auto t_suffix = sigc::tuple_end<2>(t_larger);
+ c = "hello";
+ d = "world";
+ //This works, but it's not what we are testing here:
+ //assert(std::get<0>(t_larger) == "hello");
+
+ assert(std::get<0>(t_suffix) == "hello");
+ assert(std::get<1>(t_suffix) == "world");
+}
+
+
+int
+main() {
+ test_tuple_type_end();
+ test_tuple_end();
+ test_tuple_end_stdref();
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/test_tuple_for_each.cc b/tests/test_tuple_for_each.cc
new file mode 100644
index 0000000..b621c57
--- /dev/null
+++ b/tests/test_tuple_for_each.cc
@@ -0,0 +1,219 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#include <cassert>
+#include <cstdlib>
+#include <sigc++/tuple_for_each.h>
+#include <utility>
+//#include <typeinfo>
+#include <iostream>
+#include <functional>
+
+template <class T_element_from>
+class for_each_simple {
+public:
+ static void
+ visit(const T_element_from& from) {
+ std::cout << "for_each_simple(): " << std::to_string(from) << std::endl;
+ }
+};
+
+void
+test_tuple_for_each_same_types() {
+ {
+ auto t_original = std::make_tuple(1, 2, 3);
+ sigc::tuple_for_each<for_each_simple>(t_original);
+ }
+
+ {
+ auto t_original = std::make_tuple(1, (double)2.1f, 3);
+ sigc::tuple_for_each<for_each_simple>(t_original);
+ }
+}
+
+template <class T_element_from>
+class for_each_simple_with_extras {
+public:
+ static void
+ visit(const T_element_from& from, int extra1, const std::string& extra2) {
+ std::cout << "for_each_simple_with_extras(): from=" << std::to_string(from)
+ << ", extra1: " << extra1 << ", extra2: " << extra2 << std::endl;
+ }
+};
+
+void
+test_tuple_for_each_same_types_with_extras() {
+ {
+ auto t_original = std::make_tuple(1, (double)2.1f, 3);
+ sigc::tuple_for_each<for_each_simple_with_extras>(
+ t_original, 89, "eightynine");
+ }
+}
+
+template <class T_element_from>
+class for_each_simple_with_nonconst_extras {
+public:
+ static void
+ visit(const T_element_from& from, int& extra) {
+ extra += (int)from;
+ }
+};
+
+void
+test_tuple_for_each_same_types_with_nonconst_extras() {
+ {
+ auto t_original = std::make_tuple(1, (double)2.1f, 3);
+ int extra = 0;
+
+ sigc::tuple_for_each<for_each_simple_with_nonconst_extras>(t_original, extra);
+ // std::cout << "extra: " << extra << std::endl;
+ assert(extra == 6);
+ }
+}
+
+// The general template declaration.
+// We then provide specializations for each type,
+// so we can test having a different return value for each T_element_from type.
+template <class T_element_from>
+class visitor_with_specializations;
+
+// An int will be converted to a std::string:
+template <>
+class visitor_with_specializations<int> {
+public:
+ static void
+ visit(const int& from) {
+ std::cout << "visitor_with_specializations::visit(): "
+ << std::to_string(from) << std::endl;
+ }
+};
+
+// A double will be converted to a char:
+template <>
+class visitor_with_specializations<double> {
+public:
+ static void
+ visit(const double& from) {
+ std::cout << "visitor_with_specializations::visit(): "
+ << std::to_string(from)[0] << std::endl;
+ }
+};
+
+// A std::string will be converted to an int:
+template <>
+class visitor_with_specializations<std::string> {
+public:
+ static void
+ visit(const std::string& from) {
+ std::cout << "visitor_with_specializations::visit(): " << std::stoi(from)
+ << std::endl;
+ }
+};
+
+void
+test_tuple_for_each_multiple_types() {
+ auto t_original = std::make_tuple(1, (double)2.1f, std::string("3"));
+ sigc::tuple_for_each<visitor_with_specializations>(t_original);
+}
+
+template <class T_element_from>
+class for_each_nonconst {
+public:
+ static void
+ visit(T_element_from& from) {
+ from *= 2;
+ // Or, for instance, call a non-const method on from.
+ }
+};
+
+void
+test_tuple_for_each_nonconst() {
+ auto t = std::make_tuple(1, 2, 3);
+ sigc::tuple_for_each<for_each_nonconst, decltype(t)&>(t);
+ std::cout << std::get<0>(t) << std::endl;
+ assert(std::get<0>(t) == 2);
+ assert(std::get<1>(t) == 4);
+ assert(std::get<2>(t) == 6);
+}
+
+void
+test_tuple_for_each_stdref() {
+ {
+ int a = 1;
+ int b = 2;
+ int c = 3;
+ auto t_original = std::make_tuple(std::ref(a), std::ref(b), std::ref(c));
+ sigc::tuple_for_each<for_each_simple>(t_original);
+ }
+
+ {
+ int a = 1;
+ int b = 2;
+ int c = 3;
+ auto t_original = std::make_tuple(std::ref(a), std::ref(b), std::ref(c));
+ sigc::tuple_for_each<for_each_nonconst>(t_original);
+ assert(a == 2);
+ assert(b == 4);
+ assert(c == 6);
+ }
+}
+
+static std::string correct_sequence_output;
+
+template <class T_element_from>
+class for_each_correct_sequence {
+public:
+ static void
+ visit(const T_element_from& from) {
+ //std::cout << "from: " << from << std::endl;
+ correct_sequence_output += std::to_string(from);
+ }
+};
+
+void
+test_tuple_for_each_correct_sequence() {
+ correct_sequence_output.clear();
+ auto t = std::make_tuple(1, 2, 3);
+ sigc::tuple_for_each<for_each_correct_sequence>(t);
+ //std::cout << "correct_sequence_output: " << correct_sequence_output << std::endl;
+ assert(correct_sequence_output == "123");
+}
+
+void
+test_tuple_for_each_empty_tuple() {
+ auto t = std::tuple<>();
+ sigc::tuple_for_each<for_each_simple>(t);
+}
+
+
+int
+main() {
+ test_tuple_for_each_same_types();
+ test_tuple_for_each_same_types_with_extras();
+ test_tuple_for_each_same_types_with_nonconst_extras();
+
+ test_tuple_for_each_multiple_types();
+
+ test_tuple_for_each_nonconst();
+
+ test_tuple_for_each_stdref();
+
+ test_tuple_for_each_correct_sequence();
+
+ test_tuple_for_each_empty_tuple();
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/test_tuple_start.cc b/tests/test_tuple_start.cc
new file mode 100644
index 0000000..00e4f30
--- /dev/null
+++ b/tests/test_tuple_start.cc
@@ -0,0 +1,123 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#include <cassert>
+#include <cstdlib>
+#include <sigc++/tuple_start.h>
+#include <functional>
+
+void
+test_tuple_type_start() {
+ {
+ using type_tuple = std::tuple<int, short, double>;
+ using type_tuple_start = sigc::tuple_type_start<type_tuple, 1>::type;
+ using type_tuple_expected = std::tuple<int>;
+
+ static_assert(std::is_same<type_tuple_start, type_tuple_expected>::value,
+ "unexpected type_tuple_start type");
+ }
+
+ {
+ using type_tuple = std::tuple<int, short, double>;
+ using type_tuple_start = sigc::tuple_type_start<type_tuple, 2>::type;
+ using type_tuple_expected = std::tuple<int, short>;
+
+ static_assert(std::is_same<type_tuple_start, type_tuple_expected>::value,
+ "unexpected type_tuple_start type");
+ }
+
+ {
+ using type_tuple = std::tuple<int, short, double>;
+ using type_tuple_start = sigc::tuple_type_start<type_tuple, 3>::type;
+ using type_tuple_expected = std::tuple<int, short, double>;
+
+ static_assert(std::is_same<type_tuple_start, type_tuple_expected>::value,
+ "unexpected type_tuple_start type");
+ }
+}
+
+void
+test_tuple_start() {
+ {
+ auto t_original =
+ std::make_tuple(nullptr, std::string("hello"), std::string("world"));
+ auto t_prefix = sigc::tuple_start<3>(t_original);
+
+ static_assert(std::tuple_size<decltype(t_prefix)>::value == 3,
+ "unexpected tuple_start()ed tuple size.");
+
+ assert(std::get<0>(t_prefix) == nullptr);
+ assert(std::get<1>(t_prefix) == "hello");
+ assert(std::get<2>(t_prefix) == "world");
+
+ static_assert(std::is_same<decltype(t_prefix), decltype(t_original)>::value,
+ "unexpected start()ed tuple type");
+ }
+
+ {
+ auto t_original =
+ std::make_tuple(nullptr, std::string("hello"), std::string("world"));
+ auto t_prefix = sigc::tuple_start<2>(t_original);
+
+ static_assert(std::tuple_size<decltype(t_prefix)>::value == 2,
+ "unexpected tuple_start()ed tuple size.");
+
+ assert(std::get<0>(t_prefix) == nullptr);
+ assert(std::get<1>(t_prefix) == "hello");
+
+ using type_tuple_prefix = std::tuple<std::nullptr_t, std::string>;
+ static_assert(std::is_same<decltype(t_prefix), type_tuple_prefix>::value,
+ "unexpected start()ed tuple type");
+ }
+
+ {
+ auto t_original =
+ std::make_tuple(nullptr, std::string("hello"), std::string("world"));
+ auto t_prefix = sigc::tuple_start<1>(t_original);
+
+ static_assert(std::tuple_size<decltype(t_prefix)>::value == 1,
+ "unexpected tuple_start()ed tuple size.");
+
+ assert(std::get<0>(t_prefix) == nullptr);
+
+ using type_tuple_prefix = std::tuple<std::nullptr_t>;
+ static_assert(std::is_same<decltype(t_prefix), type_tuple_prefix>::value,
+ "unexpected start()ed tuple type");
+ }
+}
+
+void
+test_tuple_start_stdref() {
+ std::string a = "yadda";
+ std::string b = "yaddayadda";
+ auto t_larger = std::make_tuple(std::ref(a), std::ref(b), 1);
+
+ auto t_prefix = sigc::tuple_start<2>(t_larger);
+ a = "hello";
+ b = "world";
+ //This works, but it's not what we are testing here:
+ //assert(std::get<0>(t_larger) == "hello");
+
+ assert(std::get<0>(t_prefix) == "hello");
+ assert(std::get<1>(t_prefix) == "world");
+}
+
+int
+main() {
+ test_tuple_type_start();
+ test_tuple_start();
+ test_tuple_start_stdref();
+}
diff --git a/tests/test_tuple_transform_each.cc b/tests/test_tuple_transform_each.cc
new file mode 100644
index 0000000..18b95d6
--- /dev/null
+++ b/tests/test_tuple_transform_each.cc
@@ -0,0 +1,278 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/
+ */
+
+#include <cassert>
+#include <cstdlib>
+#include <sigc++/tuple_transform_each.h>
+#include <utility>
+#include <functional>
+
+template <class T_element_from>
+class transform_to_string {
+public:
+ static decltype(auto)
+ transform(T_element_from& from) {
+ return std::to_string(from);
+ }
+};
+
+void
+test_tuple_type_transform_each_same_types() {
+ using type_tuple_original = std::tuple<int, int>;
+ using type_tuple_transformed =
+ sigc::tuple_type_transform_each<type_tuple_original,
+ transform_to_string>::type;
+ using type_tuple_expected = std::tuple<std::string, std::string>;
+
+ static_assert(
+ std::is_same<type_tuple_transformed, type_tuple_expected>::value,
+ "unexpected tuple_transform_each()ed tuple type");
+}
+
+// In these tests, t_expected has elements all of the same type.
+void
+test_tuple_transform_each_same_types() {
+ {
+ auto t_original = std::make_tuple(1, 2, 3);
+ auto t_transformed =
+ sigc::tuple_transform_each<transform_to_string>(t_original);
+ auto t_expected =
+ std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
+
+ static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
+ "unexpected tuple_transform_each()ed tuple size.");
+
+ assert(std::get<0>(t_transformed) == "1");
+ assert(std::get<1>(t_transformed) == "2");
+ assert(std::get<2>(t_transformed) == "3");
+
+ static_assert(
+ std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
+ "unexpected transform_each()ed tuple type");
+ }
+
+ {
+ auto t_original = std::make_tuple(1, (double)2.1f, 3);
+ auto t_transformed =
+ sigc::tuple_transform_each<transform_to_string>(t_original);
+ auto t_expected =
+ std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
+
+ static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
+ "unexpected tuple_transform_each()ed tuple size.");
+
+ assert(std::get<0>(t_transformed) == "1");
+ assert(std::get<1>(t_transformed).substr(0, 3) == "2.1");
+ assert(std::get<2>(t_transformed) == "3");
+
+ static_assert(
+ std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
+ "unexpected transform_each()ed tuple type");
+ }
+}
+
+// The general template declaration.
+// We then provide specializations for each type,
+// so we can test having a different return value for each T_element_from type.
+template <class T_element_from>
+class transform_to_something;
+
+// An int will be converted to a std::string:
+template <>
+class transform_to_something<int> {
+public:
+ static std::string
+ transform(int& from) {
+ return std::to_string(from);
+ }
+};
+
+// A double will be converted to a char:
+template <>
+class transform_to_something<double> {
+public:
+ static char
+ transform(double& from) {
+ return std::to_string(from)[0];
+ }
+};
+
+// A std::string will be converted to an int:
+template <>
+class transform_to_something<std::string> {
+public:
+ static int
+ transform(std::string& from) {
+ return std::stoi(from);
+ }
+};
+
+void
+test_tuple_type_transform_each_multiple_types() {
+ using type_tuple_original = std::tuple<int, double, std::string>;
+ using type_tuple_transformed =
+ sigc::tuple_type_transform_each<type_tuple_original,
+ transform_to_something>::type;
+ using type_tuple_expected = std::tuple<std::string, char, int>;
+
+ static_assert(
+ std::is_same<type_tuple_transformed, type_tuple_expected>::value,
+ "unexpected tuple_transform_each()ed tuple type");
+}
+
+// In these tests, t_expected has elements of different types.
+void
+test_tuple_transform_each_multiple_types() {
+ auto t_original = std::make_tuple(1, (double)2.1f, std::string("3"));
+ auto t_transformed =
+ sigc::tuple_transform_each<transform_to_something>(t_original);
+ auto t_expected = std::make_tuple(std::string("1"), '2', 3);
+
+ static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
+ "unexpected tuple_transform_each()ed tuple size.");
+
+ assert(std::get<0>(t_transformed) == "1");
+ assert(std::get<1>(t_transformed) == '2');
+ assert(std::get<2>(t_transformed) == 3);
+
+ static_assert(
+ std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
+ "unexpected transform_each()ed tuple type");
+}
+
+template <class T_element_from>
+class transform_each_nonconst {
+public:
+ static int
+ transform(T_element_from& from) {
+ from *= 2;
+ // Or, for instance, call a non-const method on from.
+
+ return from * 10;
+ }
+};
+
+void
+test_tuple_transform_each_nonconst() {
+ auto t = std::make_tuple(1, 2, 3);
+ auto t_transformed =
+ sigc::tuple_transform_each<transform_each_nonconst>(t);
+
+ // Check that t was changed (from * 2):
+ assert(std::get<0>(t) == 2);
+ assert(std::get<1>(t) == 4);
+ assert(std::get<2>(t) == 6);
+
+ // Check that t_transformed has the expected values ( from * 2 * 10):
+ assert(std::get<0>(t_transformed) == 20);
+ assert(std::get<1>(t_transformed) == 40);
+ assert(std::get<2>(t_transformed) == 60);
+}
+
+void
+test_tuple_transform_each_stdref() {
+ int a = 1;
+ int b = 2;
+ int c = 3;
+ auto t_original = std::make_tuple(std::ref(a), std::ref(b), std::ref(c));
+ auto t_transformed =
+ sigc::tuple_transform_each<transform_to_string>(t_original);
+ auto t_expected =
+ std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
+
+ static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
+ "unexpected tuple_transform_each()ed tuple size.");
+
+ assert(std::get<0>(t_transformed) == "1");
+ assert(std::get<1>(t_transformed) == "2");
+ assert(std::get<2>(t_transformed) == "3");
+
+ static_assert(
+ std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
+ "unexpected transform_each()ed tuple type");
+}
+
+
+//This can only be used via std::ref(), for instance.
+//Any attempt to copy or move it, should cause a compiler error.
+class NonCopyable {
+public:
+ explicit NonCopyable(int val)
+ : m_val(val)
+ {}
+
+ int get_val() const {
+ return m_val;
+ }
+
+ NonCopyable(const NonCopyable& src) = delete;
+ NonCopyable& operator=(const NonCopyable& src) = delete;
+
+ NonCopyable(NonCopyable&& src) = delete;
+ NonCopyable& operator=(NonCopyable&& src) = delete;
+
+private:
+ int m_val;
+};
+
+
+template <class T_element_from>
+class transform_noncopyable_to_string {
+public:
+ static decltype(auto)
+ transform(T_element_from&& from) {
+ return std::to_string(from.get_val());
+ }
+};
+
+void
+test_tuple_transform_each_stdref_non_copyable() {
+ NonCopyable a(1);
+ NonCopyable b(2);
+ NonCopyable c(3);
+ auto t_original = std::make_tuple(std::ref(a), std::ref(b), std::ref(c));
+ auto t_transformed =
+ sigc::tuple_transform_each<transform_noncopyable_to_string>(t_original);
+ auto t_expected =
+ std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
+
+ static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
+ "unexpected tuple_transform_each()ed tuple size.");
+
+ assert(std::get<0>(t_transformed) == "1");
+ assert(std::get<1>(t_transformed) == "2");
+ assert(std::get<2>(t_transformed) == "3");
+
+ static_assert(
+ std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
+ "unexpected transform_each()ed tuple type");
+}
+
+int
+main() {
+ test_tuple_type_transform_each_same_types();
+ test_tuple_type_transform_each_multiple_types();
+
+ test_tuple_transform_each_same_types();
+ test_tuple_transform_each_multiple_types();
+
+ test_tuple_transform_each_nonconst();
+
+ test_tuple_transform_each_stdref();
+ test_tuple_transform_each_stdref_non_copyable();
+
+ return EXIT_SUCCESS;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]