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