Header file range/v3/view/join.hpp

#include <meta/meta.hpp>

#include <range/v3/range_fwd.hpp>

#include <range/v3/size.hpp>

#include <range/v3/numeric.hpp>

#include <range/v3/begin_end.hpp>

#include <range/v3/empty.hpp>

#include <range/v3/range_traits.hpp>

#include <range/v3/utility/functional.hpp>

#include <range/v3/utility/static_const.hpp>

#include <range/v3/utility/variant.hpp>

#include <range/v3/view_facade.hpp>

#include <range/v3/view/transform.hpp>

#include <range/v3/view/all.hpp>

#include <range/v3/view/view.hpp>

#include <range/v3/view/single.hpp>

namespace ranges
{
    inline namespace v3
    {
        namespace detail
        {
            template <typename Outer, typename Inner, typename Joiner>
            using join_cardinality_ = std::integral_constant<cardinality, Outer::value==infinite||Inner::value==infinite||(Joiner::value==infinite&&Outer::value!=0&&Outer::value!=1)?infinite:Outer::value==unknown||Inner::value==unknown||(Joiner::value==unknown&&Outer::value!=0&&Outer::value!=1)?unknown:Outer::value==finite||Inner::value==finite||(Joiner::value==finite&&Outer::value!=0&&Outer::value!=1)?finite:static_cast<cardinality>(Outer::value*Inner::value+(Outer::value==0?0:(Outer::value-1)*Joiner::value))>;
            
            template <typename Range, typename JoinRange = void>
            using join_cardinality = join_cardinality_<range_cardinality<Range>, range_cardinality<range_reference_t<Range>>, meta::if_<std::is_same<void, JoinRange>, std::integral_constant<cardinality, static_cast<cardinality>(0)>, range_cardinality<JoinRange>>>;
        }
        
        template <typename Rng, typename ValRng>
        struct join_view
        : view_facade<join_view<Rng, ValRng>, detail::join_cardinality<Rng, ValRng>::value>
        {
            using size_type = common_type_t<range_size_t<Rng>, range_size_t<range_value_t<Rng>>>;
            
            join_view() = default;
            
            join_view(Rng rng, ValRng val);
            
            template <int _concept_requires_175 = 42, typename std::enable_if<(_concept_requires_175==43)||(detail::join_cardinality<Rng, ValRng>::value>=0), int>::type=0>
            constexpr size_type size() const;
            
            template <int _concept_requires_180 = 42, typename std::enable_if<(_concept_requires_180==43)||(detail::join_cardinality<Rng, ValRng>::value<0&&range_cardinality<Rng>::value>=0&&ForwardRange<Rng>()&&SizedRange<range_reference_t<Rng>>()&&SizedRange<ValRng>()), int>::type=0>
            size_type size() const;
        };
        
        namespace view
        {
            struct join_fn
            {
                template <typename Rng>
                using JoinableRange_ = meta::and_<InputRange<Rng>, meta::lazy::invoke<meta::compose<meta::quote<InputRange>, meta::quote<range_reference_t>>, Rng>>;
                
                template <typename Rng, int _concept_requires_314 = 42, typename std::enable_if<(_concept_requires_314==43)||(JoinableRange_<Rng>()), int>::type=0>
                join_view<all_t<Rng>> operator()(Rng&& rng) const;
                
                template <typename Rng, typename Val = range_value_t<range_reference_t<Rng>>, int _concept_requires_320 = 42, typename std::enable_if<(_concept_requires_320==43)||(JoinableRange_<Rng>()), int>::type=0>
                join_view<all_t<Rng>, single_view<Val>> operator()(Rng&& rng, meta::id_t<Val> v) const;
                
                template <typename Rng, typename ValRng, int _concept_requires_330 = 42, typename std::enable_if<(_concept_requires_330==43)||(JoinableRange_<Rng>()&&ForwardRange<ValRng>()), int>::type=0>
                join_view<all_t<Rng>, all_t<ValRng>> operator()(Rng&& rng, ValRng&& val) const;
            };
            
            inline namespace 
            {
                constexpr auto& join = static_const<view<join_fn>>::value;
            }
        }
    }
}