summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Tests/CMakeLib/CMakeLists.txt1
-rw-r--r--Tests/CMakeLib/testCMExtAlgorithm.cxx117
-rw-r--r--Utilities/std/cm/type_traits7
-rw-r--r--Utilities/std/cmext/algorithm52
-rw-r--r--Utilities/std/cmext/iterator49
5 files changed, 226 insertions, 0 deletions
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 <iostream>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <cmext/algorithm>
+
+namespace {
+
+int failed = 0;
+
+void testAppend()
+{
+ std::cout << "testAppend()" << std::endl;
+
+ // ----------------------------------------------------
+ // cm::append(Vector, Iterator, Iterator)
+ {
+ std::vector<int> v1{ 1, 2, 3 };
+ std::vector<int> v1_ref{ 1, 2, 3, 4, 5, 6 };
+ std::vector<int> v2{ 4, 5, 6 };
+ std::vector<int> 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<int> v1{ 1, 2, 3 };
+ std::vector<int> v1_ref{ 1, 2, 3, 4, 5, 6 };
+ std::vector<int> v2{ 4, 5, 6 };
+ std::vector<int> v2_ref{ 4, 5, 6 };
+
+ cm::append(v1, v2);
+
+ if (v1 != v1_ref || v2 != v2_ref) {
+ ++failed;
+ }
+ }
+
+ // ----------------------------------------------------
+ // cm::append(Vector<*>, Vector<unique_ptr>)
+ {
+ std::vector<int*> v1{ new int(1), new int(2), new int(3) };
+ std::vector<int*> v1_ref = v1;
+ std::vector<std::unique_ptr<int>> 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<unique_ptr>, Vector<unique_ptr>)
+ {
+ std::vector<std::unique_ptr<int>> v1;
+ std::vector<std::unique_ptr<int>> 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<B, T>::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 <bool B>
+using bool_constant = std::integral_constant<bool, B>;
+
// Miscellaneous transformations
template <typename F, typename... ArgTypes>
using invoke_result = std::result_of<F(ArgTypes...)>;
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 <algorithm>
+#include <iterator>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <cm/type_traits>
+#include <cmext/iterator>
+
+namespace cm {
+
+template <typename T>
+void append(std::vector<std::unique_ptr<T>>& v,
+ std::vector<std::unique_ptr<T>>&& r)
+{
+ std::transform(r.begin(), r.end(), std::back_inserter(v),
+ [](std::unique_ptr<T>& item) { return std::move(item); });
+ r.clear();
+}
+
+template <typename T>
+void append(std::vector<T*>& v, std::vector<std::unique_ptr<T>> const& r)
+{
+ std::transform(r.begin(), r.end(), std::back_inserter(v),
+ [](const std::unique_ptr<T>& item) { return item.get(); });
+}
+
+template <typename T, typename InputIt,
+ cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = 0>
+void append(std::vector<T>& v, InputIt first, InputIt last)
+{
+ v.insert(v.end(), first, last);
+}
+
+template <typename T, typename Range,
+ cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0>
+void append(std::vector<T>& 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 <iterator>
+
+#include <cm/type_traits>
+
+namespace cm {
+
+// checks if a type is an iterator type
+template <typename I>
+using is_iterator =
+ std::is_integral<typename std::iterator_traits<I>::difference_type>;
+
+// checks if a type is an input iterator type
+template <typename I>
+using is_input_iterator =
+ std::is_base_of<std::input_iterator_tag,
+ typename std::iterator_traits<I>::iterator_category>;
+
+// checks if a type is a range type: must have a difference_type type
+template <typename Range>
+using is_range = cm::bool_constant<
+ cm::is_iterator<decltype(std::declval<const Range>().begin())>::value &&
+ cm::is_iterator<decltype(std::declval<const Range>().end())>::value>;
+
+// checks if a type is an input range type: must have methods begin() and end()
+// returning an input iterator
+template <typename Range>
+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<typename Range::const_iterator>;
+#else
+ cm::bool_constant<
+ cm::is_input_iterator<decltype(
+ std::declval<const Range>().begin())>::value &&
+ cm::is_input_iterator<decltype(std::declval<const Range>().end())>::value>;
+#endif
+
+} // namespace cm
+
+#endif