blob: 54ab47b1705333c6e143a211e1f60b200edf3edf [file]
// -*-c++-*-
// vim: set ft=cpp:
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#pragma once
#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
# define CMake_HAVE_CXX_RANGES
#endif
#if defined(CMake_HAVE_CXX_RANGES)
# include <ranges>
#else
# include <algorithm>
# include <iterator>
# include <tuple>
# include <vector>
# include <cm/type_traits>
# include <cmext/type_traits>
#endif
namespace cm {
namespace ranges {
namespace views {
#if defined(CMake_HAVE_CXX_RANGES)
using std::ranges::views::keys;
using std::ranges::views::values;
#else
// associative containers
template <
typename Range,
cm::enable_if_t<cm::is_associative_container<Range>::value ||
cm::is_unordered_associative_container<Range>::value,
int> = 0>
std::vector<typename Range::key_type> keys(Range const& range)
{
using key_type = typename Range::key_type;
std::vector<key_type> keys;
keys.reserve(range.size());
std::transform(range.begin(), range.end(),
std::back_inserter<std::vector<key_type>>(keys),
[](typename Range::value_type const& entry) -> key_type {
return entry.first;
});
return keys;
}
template <
typename Range,
cm::enable_if_t<cm::is_associative_container<Range>::value ||
cm::is_unordered_associative_container<Range>::value,
int> = 0>
std::vector<typename Range::mapped_type> values(Range const& range)
{
using value_type = typename Range::mapped_type;
std::vector<value_type> values;
values.reserve(range.size());
std::transform(range.begin(), range.end(),
std::back_inserter<std::vector<value_type>>(values),
[](typename Range::value_type const& entry) -> value_type {
return entry.second;
});
return values;
}
// sequence containers with std::pair<> or std::tuple<> as elements
template <typename Range,
cm::enable_if_t<cm::is_sequence_container<Range>::value &&
cm::is_tuple<1, typename Range::value_type>::value,
int> = 0>
std::vector<typename std::tuple_element<0, typename Range::value_type>::type>
keys(Range const& range)
{
using key_type =
typename std::tuple_element<0, typename Range::value_type>::type;
std::vector<key_type> keys;
keys.reserve(range.size());
std::transform(range.begin(), range.end(),
std::back_inserter<std::vector<key_type>>(keys),
[](typename Range::value_type const& entry) -> key_type {
return std::get<0>(entry);
});
return keys;
}
template <typename Range,
cm::enable_if_t<cm::is_sequence_container<Range>::value &&
cm::is_tuple<2, typename Range::value_type>::value,
int> = 0>
std::vector<typename std::tuple_element<1, typename Range::value_type>::type>
values(Range const& range)
{
using value_type =
typename std::tuple_element<1, typename Range::value_type>::type;
std::vector<value_type> values;
values.reserve(range.size());
std::transform(range.begin(), range.end(),
std::back_inserter<std::vector<value_type>>(values),
[](typename Range::value_type const& entry) -> value_type {
return std::get<1>(entry);
});
return values;
}
#endif
}
}
namespace views = ranges::views;
}