// Copyright 2017 Elias Kosunen // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // This file is a part of scnlib: // https://github.com/eliaskosunen/scnlib // // The contents of this file are adapted from NanoRange. // https://github.com/tcbrindle/NanoRange // Copyright (c) 2018 Tristan Brindle // Distributed under the Boost Software License, Version 1.0 #ifndef SCN_RANGES_CUSTOM_IMPL_H #define SCN_RANGES_CUSTOM_IMPL_H #include "util.h" #include "../util/string_view.h" #include #include namespace scn { SCN_BEGIN_NAMESPACE namespace custom_ranges { // iterator_category is span.h template struct iterator_category; namespace detail { template struct iterator_category { }; template struct iterator_category : std::enable_if::value, contiguous_iterator_tag> { }; template struct iterator_category : iterator_category { }; template struct iterator_category< T, detail::void_t> { using type = typename T::iterator_category; }; } // namespace detail template struct iterator_category : detail::iterator_category { }; template using iterator_category_t = typename iterator_category::type; template using iter_reference_t = decltype(*SCN_DECLVAL(T&)); // iter_difference_t template struct incrementable_traits; namespace detail { struct empty { }; template struct with_difference_type { using difference_type = T; }; template struct incrementable_traits_helper { }; template <> struct incrementable_traits_helper { }; template struct incrementable_traits_helper : std::conditional::value, with_difference_type, empty>::type { }; template struct incrementable_traits_helper : incrementable_traits::type> { }; template struct has_member_difference_type : std::false_type { }; template struct has_member_difference_type< T, detail::void_t> : std::true_type { }; template struct incrementable_traits_helper< T, typename std::enable_if< has_member_difference_type::value>::type> { using difference_type = typename T::difference_type; }; template struct incrementable_traits_helper< T, typename std::enable_if< !std::is_pointer::value && !has_member_difference_type::value && std::is_integral::value>:: type> : with_difference_type::type> { }; } // namespace detail template struct incrementable_traits : detail::incrementable_traits_helper { }; template using iter_difference_t = typename incrementable_traits::difference_type; // iter_value_t template struct readable_traits; namespace detail { template struct with_value_type { using value_type = T; }; template struct readable_traits_helper { }; template struct readable_traits_helper : std::conditional< std::is_object::value, with_value_type::type>, empty>::type { }; template struct readable_traits_helper< I, typename std::enable_if::value>::type> : readable_traits::type> { }; template struct readable_traits_helper< const I, typename std::enable_if::value>::type> : readable_traits::type> { }; template struct member_value_type : std::conditional::value, with_value_type, empty>::type { }; template struct _member_element_type : std::conditional< std::is_object::value, with_value_type::type>, empty>::type { }; template using member_value_type_t = typename T::value_type; template struct has_member_value_type : exists { }; template using member_element_type_t = typename T::element_type; template struct has_member_element_type : exists { }; template struct readable_traits_helper< T, typename std::enable_if< has_member_value_type::value && !has_member_element_type::value>::type> : member_value_type { }; template struct readable_traits_helper< T, typename std::enable_if::value && !has_member_value_type::value>::type> : _member_element_type { }; template struct readable_traits_helper< T, typename std::enable_if< has_member_element_type::value && has_member_value_type::value>::type> { }; } // namespace detail template struct readable_traits : detail::readable_traits_helper { }; template using iter_value_t = typename readable_traits::value_type; // sentinel_for namespace detail { struct sentinel_for_concept { template auto _test_requires(S s, I i) -> decltype(scn::detail::valid_expr(*i, i == s, i != s)); }; } // namespace detail template struct sentinel_for : std::integral_constant< bool, std::is_default_constructible::value && std::is_copy_constructible::value && detail::_requires:: value> { }; // sized_sentinel_for namespace detail { struct sized_sentinel_for_concept { template auto _test_requires(const S& s, const I& i) -> decltype( detail::requires_expr< std::is_same>::value>{}, detail::requires_expr< std::is_same>::value>{}); }; } // namespace detail template struct sized_sentinel_for : std::integral_constant< bool, detail::_requires:: value && sentinel_for::value> { }; template struct sized_sentinel_for : std::false_type { }; template struct sized_sentinel_for : std::false_type { }; template <> struct sized_sentinel_for : std::false_type { }; // begin namespace _begin { template void begin(T&&) = delete; template void begin(std::initializer_list&&) = delete; struct fn { private: template static SCN_CONSTEXPR14 void impl(T(&&)[N], detail::priority_tag<3>) = delete; template static SCN_CONSTEXPR14 auto impl( T (&t)[N], detail::priority_tag<3>) noexcept -> decltype((t) + 0) { return (t) + 0; } template static SCN_CONSTEXPR14 auto impl( basic_string_view sv, detail::priority_tag<2>) noexcept -> decltype(sv.begin()) { return sv.begin(); } template static SCN_CONSTEXPR14 auto impl(T& t, detail::priority_tag<1>) noexcept(noexcept( ::scn::custom_ranges::detail::decay_copy(t.begin()))) -> decltype(::scn::custom_ranges::detail::decay_copy( t.begin())) { return ::scn::custom_ranges::detail::decay_copy(t.begin()); } template static SCN_CONSTEXPR14 auto impl(T&& t, detail::priority_tag<0>) noexcept( noexcept(::scn::custom_ranges::detail::decay_copy( begin(SCN_FWD(t))))) -> decltype(::scn::custom_ranges::detail::decay_copy( begin(SCN_FWD(t)))) { return ::scn::custom_ranges::detail::decay_copy( begin(SCN_FWD(t))); } public: template SCN_CONSTEXPR14 auto operator()(T&& t) const noexcept( noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<3>{}))) -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<3>{})) { return fn::impl(SCN_FWD(t), detail::priority_tag<3>{}); } }; } // namespace _begin namespace { constexpr auto& begin = detail::static_const<_begin::fn>::value; } // end namespace _end { template void end(T&&) = delete; template void end(std::initializer_list&&) = delete; struct fn { private: template static constexpr void impl(T(&&)[N], detail::priority_tag<2>) = delete; template static constexpr auto impl(T (&t)[N], detail::priority_tag<2>) noexcept -> decltype((t) + N) { return (t) + N; } template static constexpr auto impl(basic_string_view sv, detail::priority_tag<2>) noexcept -> decltype(sv.end()) { return sv.end(); } SCN_GCC_PUSH SCN_GCC_IGNORE("-Wnoexcept") template static constexpr auto impl(T& t, detail::priority_tag<1>) noexcept( noexcept(::scn::custom_ranges::detail::decay_copy(t.end()))) -> decltype(::scn::custom_ranges::detail::decay_copy( t.end())) { return ::scn::custom_ranges::detail::decay_copy(t.end()); } template static constexpr auto impl(T& t, detail::priority_tag<0>) noexcept(noexcept( ::scn::custom_ranges::detail::decay_copy(end(SCN_FWD(t))))) -> S { return ::scn::custom_ranges::detail::decay_copy( end(SCN_FWD(t))); } public: template constexpr auto operator()(T&& t) const noexcept( noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<2>{}))) -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<2>{})) { return fn::impl(SCN_FWD(t), detail::priority_tag<2>{}); } SCN_GCC_POP }; } // namespace _end namespace { constexpr auto& end = detail::static_const<_end::fn>::value; } // cbegin namespace _cbegin { struct fn { template constexpr auto operator()(const T& t) const noexcept(noexcept(::scn::custom_ranges::begin(t))) -> decltype(::scn::custom_ranges::begin(t)) { return ::scn::custom_ranges::begin(t); } template constexpr auto operator()(const T&& t) const noexcept(noexcept( ::scn::custom_ranges::begin(static_cast(t)))) -> decltype(::scn::custom_ranges::begin( static_cast(t))) { return ::scn::custom_ranges::begin( static_cast(t)); } }; } // namespace _cbegin namespace { constexpr auto& cbegin = detail::static_const<_cbegin::fn>::value; } // cend namespace _cend { struct fn { template constexpr auto operator()(const T& t) const noexcept(noexcept(::scn::custom_ranges::end(t))) -> decltype(::scn::custom_ranges::end(t)) { return ::scn::custom_ranges::end(t); } template constexpr auto operator()(const T&& t) const noexcept(noexcept( ::scn::custom_ranges::end(static_cast(t)))) -> decltype(::scn::custom_ranges::end( static_cast(t))) { return ::scn::custom_ranges::end(static_cast(t)); } }; } // namespace _cend namespace { constexpr auto& cend = detail::static_const<_cend::fn>::value; } // range namespace detail { struct range_impl_concept { template auto _test_requires(T&& t) -> decltype(::scn::custom_ranges::begin(SCN_FWD(t)), ::scn::custom_ranges::end(SCN_FWD(t))); }; template struct range_impl : _requires { }; struct range_concept { template static auto test(long) -> std::false_type; template static auto test(int) -> typename std::enable_if::value, std::true_type>::type; }; } // namespace detail template struct range : decltype(detail::range_concept::test(0)) { }; template struct forwarding_range : std::integral_constant::value && detail::range_impl::value> { }; // typedefs template using iterator_t = typename std::enable_if::value, decltype(::scn::custom_ranges::begin( SCN_DECLVAL(R&)))>::type; template using sentinel_t = typename std::enable_if::value, decltype(::scn::custom_ranges::end( SCN_DECLVAL(R&)))>::type; template using range_difference_t = typename std::enable_if::value, iter_difference_t>>::type; template using range_value_t = typename std::enable_if::value, iter_value_t>>::type; template using range_reference_t = typename std::enable_if::value, iter_reference_t>>::type; // view struct view_base { }; namespace detail { template struct is_std_non_view : std::false_type { }; template struct is_std_non_view> : std::true_type { }; template struct enable_view_helper : std::conditional< std::is_base_of::value, std::true_type, typename std::conditional< is_std_non_view::value, std::false_type, typename std::conditional< range::value && range::value, std::is_same, range_reference_t>, std::true_type>::type>::type>::type { }; template struct view_impl : std::integral_constant< bool, std::is_copy_constructible::value && std::is_default_constructible::value && detail::enable_view_helper::value> { }; } // namespace detail template struct view : std::conditional::value, detail::view_impl, std::false_type>::type { }; // data template struct _is_object_pointer : std::integral_constant< bool, std::is_pointer

