You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
9.1 KiB
252 lines
9.1 KiB
4 years ago
|
// -*-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 <cm/type_traits>
|
||
|
#include <cmext/iterator>
|
||
|
#include <cmext/type_traits>
|
||
|
|
||
|
#if defined(__SUNPRO_CC) && defined(__sparc)
|
||
|
# include <list>
|
||
|
# include <vector>
|
||
|
#endif
|
||
|
|
||
|
namespace cm {
|
||
|
|
||
|
#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),
|
||
|
[](typename Container2::value_type& item) { return std::move(item); });
|
||
|
r.clear();
|
||
|
}
|
||
|
|
||
|
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 typename Container2::value_type& item) { return item.get(); });
|
||
|
}
|
||
|
|
||
|
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 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
|
||
|
|
||
|
#if defined(__SUNPRO_CC)
|
||
|
template <typename Iterator, typename Key>
|
||
|
auto contains(Iterator first, Iterator last, Key const& key,
|
||
|
detail::overload_selector<1>) -> decltype(first->first == key)
|
||
|
#else
|
||
|
template <typename Iterator, typename Key,
|
||
|
cm::enable_if_t<
|
||
|
cm::is_input_iterator<Iterator>::value &&
|
||
|
std::is_convertible<Key,
|
||
|
typename std::iterator_traits<
|
||
|
Iterator>::value_type::first_type>::value,
|
||
|
int> = 0>
|
||
|
bool contains(Iterator first, Iterator last, Key const& key)
|
||
|
#endif
|
||
|
{
|
||
|
return std::find_if(
|
||
|
first, last,
|
||
|
[&key](
|
||
|
typename std::iterator_traits<Iterator>::value_type const& item) {
|
||
|
return item.first == key;
|
||
|
}) != last;
|
||
|
}
|
||
|
|
||
|
#if defined(__SUNPRO_CC)
|
||
|
template <typename Iterator, typename Key>
|
||
|
bool contains(Iterator first, Iterator last, Key const& key,
|
||
|
detail::overload_selector<0>)
|
||
|
#else
|
||
|
template <
|
||
|
typename Iterator, typename Key,
|
||
|
cm::enable_if_t<
|
||
|
cm::is_input_iterator<Iterator>::value &&
|
||
|
std::is_convertible<
|
||
|
Key, typename std::iterator_traits<Iterator>::value_type>::value,
|
||
|
int> = 0>
|
||
|
bool contains(Iterator first, Iterator last, Key const& key)
|
||
|
#endif
|
||
|
{
|
||
|
return std::find(first, last, key) != last;
|
||
|
}
|
||
|
|
||
|
#if defined(__SUNPRO_CC)
|
||
|
template <typename Iterator, typename Key>
|
||
|
bool contains(Iterator first, Iterator last, Key const& key)
|
||
|
{
|
||
|
return contains(first, last, key, detail::overload_selector<1>{});
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if defined(__SUNPRO_CC)
|
||
|
template <typename Range, typename Key>
|
||
|
auto contains(Range const& range, Key const& key, detail::overload_selector<1>)
|
||
|
-> decltype(range.find(key) != range.end())
|
||
|
#else
|
||
|
template <
|
||
|
typename Range, typename Key,
|
||
|
cm::enable_if_t<cm::is_associative_container<Range>::value ||
|
||
|
cm::is_unordered_associative_container<Range>::value,
|
||
|
int> = 0>
|
||
|
bool contains(Range const& range, Key const& key)
|
||
|
#endif
|
||
|
{
|
||
|
return range.find(key) != range.end();
|
||
|
}
|
||
|
|
||
|
#if defined(__SUNPRO_CC)
|
||
|
template <typename Range, typename Key>
|
||
|
bool contains(Range const& range, Key const& key, detail::overload_selector<0>)
|
||
|
#else
|
||
|
template <
|
||
|
typename Range, typename Key,
|
||
|
cm::enable_if_t<cm::is_input_range<Range>::value &&
|
||
|
!(cm::is_associative_container<Range>::value ||
|
||
|
cm::is_unordered_associative_container<Range>::value),
|
||
|
int> = 0>
|
||
|
bool contains(Range const& range, Key const& key)
|
||
|
#endif
|
||
|
{
|
||
|
return std::find(std::begin(range), std::end(range), key) != std::end(range);
|
||
|
}
|
||
|
|
||
|
#if defined(__SUNPRO_CC)
|
||
|
template <typename Range, typename Key>
|
||
|
bool contains(Range const& range, Key const& key)
|
||
|
{
|
||
|
return contains(range, key, detail::overload_selector<1>{});
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
} // namespace cm
|
||
|
|
||
|
#endif
|