Quellcode durchsuchen

Stl support: cm::append now supports any sequential container

Marc Chevrier vor 5 Jahren
Ursprung
Commit
73d1da4f86
3 geänderte Dateien mit 146 neuen und 16 gelöschten Zeilen
  1. 1 0
      Tests/CMakeLib/testCMExtAlgorithm.cxx
  2. 127 16
      Utilities/std/cmext/algorithm
  3. 18 0
      Utilities/std/cmext/type_traits

+ 1 - 0
Tests/CMakeLib/testCMExtAlgorithm.cxx

@@ -1,5 +1,6 @@
 #include <iostream>
 #include <memory>
+#include <type_traits>
 #include <utility>
 #include <vector>
 

+ 127 - 16
Utilities/std/cmext/algorithm

@@ -10,43 +10,154 @@
 #include <iterator>
 #include <memory>
 #include <utility>
-#include <vector>
 
 #include <cm/type_traits>
 #include <cmext/iterator>
 
+#if defined(__SUNPRO_CC) && defined(__sparc)
+#  include <list>
+#  include <vector>
+#else
+#  include <cmext/type_traits>
+#endif
+
 namespace cm {
 
-template <typename T>
-void append(std::vector<std::unique_ptr<T>>& v,
-            std::vector<std::unique_ptr<T>>&& r)
+#if defined(__SUNPRO_CC) && defined(__sparc)
+// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
+// templates with constraints.
+// So, on this platform, use only simple templates.
+#  define APPEND_TWO(C1, C2)                                                  \
+    template <typename T, typename U>                                         \
+    void append(C1<std::unique_ptr<T>>& v, C2<std::unique_ptr<U>>&& r)        \
+    {                                                                         \
+      std::transform(                                                         \
+        r.begin(), r.end(), std::back_inserter(v),                            \
+        [](std::unique_ptr<U>& item) { return std::move(item); });            \
+      r.clear();                                                              \
+    }                                                                         \
+                                                                              \
+    template <typename T, typename U>                                         \
+    void append(C1<T*>& v, C2<std::unique_ptr<U>> const& r)                   \
+    {                                                                         \
+      std::transform(                                                         \
+        r.begin(), r.end(), std::back_inserter(v),                            \
+        [](const std::unique_ptr<U>& item) { return item.get(); });           \
+    }
+
+#  define APPEND_ONE(C)                                                       \
+    template <typename T, typename InputIt,                                   \
+              cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> =   \
+                0>                                                            \
+    void append(C<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(C<T>& v, Range const& r)                                      \
+    {                                                                         \
+      v.insert(v.end(), r.begin(), r.end());                                  \
+    }
+
+#  define APPEND(C)                                                           \
+    APPEND_TWO(C, C)                                                          \
+    APPEND_ONE(C)
+
+#  define APPEND_MIX(C1, C2)                                                  \
+    APPEND_TWO(C1, C2)                                                        \
+    APPEND_TWO(C2, C1)
+
+// For now, manage only support for std::vector and std::list.
+// Other sequential container support can be added if needed.
+APPEND(std::vector)
+APPEND(std::list)
+APPEND_MIX(std::vector, std::list)
+
+#  undef APPEND
+#  undef APPEND_MIX
+#  undef APPEND_TWO
+#  undef APPEND_ONE
+
+#else
+
+template <
+  typename Container1, typename Container2,
+  cm::enable_if_t<
+    cm::is_sequence_container<Container1>::value &&
+      cm::is_unique_ptr<typename Container1::value_type>::value &&
+      cm::is_unique_ptr<typename Container2::value_type>::value &&
+      std::is_convertible<typename Container2::value_type::pointer,
+                          typename Container1::value_type::pointer>::value,
+    int> = 0>
+void append(Container1& v, Container2&& r)
 {
-  std::transform(r.begin(), r.end(), std::back_inserter(v),
-                 [](std::unique_ptr<T>& item) { return std::move(item); });
+  std::transform(
+    r.begin(), r.end(), std::back_inserter(v),
+    [](typename Container2::value_type& item) { return std::move(item); });
   r.clear();
 }
 
-template <typename T>
-void append(std::vector<T*>& v, std::vector<std::unique_ptr<T>> const& r)
+template <typename Container1, typename Container2,
+          cm::enable_if_t<
+            cm::is_sequence_container<Container1>::value &&
+              std::is_pointer<typename Container1::value_type>::value &&
+              cm::is_unique_ptr<typename Container2::value_type>::value &&
+              std::is_convertible<typename Container2::value_type::pointer,
+                                  typename Container1::value_type>::value,
+            int> = 0>
+#  if defined(__SUNPRO_CC)
+void append(Container1& v, Container2 const& r, detail::overload_selector<0>)
+#  else
+void append(Container1& v, Container2 const& r)
+#  endif
 {
-  std::transform(r.begin(), r.end(), std::back_inserter(v),
-                 [](const std::unique_ptr<T>& item) { return item.get(); });
+  std::transform(
+    r.begin(), r.end(), std::back_inserter(v),
+    [](const typename Container2::value_type& 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)
+template <
+  typename Container, typename InputIt,
+  cm::enable_if_t<
+    cm::is_sequence_container<Container>::value &&
+      cm::is_input_iterator<InputIt>::value &&
+      std::is_convertible<typename std::iterator_traits<InputIt>::value_type,
+                          typename Container::value_type>::value,
+    int> = 0>
+void append(Container& 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)
+template <typename Container, typename Range,
+          cm::enable_if_t<
+            cm::is_sequence_container<Container>::value &&
+              cm::is_input_range<Range>::value &&
+              !cm::is_unique_ptr<typename Container::value_type>::value &&
+              !cm::is_unique_ptr<typename Range::value_type>::value &&
+              std::is_convertible<typename Range::value_type,
+                                  typename Container::value_type>::value,
+            int> = 0>
+#  if defined(__SUNPRO_CC)
+void append(Container& v, Range const& r, detail::overload_selector<1>)
+#  else
+void append(Container& v, Range const& r)
+#  endif
 {
   v.insert(v.end(), r.begin(), r.end());
 }
 
+#  if defined(__SUNPRO_CC)
+template <typename T, typename U>
+void append(T& v, U const& r)
+{
+  cm::append(v, r, detail::overload_selector<1>{});
+}
+#  endif
+#endif
+
 } // namespace cm
 
 #endif

+ 18 - 0
Utilities/std/cmext/type_traits

@@ -10,6 +10,24 @@
 
 namespace cm {
 
+#if defined(__SUNPRO_CC)
+// Oracle DeveloperStudio C++ compiler do not support overloaded templates with
+// same signature but different constraints over template arguments
+// (i.e. meta-programming).
+// As a work-around, use a structure to avoid templates with same signature.
+namespace detail {
+template <int N>
+struct overload_selector : overload_selector<N - 1>
+{
+};
+
+template <>
+struct overload_selector<0>
+{
+};
+}
+#endif
+
 // type traits for managed pointer types
 template <typename>
 struct is_unique_ptr : std::false_type