::value && std::is_object>::value> { }; namespace _data { struct fn { private: template static constexpr auto impl( std::basic_string& str, detail::priority_tag<2>) noexcept -> typename std:: basic_string::pointer { return std::addressof(*str.begin()); } template static constexpr auto impl( const std::basic_string& str, detail::priority_tag<2>) noexcept -> typename std:: basic_string::const_pointer { return std::addressof(*str.begin()); } template static constexpr auto impl( std::basic_string&& str, detail::priority_tag<2>) noexcept -> typename std:: basic_string::pointer { return std::addressof(*str.begin()); } template static constexpr auto impl(T& t, detail::priority_tag<1>) noexcept(noexcept( ::scn::custom_ranges::detail::decay_copy(t.data()))) -> typename std::enable_if<_is_object_pointer::value, D>::type { return ::scn::custom_ranges::detail::decay_copy(t.data()); } template static constexpr auto impl(T&& t, detail::priority_tag<0>) noexcept( noexcept(::scn::custom_ranges::begin(SCN_FWD(t)))) -> typename std::enable_if< _is_object_pointer::value, decltype(::scn::custom_ranges::begin(SCN_FWD(t)))>::type { return ::scn::custom_ranges::begin(SCN_FWD(t)); } public: template constexpr auto operator()(T&& t) const noexcept( noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<2>{}))) -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<2>{})) { return fn::impl(SCN_FWD(t), detail::priority_tag<2>{}); } }; } // namespace _data namespace { constexpr auto& data = detail::static_const<_data::fn>::value; } // size template struct disable_sized_range : std::false_type { }; namespace _size { template void size(T&&) = delete; template void size(T&) = delete; struct fn { private: template static constexpr std::size_t impl( const T(&&)[N], detail::priority_tag<3>) noexcept { return N; } template static constexpr std::size_t impl( const T (&)[N], detail::priority_tag<3>) noexcept { return N; } template static constexpr auto impl(T&& t, detail::priority_tag<2>) noexcept( noexcept(::scn::custom_ranges::detail::decay_copy( SCN_FWD(t).size()))) -> typename std::enable_if< std::is_integral::value && !disable_sized_range< detail::remove_cvref_t>::value, I>::type { return ::scn::custom_ranges::detail::decay_copy( SCN_FWD(t).size()); } template static constexpr auto impl(T&& t, detail::priority_tag<1>) noexcept(noexcept( ::scn::custom_ranges::detail::decay_copy(size(SCN_FWD(t))))) -> typename std::enable_if< std::is_integral::value && !disable_sized_range< detail::remove_cvref_t>::value, I>::type { return ::scn::custom_ranges::detail::decay_copy( size(SCN_FWD(t))); } template static constexpr auto impl(T&& t, detail::priority_tag<0>) noexcept( noexcept(::scn::custom_ranges::detail::decay_copy( ::scn::custom_ranges::end(t) - ::scn::custom_ranges::begin(t)))) -> typename std::enable_if< !std::is_array>::value, D>::type { return ::scn::custom_ranges::detail::decay_copy( ::scn::custom_ranges::end(t) - ::scn::custom_ranges::begin(t)); } public: template constexpr auto operator()(T&& t) const noexcept( noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<3>{}))) -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<3>{})) { return fn::impl(SCN_FWD(t), detail::priority_tag<3>{}); } }; } // namespace _size namespace { constexpr auto& size = detail::static_const<_size::fn>::value; } // empty namespace _empty_ns { struct fn { private: template static constexpr auto impl(T&& t, detail::priority_tag<2>) noexcept( noexcept((bool(SCN_FWD(t).empty())))) -> decltype((bool(SCN_FWD(t).empty()))) { return bool((SCN_FWD(t).empty())); } template static constexpr auto impl(T&& t, detail::priority_tag<1>) noexcept( noexcept(::scn::custom_ranges::size(SCN_FWD(t)) == 0)) -> decltype(::scn::custom_ranges::size(SCN_FWD(t)) == 0) { return ::scn::custom_ranges::size(SCN_FWD(t)) == 0; } template static constexpr auto impl(T&& t, detail::priority_tag<0>) noexcept( noexcept(::scn::custom_ranges::begin(t) == ::scn::custom_ranges::end(t))) -> decltype(::scn::custom_ranges::begin(t) == ::scn::custom_ranges::end(t)) { return ::scn::custom_ranges::begin(t) == ::scn::custom_ranges::end(t); } public: template constexpr auto operator()(T&& t) const noexcept( noexcept(fn::impl(SCN_FWD(t), detail::priority_tag<2>{}))) -> decltype(fn::impl(SCN_FWD(t), detail::priority_tag<2>{})) { return fn::impl(SCN_FWD(t), detail::priority_tag<2>{}); } }; } // namespace _empty_ns namespace { constexpr auto& empty = detail::static_const<_empty_ns::fn>::value; } // sized_range namespace detail { struct sized_range_concept { template auto _test_requires(T& t) -> decltype(::scn::custom_ranges::size(t)); }; } // namespace detail template struct sized_range : std::integral_constant< bool, range::value && !disable_sized_range>::value && detail::_requires::value> { }; // contiguous_range namespace detail { struct contiguous_range_concept { template static auto test(long) -> std::false_type; template static auto test(int) -> typename std::enable_if< _requires::value, std::true_type>::type; template auto _test_requires(T& t) -> decltype(requires_expr>::type>::value>{}); }; } // namespace detail template struct contiguous_range : decltype(detail::contiguous_range_concept::test(0)) { }; // subrange template class view_interface : public view_base { static_assert(std::is_class::value, ""); static_assert( std::is_same::type>::value, ""); private: SCN_CONSTEXPR14 D& derived() noexcept { return static_cast(*this); } constexpr D& derived() const noexcept { return static_cast(*this); } public: SCN_NODISCARD SCN_CONSTEXPR14 bool empty() { return ::scn::custom_ranges::begin(derived()) == ::scn::custom_ranges::end(derived()); } SCN_NODISCARD constexpr bool empty() const { return ::scn::custom_ranges::begin(derived()) == ::scn::custom_ranges::end(derived()); } template SCN_CONSTEXPR14 explicit operator bool() { return !::scn::custom_ranges::empty(derived()); } template constexpr explicit operator bool() const { return !::scn::custom_ranges::empty(derived()); } template ::value>::type* = nullptr> auto data() -> decltype(std::addressof( *::scn::custom_ranges::begin(static_cast(*this)))) { return ::scn::custom_ranges::empty(derived()) ? nullptr : std::addressof( *::scn::custom_ranges::begin(derived())); } template ::value>::type* = nullptr> auto data() const -> decltype(std::addressof( *::scn::custom_ranges::begin(static_cast(*this)))) { return ::scn::custom_ranges::empty(derived()) ? nullptr : std::addressof( *::scn::custom_ranges::begin(derived())); } template ::value && sized_sentinel_for, iterator_t>:: value>::type* = nullptr> SCN_CONSTEXPR14 auto size() -> decltype(::scn::custom_ranges::end(static_cast(*this)) - ::scn::custom_ranges::begin(static_cast(*this))) { return ::scn::custom_ranges::end(derived()) - ::scn::custom_ranges::begin(derived()); } template < typename R = D, typename std::enable_if< range::value && sized_sentinel_for, iterator_t>::value>::type* = nullptr> constexpr auto size() const -> decltype(::scn::custom_ranges::end( static_cast(*this)) - ::scn::custom_ranges::begin( static_cast(*this))) { return ::scn::custom_ranges::end(derived()) - ::scn::custom_ranges::begin(derived()); } }; enum class subrange_kind : bool { unsized, sized }; namespace detail { template struct default_subrange_kind : std::integral_constant::value ? subrange_kind::sized : subrange_kind::unsized> { }; } // namespace detail namespace _subrange { template ::value> class subrange; } // namespace _subrange using _subrange::subrange; namespace detail { struct pair_like_concept { template static auto test(long) -> std::false_type; template ::type> static auto test(int) -> typename std::enable_if< _requires::value, std::true_type>::type; template auto _test_requires(T t) -> decltype( requires_expr< std::is_base_of, std::tuple_size>::value>{}, std::declval::type>>(), std::declval::type>>(), requires_expr(t)), const std::tuple_element<0, T>&>::value>{}, requires_expr(t)), const std::tuple_element<1, T>&>::value>{}); }; template struct pair_like : std::integral_constant< bool, !std::is_reference::value && decltype(pair_like_concept::test(0))::value> { }; struct pair_like_convertible_to_concept { template auto _test_requires(T&& t) -> decltype( requires_expr< std::is_convertible(SCN_FWD(t))), U>::value>{}, requires_expr< std::is_convertible(SCN_FWD(t))), V>::value>{}); }; template struct pair_like_convertible_to : std::integral_constant< bool, !range::value && pair_like< typename std::remove_reference::type>::value && _requires:: value> { }; template struct pair_like_convertible_from : std::integral_constant< bool, !range::value && pair_like< typename std::remove_reference::type>::value && std::is_constructible::value> { }; struct iterator_sentinel_pair_concept { template static auto test(long) -> std::false_type; template static auto test(int) -> typename std::enable_if< !range::value && pair_like::value && sentinel_for< typename std::tuple_element<1, T>::type, typename std::tuple_element<0, T>::type>::value, std::true_type>::type; }; template struct iterator_sentinel_pair : decltype(iterator_sentinel_pair_concept::test(0)) { }; template struct subrange_data { constexpr subrange_data() = default; constexpr subrange_data(I&& b, S&& e) : begin(SCN_MOVE(b)), end(SCN_MOVE(e)) { } template constexpr subrange_data( I&& b, S&& e, typename std::enable_if>::type) : begin(SCN_MOVE(b)), end(SCN_MOVE(e)) { } constexpr iter_difference_t get_size() const { return distance(begin, end); } I begin{}; S end{}; }; template struct subrange_data { constexpr subrange_data() = default; constexpr subrange_data(I&& b, S&& e, iter_difference_t s) : begin(SCN_MOVE(b)), end(SCN_MOVE(e)), size(s) { } constexpr iter_difference_t get_size() const { return size; } I begin{}; S end{}; iter_difference_t size{0}; }; template auto subrange_range_constructor_constraint_helper_fn(long) -> std::false_type; template auto subrange_range_constructor_constraint_helper_fn(int) -> typename std::enable_if< forwarding_range::value && std::is_convertible, I>::value && std::is_convertible, S>::value, std::true_type>::type; template struct subrange_range_constructor_constraint_helper : decltype(subrange_range_constructor_constraint_helper_fn( 0)) { }; template constexpr subrange_kind subrange_deduction_guide_helper() { return (sized_range::value || sized_sentinel_for, iterator_t>::value) ? subrange_kind::sized : subrange_kind::unsized; } template struct not_same_as : std::integral_constant< bool, !std::is_same, remove_cvref_t>::value> { }; } // namespace detail namespace _subrange { template class subrange : public view_interface> { static_assert(sentinel_for::value, ""); static_assert(K == subrange_kind::sized || !sized_sentinel_for::value, ""); static constexpr bool _store_size = K == subrange_kind::sized && !sized_sentinel_for::value; public: using iterator = I; using sentinel = S; subrange() = default; template ::type* = nullptr> SCN_CONSTEXPR14 subrange(I i, S s) : m_data{SCN_MOVE(i), SCN_MOVE(s)} { } template ::type* = nullptr> SCN_CONSTEXPR14 subrange( I i, S s, typename std::enable_if>::type n) : m_data{SCN_MOVE(i), SCN_MOVE(s), n} { } constexpr I begin() const noexcept { return m_data.begin; } constexpr S end() const noexcept { return m_data.end; } SCN_NODISCARD constexpr bool empty() const noexcept { return m_data.begin == m_data.end; } template ::type* = nullptr> constexpr iter_difference_t size() const noexcept { return m_data.get_size(); } private: detail::subrange_data m_data{}; }; template I begin(subrange&& r) noexcept { return r.begin(); } template S end(subrange&& r) noexcept { return r.end(); } } // namespace _subrange namespace detail { template struct subrange_get_impl; template <> struct subrange_get_impl<0> { template static auto get(const subrange& s) -> decltype(s.begin()) { return s.begin(); } }; template <> struct subrange_get_impl<1> { template static auto get(const subrange& s) -> decltype(s.end()) { return s.end(); } }; } // namespace detail template ::type* = nullptr> auto get(const subrange& s) -> decltype(detail::subrange_get_impl::get(s)) { return detail::subrange_get_impl::get(s); } // reconstructible_range template struct pair_reconstructible_range : std::integral_constant< bool, range::value && forwarding_range< typename std::remove_reference::type>::value && std::is_constructible, sentinel_t>:: value> { }; template struct reconstructible_range : std::integral_constant< bool, range::value && forwarding_range< typename std::remove_reference::type>::value && std::is_constructible< R, subrange, sentinel_t>>::value> { }; } // namespace custom_ranges namespace polyfill_2a { // bidir iterator namespace detail { struct bidirectional_iterator_concept { template auto _test_requires(I i) -> decltype(custom_ranges::detail::requires_expr< std::is_same::value>{}); template static auto test(long) -> std::false_type; template static auto test(int) -> typename std::enable_if< std::is_base_of< custom_ranges::bidirectional_iterator_tag, custom_ranges::iterator_category_t>::value && custom_ranges::detail:: _requires::value, std::true_type>::type; }; } // namespace detail template struct bidirectional_iterator : decltype(detail::bidirectional_iterator_concept::test(0)) { }; // random access iterator namespace detail { struct random_access_iterator_concept { template auto _test_requires(I i, const I j, const custom_ranges::iter_difference_t n) -> decltype(valid_expr( j + n, custom_ranges::detail::requires_expr< std::is_same::value>{}, n + j, #ifndef _MSC_VER custom_ranges::detail::requires_expr< std::is_same::value>{}, #endif j - n, custom_ranges::detail::requires_expr< std::is_same::value>{}, j[n], custom_ranges::detail::requires_expr>::value>{}, custom_ranges::detail::requires_expr< std::is_convertible::value>{})); template static auto test(long) -> std::false_type; template static auto test(int) -> typename std::enable_if< bidirectional_iterator::value && std::is_base_of< custom_ranges::random_access_iterator_tag, custom_ranges::iterator_category_t>::value && custom_ranges::sized_sentinel_for::value && custom_ranges::detail:: _requires::value, std::true_type>::type; }; } // namespace detail template struct random_access_iterator : decltype(detail::random_access_iterator_concept::test(0)) { }; } // namespace polyfill_2a namespace custom_ranges { // advance namespace _advance { struct fn { private: template static constexpr T abs(T t) { return t < T{0} ? -t : t; } template < typename R, typename std::enable_if::value>::type* = nullptr> static SCN_CONSTEXPR14 void impl(R& r, iter_difference_t n) { r += n; } template < typename I, typename std::enable_if< polyfill_2a::bidirectional_iterator::value && !polyfill_2a::random_access_iterator::value>::type* = nullptr> static SCN_CONSTEXPR14 void impl(I& i, iter_difference_t n) { constexpr auto zero = iter_difference_t{0}; if (n > zero) { while (n-- > zero) { ++i; } } else { while (n++ < zero) { --i; } } } template < typename I, typename std::enable_if< !polyfill_2a::bidirectional_iterator::value>::type* = nullptr> static SCN_CONSTEXPR14 void impl(I& i, iter_difference_t n) { while (n-- > iter_difference_t{0}) { ++i; } } template < typename I, typename S, typename std::enable_if< std::is_assignable::value>::type* = nullptr> static SCN_CONSTEXPR14 void impl(I& i, S bound, detail::priority_tag<2>) { i = SCN_MOVE(bound); } template ::value>::type* = nullptr> static SCN_CONSTEXPR14 void impl(I& i, S bound, detail::priority_tag<1>) { fn::impl(i, bound - i); } template static SCN_CONSTEXPR14 void impl(I& i, S bound, detail::priority_tag<0>) { while (i != bound) { ++i; } } template ::value>::type* = nullptr> static SCN_CONSTEXPR14 auto impl(I& i, iter_difference_t n, S bound) -> iter_difference_t { if (fn::abs(n) >= fn::abs(bound - i)) { auto dist = bound - i; fn::impl(i, bound, detail::priority_tag<2>{}); return dist; } else { fn::impl(i, n); return n; } } template < typename I, typename S, typename std::enable_if< polyfill_2a::bidirectional_iterator::value && !sized_sentinel_for::value>::type* = nullptr> static SCN_CONSTEXPR14 auto impl(I& i, iter_difference_t n, S bound) -> iter_difference_t { constexpr iter_difference_t zero{0}; iter_difference_t counter{0}; if (n < zero) { do { --i; --counter; } while (++n < zero && i != bound); } else { while (n-- > zero && i != bound) { ++i; ++counter; } } return counter; } template < typename I, typename S, typename std::enable_if< !polyfill_2a::bidirectional_iterator::value && !sized_sentinel_for::value>::type* = nullptr> static SCN_CONSTEXPR14 auto impl(I& i, iter_difference_t n, S bound) -> iter_difference_t { constexpr iter_difference_t zero{0}; iter_difference_t counter{0}; while (n-- > zero && i != bound) { ++i; ++counter; } return counter; } public: template SCN_CONSTEXPR14 void operator()(I& i, iter_difference_t n) const { fn::impl(i, n); } template ::value>::type* = nullptr> SCN_CONSTEXPR14 void operator()(I& i, S bound) const { fn::impl(i, bound, detail::priority_tag<2>{}); } template ::value>::type* = nullptr> SCN_CONSTEXPR14 iter_difference_t operator()(I& i, iter_difference_t n, S bound) const { return n - fn::impl(i, n, bound); } }; } // namespace _advance namespace { constexpr auto& advance = detail::static_const<_advance::fn>::value; } // distance SCN_GCC_PUSH SCN_GCC_IGNORE("-Wnoexcept") namespace _distance { struct fn { private: template static SCN_CONSTEXPR14 auto impl(I i, S s) noexcept(noexcept(s - i)) -> typename std::enable_if::value, iter_difference_t>::type { return s - i; } template static SCN_CONSTEXPR14 auto impl(I i, S s) noexcept( noexcept(i != s, ++i, ++SCN_DECLVAL(iter_difference_t&))) -> typename std::enable_if::value, iter_difference_t>::type { iter_difference_t counter{0}; while (i != s) { ++i; ++counter; } return counter; } template static SCN_CONSTEXPR14 auto impl(R&& r) noexcept( noexcept(::scn::custom_ranges::size(r))) -> typename std::enable_if< sized_range::value, iter_difference_t>>::type { return static_cast>>( ::scn::custom_ranges::size(r)); } template static SCN_CONSTEXPR14 auto impl(R&& r) noexcept( noexcept(fn::impl(::scn::custom_ranges::begin(r), ::scn::custom_ranges::end(r)))) -> typename std::enable_if< !sized_range::value, iter_difference_t>>::type { return fn::impl(::scn::custom_ranges::begin(r), ::scn::custom_ranges::end(r)); } public: template SCN_CONSTEXPR14 auto operator()(I first, S last) const noexcept(noexcept(fn::impl(SCN_MOVE(first), SCN_MOVE(last)))) -> typename std::enable_if::value, iter_difference_t>::type { return fn::impl(SCN_MOVE(first), SCN_MOVE(last)); } template SCN_CONSTEXPR14 auto operator()(R&& r) const noexcept(noexcept(fn::impl(SCN_FWD(r)))) -> typename std::enable_if< range::value, iter_difference_t>>::type { return fn::impl(SCN_FWD(r)); } }; } // namespace _distance namespace { constexpr auto& distance = detail::static_const<_distance::fn>::value; } SCN_GCC_POP // -Wnoexcept } // namespace custom_ranges namespace polyfill_2a { template using iter_value_t = ::scn::custom_ranges::iter_value_t; template using iter_reference_t = ::scn::custom_ranges::iter_reference_t; template using iter_difference_t = ::scn::custom_ranges::iter_difference_t; } // namespace polyfill_2a SCN_END_NAMESPACE } // namespace scn namespace std { template struct tuple_size<::scn::custom_ranges::subrange> : public integral_constant { }; template struct tuple_element<0, ::scn::custom_ranges::subrange> { using type = I; }; template struct tuple_element<1, ::scn::custom_ranges::subrange> { using type = S; }; using ::scn::custom_ranges::get; } // namespace std #define SCN_CHECK_CONCEPT(C) C::value #endif // SCN_RANGES_CUSTOM_IMPL_H