| // -*-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; |
| } |