1
0

algorithm 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // -*-c++-*-
  2. // vim: set ft=cpp:
  3. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  4. file Copyright.txt or https://cmake.org/licensing for details. */
  5. #ifndef cmext_algorithm
  6. #define cmext_algorithm
  7. #include <algorithm>
  8. #include <iterator>
  9. #include <memory>
  10. #include <utility>
  11. #include <cm/type_traits>
  12. #include <cmext/iterator>
  13. #if defined(__SUNPRO_CC) && defined(__sparc)
  14. # include <list>
  15. # include <vector>
  16. #else
  17. # include <cmext/type_traits>
  18. #endif
  19. namespace cm {
  20. #if defined(__SUNPRO_CC) && defined(__sparc)
  21. // Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
  22. // templates with constraints.
  23. // So, on this platform, use only simple templates.
  24. # define APPEND_TWO(C1, C2) \
  25. template <typename T, typename U> \
  26. void append(C1<std::unique_ptr<T>>& v, C2<std::unique_ptr<U>>&& r) \
  27. { \
  28. std::transform( \
  29. r.begin(), r.end(), std::back_inserter(v), \
  30. [](std::unique_ptr<U>& item) { return std::move(item); }); \
  31. r.clear(); \
  32. } \
  33. \
  34. template <typename T, typename U> \
  35. void append(C1<T*>& v, C2<std::unique_ptr<U>> const& r) \
  36. { \
  37. std::transform( \
  38. r.begin(), r.end(), std::back_inserter(v), \
  39. [](const std::unique_ptr<U>& item) { return item.get(); }); \
  40. }
  41. # define APPEND_ONE(C) \
  42. template <typename T, typename InputIt, \
  43. cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = \
  44. 0> \
  45. void append(C<T>& v, InputIt first, InputIt last) \
  46. { \
  47. v.insert(v.end(), first, last); \
  48. } \
  49. \
  50. template <typename T, typename Range, \
  51. cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0> \
  52. void append(C<T>& v, Range const& r) \
  53. { \
  54. v.insert(v.end(), r.begin(), r.end()); \
  55. }
  56. # define APPEND(C) \
  57. APPEND_TWO(C, C) \
  58. APPEND_ONE(C)
  59. # define APPEND_MIX(C1, C2) \
  60. APPEND_TWO(C1, C2) \
  61. APPEND_TWO(C2, C1)
  62. // For now, manage only support for std::vector and std::list.
  63. // Other sequential container support can be added if needed.
  64. APPEND(std::vector)
  65. APPEND(std::list)
  66. APPEND_MIX(std::vector, std::list)
  67. # undef APPEND
  68. # undef APPEND_MIX
  69. # undef APPEND_TWO
  70. # undef APPEND_ONE
  71. #else
  72. template <
  73. typename Container1, typename Container2,
  74. cm::enable_if_t<
  75. cm::is_sequence_container<Container1>::value &&
  76. cm::is_unique_ptr<typename Container1::value_type>::value &&
  77. cm::is_unique_ptr<typename Container2::value_type>::value &&
  78. std::is_convertible<typename Container2::value_type::pointer,
  79. typename Container1::value_type::pointer>::value,
  80. int> = 0>
  81. void append(Container1& v, Container2&& r)
  82. {
  83. std::transform(
  84. r.begin(), r.end(), std::back_inserter(v),
  85. [](typename Container2::value_type& item) { return std::move(item); });
  86. r.clear();
  87. }
  88. template <typename Container1, typename Container2,
  89. cm::enable_if_t<
  90. cm::is_sequence_container<Container1>::value &&
  91. std::is_pointer<typename Container1::value_type>::value &&
  92. cm::is_unique_ptr<typename Container2::value_type>::value &&
  93. std::is_convertible<typename Container2::value_type::pointer,
  94. typename Container1::value_type>::value,
  95. int> = 0>
  96. # if defined(__SUNPRO_CC)
  97. void append(Container1& v, Container2 const& r, detail::overload_selector<0>)
  98. # else
  99. void append(Container1& v, Container2 const& r)
  100. # endif
  101. {
  102. std::transform(
  103. r.begin(), r.end(), std::back_inserter(v),
  104. [](const typename Container2::value_type& item) { return item.get(); });
  105. }
  106. template <
  107. typename Container, typename InputIt,
  108. cm::enable_if_t<
  109. cm::is_sequence_container<Container>::value &&
  110. cm::is_input_iterator<InputIt>::value &&
  111. std::is_convertible<typename std::iterator_traits<InputIt>::value_type,
  112. typename Container::value_type>::value,
  113. int> = 0>
  114. void append(Container& v, InputIt first, InputIt last)
  115. {
  116. v.insert(v.end(), first, last);
  117. }
  118. template <typename Container, typename Range,
  119. cm::enable_if_t<
  120. cm::is_sequence_container<Container>::value &&
  121. cm::is_input_range<Range>::value &&
  122. !cm::is_unique_ptr<typename Container::value_type>::value &&
  123. !cm::is_unique_ptr<typename Range::value_type>::value &&
  124. std::is_convertible<typename Range::value_type,
  125. typename Container::value_type>::value,
  126. int> = 0>
  127. # if defined(__SUNPRO_CC)
  128. void append(Container& v, Range const& r, detail::overload_selector<1>)
  129. # else
  130. void append(Container& v, Range const& r)
  131. # endif
  132. {
  133. v.insert(v.end(), r.begin(), r.end());
  134. }
  135. # if defined(__SUNPRO_CC)
  136. template <typename T, typename U>
  137. void append(T& v, U const& r)
  138. {
  139. cm::append(v, r, detail::overload_selector<1>{});
  140. }
  141. # endif
  142. #endif
  143. } // namespace cm
  144. #endif