diff options
author | Murray Cumming <murrayc@murrayc.com> | 2016-03-02 10:46:01 +0100 |
---|---|---|
committer | Murray Cumming <murrayc@murrayc.com> | 2016-03-02 11:52:29 +0100 |
commit | f6202b9e7ed9b92efbc683eb804f6ec559c32a9a (patch) | |
tree | d03f77729b9c0a299a8dd052e0f9ac493c34637d | |
parent | 4e65aeba16ba336b2e849e37c64f9135413527ee (diff) | |
download | sigc++-f6202b9e7ed9b92efbc683eb804f6ec559c32a9a.tar.gz |
Add tuple utils from murrayc-tuple-utils.
-rw-r--r-- | sigc++/filelist.am | 6 | ||||
-rw-r--r-- | sigc++/tuple_cat.h | 54 | ||||
-rw-r--r-- | sigc++/tuple_cdr.h | 68 | ||||
-rw-r--r-- | sigc++/tuple_end.h | 93 | ||||
-rw-r--r-- | sigc++/tuple_for_each.h | 82 | ||||
-rw-r--r-- | sigc++/tuple_start.h | 80 | ||||
-rw-r--r-- | sigc++/tuple_transform_each.h | 157 | ||||
-rw-r--r-- | tests/.gitignore | 4 | ||||
-rw-r--r-- | tests/Makefile.am | 10 | ||||
-rw-r--r-- | tests/test_tuple_cat.cc | 71 | ||||
-rw-r--r-- | tests/test_tuple_cdr.cc | 76 | ||||
-rw-r--r-- | tests/test_tuple_end.cc | 132 | ||||
-rw-r--r-- | tests/test_tuple_for_each.cc | 162 | ||||
-rw-r--r-- | tests/test_tuple_start.cc | 123 | ||||
-rw-r--r-- | tests/test_tuple_transform_each.cc | 195 |
15 files changed, 1313 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..922c889 --- /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 MURRAYC_TUPLE_UTILS_TUPLE_CAT_H +#define MURRAYC_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 //MURRAYC_TUPLE_UTILS_TUPLE_CAT_H diff --git a/sigc++/tuple_cdr.h b/sigc++/tuple_cdr.h new file mode 100644 index 0000000..2aa6e50 --- /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 MURRAYC_TUPLE_UTILS_TUPLE_CDR_H +#define MURRAYC_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 //MURRAYC_TUPLE_UTILS_TUPLE_CDR_H diff --git a/sigc++/tuple_end.h b/sigc++/tuple_end.h new file mode 100644 index 0000000..2bf6628 --- /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 MURRAYC_TUPLE_UTILS_TUPLE_END_H +#define MURRAYC_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 //MURRAYC_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..1f74a41 --- /dev/null +++ b/sigc++/tuple_for_each.h @@ -0,0 +1,82 @@ +/* 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 MURRAYC_TUPLE_UTILS_TUPLE_FOR_EACH_H +#define MURRAYC_TUPLE_UTILS_TUPLE_FOR_EACH_H + +#include <tuple> + +namespace sigc { + +namespace detail { + +template <template <typename> class T_visitor, std::size_t index, + typename... T_extras> +struct tuple_for_each_impl { + template <typename T> + static void + tuple_for_each(T&& t, T_extras&&... extras) { + 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, 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, 0, T_extras...> { + template <typename T> + static void + tuple_for_each(T&& t, T_extras&&... extras) { + constexpr std::size_t index = 0; + + 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)...); + } +}; + +} // detail namespace + + +/** + * Get a tuple with each element having the transformed value of the element + * in the original tuple. + * + * @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 - 1, T_extras...>::tuple_for_each( + std::forward<T>(t), std::forward<T_extras>(extras)...); +} + +} // namespace sigc + +#endif //MURRAYC_TUPLE_UTILS_TUPLE_FOR_EACH_H diff --git a/sigc++/tuple_start.h b/sigc++/tuple_start.h new file mode 100644 index 0000000..dd95636 --- /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 MURRAYC_TUPLE_UTILS_TUPLE_START_H +#define MURRAYC_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 //MURRAYC_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..9ec9cfb --- /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 MURRAYC_TUPLE_UTILS_TUPLE_TRANSFORM_EACH_H +#define MURRAYC_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 //MURRAYC_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..86bc46f --- /dev/null +++ b/tests/test_tuple_for_each.cc @@ -0,0 +1,162 @@ +/* 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> + +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); +} + +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(); + + 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..9b0d0e8 --- /dev/null +++ b/tests/test_tuple_transform_each.cc @@ -0,0 +1,195 @@ +/* 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> + +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); +} + +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(); + + return EXIT_SUCCESS; +} |