From a38d04c0764b3550bd7d17b659945a38c1368f1e Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Thu, 5 Dec 2019 17:10:23 +0100 Subject: Refactoring: introduce header cmext/algorithm with append functions --- Tests/CMakeLib/CMakeLists.txt | 1 + Tests/CMakeLib/testCMExtAlgorithm.cxx | 117 ++++++++++++++++++++++++++++++++++ Utilities/std/cm/type_traits | 7 ++ Utilities/std/cmext/algorithm | 52 +++++++++++++++ Utilities/std/cmext/iterator | 49 ++++++++++++++ 5 files changed, 226 insertions(+) create mode 100644 Tests/CMakeLib/testCMExtAlgorithm.cxx create mode 100644 Utilities/std/cmext/algorithm create mode 100644 Utilities/std/cmext/iterator diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index 976c924..25d2de6 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -26,6 +26,7 @@ set(CMakeLib_TESTS testUVRAII.cxx testUVStreambuf.cxx testCMExtMemory.cxx + testCMExtAlgorithm.cxx ) add_executable(testUVProcessChainHelper testUVProcessChainHelper.cxx) diff --git a/Tests/CMakeLib/testCMExtAlgorithm.cxx b/Tests/CMakeLib/testCMExtAlgorithm.cxx new file mode 100644 index 0000000..c731b72 --- /dev/null +++ b/Tests/CMakeLib/testCMExtAlgorithm.cxx @@ -0,0 +1,117 @@ +#include +#include +#include +#include + +#include + +namespace { + +int failed = 0; + +void testAppend() +{ + std::cout << "testAppend()" << std::endl; + + // ---------------------------------------------------- + // cm::append(Vector, Iterator, Iterator) + { + std::vector v1{ 1, 2, 3 }; + std::vector v1_ref{ 1, 2, 3, 4, 5, 6 }; + std::vector v2{ 4, 5, 6 }; + std::vector v2_ref{ 4, 5, 6 }; + + cm::append(v1, v2.begin(), v2.end()); + + if (v1 != v1_ref || v2 != v2_ref) { + ++failed; + } + } + + // ---------------------------------------------------- + // cm::append(Vector, Range) + { + std::vector v1{ 1, 2, 3 }; + std::vector v1_ref{ 1, 2, 3, 4, 5, 6 }; + std::vector v2{ 4, 5, 6 }; + std::vector v2_ref{ 4, 5, 6 }; + + cm::append(v1, v2); + + if (v1 != v1_ref || v2 != v2_ref) { + ++failed; + } + } + + // ---------------------------------------------------- + // cm::append(Vector<*>, Vector) + { + std::vector v1{ new int(1), new int(2), new int(3) }; + std::vector v1_ref = v1; + std::vector> v2; + + v2.emplace_back(new int(4)); + v2.emplace_back(new int(5)); + v2.emplace_back(new int(6)); + + cm::append(v1, v2); + + if (v1.size() == 6 && v2.size() == 3) { + for (int i = 0; i < 3; i++) { + if (v1[i] != v1_ref[i]) { + ++failed; + break; + } + } + for (int i = 0; i < 3; i++) { + if (v1[i + 3] != v2[i].get()) { + ++failed; + break; + } + } + } else { + ++failed; + } + + // free memory to please memory sanitizer + delete v1[0]; + delete v1[1]; + delete v1[2]; + } + + // ---------------------------------------------------- + // cm::append(Vector, Vector) + { + std::vector> v1; + std::vector> v2; + + v1.emplace_back(new int(1)); + v1.emplace_back(new int(2)); + v1.emplace_back(new int(3)); + + v2.emplace_back(new int(4)); + v2.emplace_back(new int(5)); + v2.emplace_back(new int(6)); + + cm::append(v1, std::move(v2)); + + if (v1.size() == 6 && v2.empty()) { + for (int i = 0; i < 6; i++) { + if (*v1[i] != i + 1) { + ++failed; + break; + } + } + } else { + ++failed; + } + } +} +} + +int testCMExtAlgorithm(int /*unused*/, char* /*unused*/ []) +{ + testAppend(); + + return failed; +} diff --git a/Utilities/std/cm/type_traits b/Utilities/std/cm/type_traits index 6d7a2c0..4dfe17b 100644 --- a/Utilities/std/cm/type_traits +++ b/Utilities/std/cm/type_traits @@ -26,12 +26,19 @@ using enable_if_t = typename std::enable_if::type; #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703) +// Helper classes +using std::bool_constant; + // Miscellaneous transformations using std::invoke_result; using std::invoke_result_t; #else +// Helper classes +template +using bool_constant = std::integral_constant; + // Miscellaneous transformations template using invoke_result = std::result_of; diff --git a/Utilities/std/cmext/algorithm b/Utilities/std/cmext/algorithm new file mode 100644 index 0000000..609860c --- /dev/null +++ b/Utilities/std/cmext/algorithm @@ -0,0 +1,52 @@ +// -*-c++-*- +// vim: set ft=cpp: + +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmext_algorithm +#define cmext_algorithm + +#include +#include +#include +#include +#include + +#include +#include + +namespace cm { + +template +void append(std::vector>& v, + std::vector>&& r) +{ + std::transform(r.begin(), r.end(), std::back_inserter(v), + [](std::unique_ptr& item) { return std::move(item); }); + r.clear(); +} + +template +void append(std::vector& v, std::vector> const& r) +{ + std::transform(r.begin(), r.end(), std::back_inserter(v), + [](const std::unique_ptr& item) { return item.get(); }); +} + +template ::value, int> = 0> +void append(std::vector& v, InputIt first, InputIt last) +{ + v.insert(v.end(), first, last); +} + +template ::value, int> = 0> +void append(std::vector& v, Range const& r) +{ + v.insert(v.end(), r.begin(), r.end()); +} + +} // namespace cm + +#endif diff --git a/Utilities/std/cmext/iterator b/Utilities/std/cmext/iterator new file mode 100644 index 0000000..ffe94b1 --- /dev/null +++ b/Utilities/std/cmext/iterator @@ -0,0 +1,49 @@ +// -*-c++-*- +// vim: set ft=cpp: + +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmext_iterator +#define cmext_iterator + +#include + +#include + +namespace cm { + +// checks if a type is an iterator type +template +using is_iterator = + std::is_integral::difference_type>; + +// checks if a type is an input iterator type +template +using is_input_iterator = + std::is_base_of::iterator_category>; + +// checks if a type is a range type: must have a difference_type type +template +using is_range = cm::bool_constant< + cm::is_iterator().begin())>::value && + cm::is_iterator().end())>::value>; + +// checks if a type is an input range type: must have methods begin() and end() +// returning an input iterator +template +using is_input_range = +#if defined(_MSC_VER) && _MSC_VER < 1920 + // MS C++ is not able to evaluate complex type introspection, + // so use a simplified version + cm::is_input_iterator; +#else + cm::bool_constant< + cm::is_input_iterator().begin())>::value && + cm::is_input_iterator().end())>::value>; +#endif + +} // namespace cm + +#endif -- cgit v0.12