Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:09:57

0001 /// \file
0002 // Range v3 library
0003 //
0004 //  Copyright Eric Niebler 2013-present
0005 //  Copyright Tomislav Ivek 2015-2016
0006 //
0007 //  Use, modification and distribution is subject to the
0008 //  Boost Software License, Version 1.0. (See accompanying
0009 //  file LICENSE_1_0.txt or copy at
0010 //  http://www.boost.org/LICENSE_1_0.txt)
0011 //
0012 // Project home: https://github.com/ericniebler/range-v3
0013 //
0014 
0015 #ifndef RANGES_V3_VIEW_SET_ALGORITHM_HPP
0016 #define RANGES_V3_VIEW_SET_ALGORITHM_HPP
0017 
0018 #include <algorithm>
0019 #include <iterator>
0020 #include <type_traits>
0021 #include <utility>
0022 
0023 #include <meta/meta.hpp>
0024 
0025 #include <range/v3/range_fwd.hpp>
0026 
0027 #include <range/v3/functional/comparisons.hpp>
0028 #include <range/v3/functional/identity.hpp>
0029 #include <range/v3/functional/invoke.hpp>
0030 #include <range/v3/iterator/default_sentinel.hpp>
0031 #include <range/v3/range/access.hpp>
0032 #include <range/v3/range/primitives.hpp>
0033 #include <range/v3/range/traits.hpp>
0034 #include <range/v3/utility/move.hpp>
0035 #include <range/v3/utility/semiregular_box.hpp>
0036 #include <range/v3/utility/static_const.hpp>
0037 #include <range/v3/view/all.hpp>
0038 #include <range/v3/view/facade.hpp>
0039 #include <range/v3/view/view.hpp>
0040 
0041 #include <range/v3/detail/prologue.hpp>
0042 
0043 namespace ranges
0044 {
0045     /// \addtogroup group-views
0046     /// @{
0047 
0048     /// \cond
0049     namespace detail
0050     {
0051         template<typename Rng1, typename Rng2, typename C, typename P1, typename P2,
0052                  template<bool, typename...> class Cursor, cardinality Cardinality>
0053         struct set_algorithm_view
0054           : view_facade<set_algorithm_view<Rng1, Rng2, C, P1, P2, Cursor, Cardinality>,
0055                         Cardinality>
0056         {
0057         private:
0058             friend range_access;
0059             semiregular_box_t<C> pred_;
0060             semiregular_box_t<P1> proj1_;
0061             semiregular_box_t<P2> proj2_;
0062             Rng1 rng1_;
0063             Rng2 rng2_;
0064 
0065             template<bool IsConst>
0066             using cursor = Cursor<IsConst, Rng1, Rng2, C, P1, P2>;
0067 
0068             cursor<simple_view<Rng1>() && simple_view<Rng2>()> begin_cursor()
0069             {
0070                 return {pred_,
0071                         proj1_,
0072                         proj2_,
0073                         ranges::begin(rng1_),
0074                         ranges::end(rng1_),
0075                         ranges::begin(rng2_),
0076                         ranges::end(rng2_)};
0077             }
0078             CPP_member
0079             auto begin_cursor() const //
0080                 -> CPP_ret(cursor<true>)(
0081                     requires range<Rng1 const> && range<Rng2 const>)
0082             {
0083                 return {pred_,
0084                         proj1_,
0085                         proj2_,
0086                         ranges::begin(rng1_),
0087                         ranges::end(rng1_),
0088                         ranges::begin(rng2_),
0089                         ranges::end(rng2_)};
0090             }
0091 
0092         public:
0093             set_algorithm_view() = default;
0094             set_algorithm_view(Rng1 rng1, Rng2 rng2, C pred, P1 proj1, P2 proj2)
0095               : pred_(std::move(pred))
0096               , proj1_(std::move(proj1))
0097               , proj2_(std::move(proj2))
0098               , rng1_(std::move(rng1))
0099               , rng2_(std::move(rng2))
0100             {}
0101         };
0102 
0103         template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
0104                  typename P2>
0105         struct set_difference_cursor
0106         {
0107         private:
0108             friend struct set_difference_cursor<!IsConst, Rng1, Rng2, C, P1, P2>;
0109             using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
0110             using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
0111             using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
0112             pred_ref_ pred_;
0113             proj1_ref_ proj1_;
0114             proj2_ref_ proj2_;
0115 
0116             template<typename T>
0117             using constify_if = meta::const_if_c<IsConst, T>;
0118 
0119             using R1 = constify_if<Rng1>;
0120             using R2 = constify_if<Rng2>;
0121 
0122             iterator_t<R1> it1_;
0123             sentinel_t<R1> end1_;
0124 
0125             iterator_t<R2> it2_;
0126             sentinel_t<R2> end2_;
0127 
0128             void satisfy()
0129             {
0130                 while(it1_ != end1_)
0131                 {
0132                     if(it2_ == end2_)
0133                         return;
0134 
0135                     if(invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
0136                         return;
0137 
0138                     if(!invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
0139                         ++it1_;
0140 
0141                     ++it2_;
0142                 }
0143             }
0144 
0145         public:
0146             using value_type = range_value_t<constify_if<Rng1>>;
0147             using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
0148                                            single_pass_iterator_<iterator_t<R2>>>;
0149 
0150             set_difference_cursor() = default;
0151             set_difference_cursor(pred_ref_ pred, proj1_ref_ proj1, proj2_ref_ proj2,
0152                                   iterator_t<R1> it1, sentinel_t<R1> end1,
0153                                   iterator_t<R2> it2, sentinel_t<R2> end2)
0154               : pred_(std::move(pred))
0155               , proj1_(std::move(proj1))
0156               , proj2_(std::move(proj2))
0157               , it1_(std::move(it1))
0158               , end1_(std::move(end1))
0159               , it2_(std::move(it2))
0160               , end2_(std::move(end2))
0161             {
0162                 satisfy();
0163             }
0164             template(bool Other)(
0165                 requires IsConst && CPP_NOT(Other)) //
0166                 set_difference_cursor(
0167                     set_difference_cursor<Other, Rng1, Rng2, C, P1, P2> that)
0168               : pred_(std::move(that.pred_))
0169               , proj1_(std::move(that.proj1_))
0170               , proj2_(std::move(that.proj2_))
0171               , it1_(std::move(that.it1_))
0172               , end1_(std::move(that.end1_))
0173               , it2_(std::move(that.it2_))
0174               , end2_(std::move(that.end2_))
0175             {}
0176             // clang-format off
0177             auto CPP_auto_fun(read)()(const)
0178             (
0179                 return *it1_
0180             )
0181             // clang-format on
0182             void next()
0183             {
0184                 ++it1_;
0185                 satisfy();
0186             }
0187             CPP_member
0188             auto equal(set_difference_cursor const & that) const //
0189                 -> CPP_ret(bool)(
0190                     requires forward_range<Rng1>)
0191             {
0192                 // does not support comparing iterators from different ranges
0193                 return it1_ == that.it1_;
0194             }
0195             bool equal(default_sentinel_t) const
0196             {
0197                 return it1_ == end1_;
0198             }
0199             // clang-format off
0200             auto CPP_auto_fun(move)()(const)
0201             (
0202                 return iter_move(it1_)
0203             )
0204             // clang-format on
0205         };
0206 
0207         constexpr cardinality set_difference_cardinality(cardinality c1, cardinality c2)
0208         {
0209             return (c1 == unknown)
0210                        ? unknown
0211                        : (c1 >= 0) || (c1 == finite) ? finite : // else, c1 == infinite
0212                              (c2 >= 0) || (c2 == finite) ? infinite : unknown;
0213         }
0214     } // namespace detail
0215     /// \endcond
0216 
0217     template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
0218     using set_difference_view =
0219         detail::set_algorithm_view<Rng1, Rng2, C, P1, P2, detail::set_difference_cursor,
0220                                    detail::set_difference_cardinality(
0221                                        range_cardinality<Rng1>::value,
0222                                        range_cardinality<Rng2>::value)>;
0223 
0224     namespace views
0225     {
0226         struct set_difference_base_fn
0227         {
0228             template(typename Rng1, typename Rng2, typename C = less,
0229                      typename P1 = identity, typename P2 = identity)(
0230                 requires //
0231                     viewable_range<Rng1> AND input_range<Rng1> AND
0232                     viewable_range<Rng2> AND input_range<Rng2> AND
0233                     indirect_relation<C,
0234                                       projected<iterator_t<Rng1>, P1>,
0235                                       projected<iterator_t<Rng2>, P2>>)
0236             set_difference_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2> //
0237             operator()(Rng1 && rng1,
0238                        Rng2 && rng2,
0239                        C pred = C{},
0240                        P1 proj1 = P1{},
0241                        P2 proj2 = P2{}) const
0242             {
0243                 return {all(static_cast<Rng1 &&>(rng1)),
0244                         all(static_cast<Rng2 &&>(rng2)),
0245                         std::move(pred),
0246                         std::move(proj1),
0247                         std::move(proj2)};
0248             }
0249         };
0250 
0251         struct set_difference_fn : set_difference_base_fn
0252         {
0253             using set_difference_base_fn::operator();
0254 
0255             template(typename Rng2, typename C = less, typename P1 = identity,
0256                      typename P2 = identity)(
0257                 requires viewable_range<Rng2> AND input_range<Rng2> AND (!range<C>))
0258             constexpr auto operator()(Rng2 && rng2,
0259                                       C && pred = C{},
0260                                       P1 proj1 = P1{},
0261                                       P2 proj2 = P2{}) const
0262             {
0263                 return make_view_closure(bind_back(set_difference_base_fn{},
0264                                                    all(rng2),
0265                                                    static_cast<C &&>(pred),
0266                                                    std::move(proj1),
0267                                                    std::move(proj2)));
0268             }
0269         };
0270 
0271         /// \relates set_difference_fn
0272         RANGES_INLINE_VARIABLE(set_difference_fn, set_difference)
0273     } // namespace views
0274 
0275     /// \cond
0276     namespace detail
0277     {
0278         template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
0279                  typename P2>
0280         struct set_intersection_cursor
0281         {
0282         private:
0283             friend struct set_intersection_cursor<!IsConst, Rng1, Rng2, C, P1, P2>;
0284             using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
0285             using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
0286             using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
0287             pred_ref_ pred_;
0288             proj1_ref_ proj1_;
0289             proj2_ref_ proj2_;
0290 
0291             template<typename T>
0292             using constify_if = meta::const_if_c<IsConst, T>;
0293 
0294             using R1 = constify_if<Rng1>;
0295             using R2 = constify_if<Rng2>;
0296 
0297             iterator_t<R1> it1_;
0298             sentinel_t<R1> end1_;
0299 
0300             iterator_t<R2> it2_;
0301             sentinel_t<R2> end2_;
0302 
0303             void satisfy()
0304             {
0305                 while(it1_ != end1_ && it2_ != end2_)
0306                 {
0307                     if(invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
0308                         ++it1_;
0309                     else
0310                     {
0311                         if(!invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
0312                             return;
0313                         ++it2_;
0314                     }
0315                 }
0316             }
0317 
0318         public:
0319             using value_type = range_value_t<R1>;
0320             using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
0321                                            single_pass_iterator_<iterator_t<R2>>>;
0322 
0323             set_intersection_cursor() = default;
0324             set_intersection_cursor(pred_ref_ pred, proj1_ref_ proj1, proj2_ref_ proj2,
0325                                     iterator_t<R1> it1, sentinel_t<R1> end1,
0326                                     iterator_t<R2> it2, sentinel_t<R2> end2)
0327               : pred_(std::move(pred))
0328               , proj1_(std::move(proj1))
0329               , proj2_(std::move(proj2))
0330               , it1_(std::move(it1))
0331               , end1_(std::move(end1))
0332               , it2_(std::move(it2))
0333               , end2_(std::move(end2))
0334             {
0335                 satisfy();
0336             }
0337             template(bool Other)(
0338                 requires IsConst && CPP_NOT(Other)) //
0339                 set_intersection_cursor(
0340                     set_intersection_cursor<Other, Rng1, Rng2, C, P1, P2> that)
0341               : pred_(std::move(that.pred_))
0342               , proj1_(std::move(that.proj1_))
0343               , proj2_(std::move(that.proj2_))
0344               , it1_(std::move(that.it1_))
0345               , end1_(std::move(that.end1_))
0346               , it2_(std::move(that.it2_))
0347               , end2_(std::move(that.end2_))
0348             {}
0349             // clang-format off
0350             auto CPP_auto_fun(read)()(const)
0351             (
0352                 return *it1_
0353             )
0354             // clang-format on
0355             void next()
0356             {
0357                 ++it1_;
0358                 ++it2_;
0359                 satisfy();
0360             }
0361             CPP_member
0362             auto equal(set_intersection_cursor const & that) const //
0363                 -> CPP_ret(bool)(
0364                     requires forward_range<Rng1>)
0365             {
0366                 // does not support comparing iterators from different ranges
0367                 return it1_ == that.it1_;
0368             }
0369             bool equal(default_sentinel_t) const
0370             {
0371                 return (it1_ == end1_) || (it2_ == end2_);
0372             }
0373             // clang-format off
0374             auto CPP_auto_fun(move)()(const)
0375             (
0376                 return iter_move(it1_)
0377             )
0378             // clang-format on
0379         };
0380 
0381         constexpr cardinality set_intersection_cardinality(cardinality c1, cardinality c2)
0382         {
0383             return (c1 == unknown) || (c2 == unknown)
0384                        ? unknown
0385                        : (c1 >= 0 || c1 == finite) || (c2 >= 0 || c2 == finite) ? finite
0386                                                                                 : unknown;
0387         }
0388     } // namespace detail
0389     /// \endcond
0390 
0391     template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
0392     using set_intersection_view =
0393         detail::set_algorithm_view<Rng1, Rng2, C, P1, P2, detail::set_intersection_cursor,
0394                                    detail::set_intersection_cardinality(
0395                                        range_cardinality<Rng1>::value,
0396                                        range_cardinality<Rng2>::value)>;
0397 
0398     namespace views
0399     {
0400         struct set_intersection_base_fn
0401         {
0402             template(typename Rng1, typename Rng2, typename C = less,
0403                      typename P1 = identity, typename P2 = identity)(
0404                 requires viewable_range<Rng1> AND input_range<Rng1> AND
0405                     viewable_range<Rng2> AND input_range<Rng2> AND
0406                     indirect_relation<
0407                         C,
0408                         projected<iterator_t<Rng1>, P1>,
0409                         projected<iterator_t<Rng2>, P2>>)
0410             set_intersection_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2>
0411             operator()(Rng1 && rng1,
0412                        Rng2 && rng2,
0413                        C pred = C{},
0414                        P1 proj1 = P1{},
0415                        P2 proj2 = P2{}) const
0416             {
0417                 return {all(static_cast<Rng1 &&>(rng1)),
0418                         all(static_cast<Rng2 &&>(rng2)),
0419                         std::move(pred),
0420                         std::move(proj1),
0421                         std::move(proj2)};
0422             }
0423         };
0424 
0425         struct set_intersection_fn : set_intersection_base_fn
0426         {
0427             using set_intersection_base_fn::operator();
0428 
0429             template(typename Rng2, typename C = less, typename P1 = identity,
0430                      typename P2 = identity)(
0431                 requires viewable_range<Rng2> AND input_range<Rng2> AND (!range<C>))
0432             constexpr auto operator()(Rng2 && rng2,
0433                                       C && pred = C{},
0434                                       P1 proj1 = P1{},
0435                                       P2 proj2 = P2{}) const
0436             {
0437                 return make_view_closure(bind_back(set_intersection_base_fn{},
0438                                                    all(rng2),
0439                                                    static_cast<C &&>(pred),
0440                                                    std::move(proj1),
0441                                                    std::move(proj2)));
0442             }
0443         };
0444 
0445         /// \relates set_intersection_fn
0446         RANGES_INLINE_VARIABLE(set_intersection_fn, set_intersection)
0447     } // namespace views
0448 
0449     /// \cond
0450     namespace detail
0451     {
0452         template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
0453                  typename P2>
0454         struct set_union_cursor
0455         {
0456         private:
0457             friend struct set_union_cursor<!IsConst, Rng1, Rng2, C, P1, P2>;
0458             using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
0459             using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
0460             using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
0461             pred_ref_ pred_;
0462             proj1_ref_ proj1_;
0463             proj2_ref_ proj2_;
0464 
0465             template<typename T>
0466             using constify_if = meta::const_if_c<IsConst, T>;
0467 
0468             using R1 = constify_if<Rng1>;
0469             using R2 = constify_if<Rng2>;
0470 
0471             iterator_t<R1> it1_;
0472             sentinel_t<R1> end1_;
0473 
0474             iterator_t<R2> it2_;
0475             sentinel_t<R2> end2_;
0476 
0477             enum class state_t
0478             {
0479                 FIRST,
0480                 SECOND
0481             } state;
0482 
0483             void satisfy()
0484             {
0485                 if(it1_ == end1_)
0486                 {
0487                     state = state_t::SECOND;
0488                     return;
0489                 }
0490 
0491                 if(it2_ == end2_)
0492                 {
0493                     state = state_t::FIRST;
0494                     return;
0495                 }
0496 
0497                 if(invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
0498                 {
0499                     state = state_t::SECOND;
0500                     return;
0501                 }
0502 
0503                 if(!invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
0504                     ++it2_;
0505 
0506                 state = state_t::FIRST;
0507             }
0508 
0509         public:
0510             using value_type = common_type_t<range_value_t<R1>, range_value_t<R2>>;
0511             using reference_type =
0512                 common_reference_t<range_reference_t<R1>, range_reference_t<R2>>;
0513             using rvalue_reference_type =
0514                 common_reference_t<range_rvalue_reference_t<R1>,
0515                                    range_rvalue_reference_t<R2>>;
0516             using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
0517                                            single_pass_iterator_<iterator_t<R2>>>;
0518 
0519             set_union_cursor() = default;
0520             set_union_cursor(pred_ref_ pred, proj1_ref_ proj1, proj2_ref_ proj2,
0521                              iterator_t<R1> it1, sentinel_t<R1> end1, iterator_t<R2> it2,
0522                              sentinel_t<R2> end2)
0523               : pred_(std::move(pred))
0524               , proj1_(std::move(proj1))
0525               , proj2_(std::move(proj2))
0526               , it1_(std::move(it1))
0527               , end1_(std::move(end1))
0528               , it2_(std::move(it2))
0529               , end2_(std::move(end2))
0530             {
0531                 satisfy();
0532             }
0533             template(bool Other)(
0534                 requires IsConst AND CPP_NOT(Other))
0535                 set_union_cursor(set_union_cursor<Other, Rng1, Rng2, C, P1, P2> that)
0536               : pred_(std::move(that.pred_))
0537               , proj1_(std::move(that.proj1_))
0538               , proj2_(std::move(that.proj2_))
0539               , it1_(std::move(that.it1_))
0540               , end1_(std::move(that.end1_))
0541               , it2_(std::move(that.it2_))
0542               , end2_(std::move(that.end2_))
0543             {}
0544             reference_type read() const noexcept(noexcept(*it1_) && noexcept(*it2_))
0545             {
0546                 if(state == state_t::SECOND)
0547                     return *it2_;
0548                 else
0549                     return *it1_;
0550             }
0551             void next()
0552             {
0553                 if(state == state_t::FIRST)
0554                     ++it1_;
0555                 else
0556                     ++it2_;
0557                 satisfy();
0558             }
0559             CPP_member
0560             auto equal(set_union_cursor const & that) const //
0561                 -> CPP_ret(bool)(
0562                     requires forward_range<Rng1> && forward_range<Rng2>)
0563             {
0564                 // does not support comparing iterators from different ranges
0565                 return (it1_ == that.it1_) && (it2_ == that.it2_);
0566             }
0567             bool equal(default_sentinel_t) const
0568             {
0569                 return (it1_ == end1_) && (it2_ == end2_);
0570             }
0571             rvalue_reference_type move() const
0572                 noexcept(noexcept(iter_move(it1_)) && noexcept(iter_move(it2_)))
0573             {
0574                 if(state == state_t::SECOND)
0575                     return iter_move(it2_);
0576                 else
0577                     return iter_move(it1_);
0578             }
0579         };
0580 
0581         constexpr cardinality set_union_cardinality(cardinality c1, cardinality c2)
0582         {
0583             return (c1 == infinite) || (c2 == infinite)
0584                        ? infinite
0585                        : (c1 == unknown) || (c2 == unknown) ? unknown : finite;
0586         }
0587     } // namespace detail
0588     /// \endcond
0589 
0590     template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
0591     using set_union_view =
0592         detail::set_algorithm_view<Rng1, Rng2, C, P1, P2, detail::set_union_cursor,
0593                                    detail::set_union_cardinality(
0594                                        range_cardinality<Rng1>::value,
0595                                        range_cardinality<Rng2>::value)>;
0596 
0597     namespace views
0598     {
0599         struct set_union_base_fn
0600         {
0601         public:
0602             template(typename Rng1, typename Rng2, typename C = less,
0603                      typename P1 = identity, typename P2 = identity)(
0604                 requires //
0605                     viewable_range<Rng1> AND input_range<Rng1> AND
0606                     viewable_range<Rng2> AND input_range<Rng2> AND
0607                     common_with<range_value_t<Rng1>, range_value_t<Rng2>> AND
0608                     common_reference_with<range_reference_t<Rng1>,
0609                                           range_reference_t<Rng2>> AND
0610                     common_reference_with<range_rvalue_reference_t<Rng1>,
0611                                           range_rvalue_reference_t<Rng2>> AND
0612                     indirect_relation<C,
0613                                       projected<iterator_t<Rng1>, P1>,
0614                                       projected<iterator_t<Rng2>, P2>>)
0615             set_union_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2> //
0616             operator()(Rng1 && rng1,
0617                        Rng2 && rng2,
0618                        C pred = C{},
0619                        P1 proj1 = P1{},
0620                        P2 proj2 = P2{}) const
0621             {
0622                 return {all(static_cast<Rng1 &&>(rng1)),
0623                         all(static_cast<Rng2 &&>(rng2)),
0624                         std::move(pred),
0625                         std::move(proj1),
0626                         std::move(proj2)};
0627             }
0628         };
0629 
0630         struct set_union_fn : set_union_base_fn
0631         {
0632             using set_union_base_fn::operator();
0633 
0634             template(typename Rng2, typename C = less, typename P1 = identity,
0635                      typename P2 = identity)(
0636                 requires viewable_range<Rng2> AND input_range<Rng2> AND (!range<C>))
0637             constexpr auto operator()(Rng2 && rng2,
0638                                       C && pred = C{},
0639                                       P1 proj1 = P1{},
0640                                       P2 proj2 = P2{}) const
0641             {
0642                 return make_view_closure(bind_back(set_union_base_fn{},
0643                                                    all(rng2),
0644                                                    static_cast<C &&>(pred),
0645                                                    std::move(proj1),
0646                                                    std::move(proj2)));
0647             }
0648         };
0649 
0650         /// \relates set_union_fn
0651         RANGES_INLINE_VARIABLE(set_union_fn, set_union)
0652     } // namespace views
0653 
0654     /// \cond
0655     namespace detail
0656     {
0657         template<bool IsConst, typename Rng1, typename Rng2, typename C, typename P1,
0658                  typename P2>
0659         struct set_symmetric_difference_cursor
0660         {
0661         private:
0662             friend struct set_symmetric_difference_cursor<!IsConst, Rng1, Rng2, C, P1,
0663                                                           P2>;
0664             using pred_ref_ = semiregular_box_ref_or_val_t<C, IsConst>;
0665             using proj1_ref_ = semiregular_box_ref_or_val_t<P1, IsConst>;
0666             using proj2_ref_ = semiregular_box_ref_or_val_t<P2, IsConst>;
0667             pred_ref_ pred_;
0668             proj1_ref_ proj1_;
0669             proj2_ref_ proj2_;
0670 
0671             template<typename T>
0672             using constify_if = meta::const_if_c<IsConst, T>;
0673 
0674             using R1 = constify_if<Rng1>;
0675             using R2 = constify_if<Rng2>;
0676 
0677             iterator_t<R1> it1_;
0678             sentinel_t<R1> end1_;
0679 
0680             iterator_t<R2> it2_;
0681             sentinel_t<R2> end2_;
0682 
0683             enum class state_t
0684             {
0685                 FIRST,
0686                 SECOND,
0687                 ONLY_FIRST,
0688                 ONLY_SECOND
0689             } state;
0690 
0691             void satisfy()
0692             {
0693                 while(it1_ != end1_)
0694                 {
0695                     if(it2_ == end2_)
0696                     {
0697                         state = state_t::ONLY_FIRST;
0698                         return;
0699                     }
0700 
0701                     if(invoke(pred_, invoke(proj1_, *it1_), invoke(proj2_, *it2_)))
0702                     {
0703                         state = state_t::FIRST;
0704                         return;
0705                     }
0706                     else
0707                     {
0708                         if(invoke(pred_, invoke(proj2_, *it2_), invoke(proj1_, *it1_)))
0709                         {
0710                             state = state_t::SECOND;
0711                             return;
0712                         }
0713                         else
0714                         {
0715                             ++it1_;
0716                             ++it2_;
0717                         }
0718                     }
0719                 }
0720                 state = state_t::ONLY_SECOND;
0721             }
0722 
0723         public:
0724             using value_type = common_type_t<range_value_t<R1>, range_value_t<R2>>;
0725             using reference_type =
0726                 common_reference_t<range_reference_t<R1>, range_reference_t<R2>>;
0727             using rvalue_reference_type =
0728                 common_reference_t<range_rvalue_reference_t<R1>,
0729                                    range_rvalue_reference_t<R2>>;
0730             using single_pass = meta::or_c<single_pass_iterator_<iterator_t<R1>>,
0731                                            single_pass_iterator_<iterator_t<R2>>>;
0732 
0733             set_symmetric_difference_cursor() = default;
0734             set_symmetric_difference_cursor(pred_ref_ pred, proj1_ref_ proj1,
0735                                             proj2_ref_ proj2, iterator_t<R1> it1,
0736                                             sentinel_t<R1> end1, iterator_t<R2> it2,
0737                                             sentinel_t<R2> end2)
0738               : pred_(std::move(pred))
0739               , proj1_(std::move(proj1))
0740               , proj2_(std::move(proj2))
0741               , it1_(std::move(it1))
0742               , end1_(std::move(end1))
0743               , it2_(std::move(it2))
0744               , end2_(std::move(end2))
0745               , state()
0746             {
0747                 satisfy();
0748             }
0749             template(bool Other)(
0750                 requires IsConst && CPP_NOT(Other)) //
0751             set_symmetric_difference_cursor(
0752                     set_symmetric_difference_cursor<Other, Rng1, Rng2, C, P1, P2> that)
0753               : pred_(std::move(that.pred_))
0754               , proj1_(std::move(that.proj1_))
0755               , proj2_(std::move(that.proj2_))
0756               , it1_(std::move(that.it1_))
0757               , end1_(std::move(that.end1_))
0758               , it2_(std::move(that.it2_))
0759               , end2_(std::move(that.end2_))
0760               , state(that.state)
0761             {}
0762             reference_type read() const noexcept(noexcept(*it1_) && noexcept(*it2_))
0763             {
0764                 if(state == state_t::SECOND || state == state_t::ONLY_SECOND)
0765                     return *it2_;
0766                 else
0767                     return *it1_;
0768             }
0769             void next()
0770             {
0771                 switch(state)
0772                 {
0773                 case state_t::FIRST:
0774                     ++it1_;
0775                     satisfy();
0776                     break;
0777                 case state_t::ONLY_FIRST:
0778                     ++it1_;
0779                     break;
0780                 case state_t::SECOND:
0781                     ++it2_;
0782                     satisfy();
0783                     break;
0784                 case state_t::ONLY_SECOND:
0785                     ++it2_;
0786                     break;
0787                 }
0788             }
0789             CPP_member
0790             auto equal(set_symmetric_difference_cursor const & that) const
0791                 -> CPP_ret(bool)(
0792                     requires forward_range<R1> && forward_range<R2>)
0793             {
0794                 // does not support comparing iterators from different ranges:
0795                 return (it1_ == that.it1_) && (it2_ == that.it2_);
0796             }
0797             bool equal(default_sentinel_t) const
0798             {
0799                 return (it1_ == end1_) && (it2_ == end2_);
0800             }
0801             rvalue_reference_type move() const
0802                 noexcept(noexcept(iter_move(it1_)) && noexcept(iter_move(it2_)))
0803             {
0804                 if(state == state_t::SECOND || state == state_t::ONLY_SECOND)
0805                     return iter_move(it2_);
0806                 else
0807                     return iter_move(it1_);
0808             }
0809         };
0810 
0811         constexpr cardinality set_symmetric_difference_cardinality(cardinality c1,
0812                                                                    cardinality c2)
0813         {
0814             return (c1 == unknown) || (c2 == unknown)
0815                        ? unknown
0816                        : (c1 == infinite) != (c2 == infinite)
0817                              ? infinite
0818                              : (c1 == infinite) && (c2 == infinite) ? unknown : finite;
0819         }
0820 
0821     } // namespace detail
0822     /// \endcond
0823 
0824     template<typename Rng1, typename Rng2, typename C, typename P1, typename P2>
0825     using set_symmetric_difference_view = detail::set_algorithm_view<
0826         Rng1, Rng2, C, P1, P2, detail::set_symmetric_difference_cursor,
0827         detail::set_symmetric_difference_cardinality(range_cardinality<Rng1>::value,
0828                                                      range_cardinality<Rng2>::value)>;
0829 
0830     namespace views
0831     {
0832         struct set_symmetric_difference_base_fn
0833         {
0834             template(typename Rng1, typename Rng2, typename C = less,
0835                      typename P1 = identity, typename P2 = identity)(
0836                 requires //
0837                     viewable_range<Rng1> AND input_range<Rng1> AND
0838                     viewable_range<Rng2> AND input_range<Rng2> AND
0839                     common_with<range_value_t<Rng1>, range_value_t<Rng2>> AND
0840                     common_reference_with<range_reference_t<Rng1>,
0841                                           range_reference_t<Rng2>> AND
0842                     common_reference_with<range_rvalue_reference_t<Rng1>,
0843                                           range_rvalue_reference_t<Rng2>> AND
0844                     indirect_relation<C,
0845                                       projected<iterator_t<Rng1>, P1>,
0846                                       projected<iterator_t<Rng2>, P2>>)
0847             set_symmetric_difference_view<all_t<Rng1>, all_t<Rng2>, C, P1, P2>
0848             operator()(Rng1 && rng1,
0849                        Rng2 && rng2,
0850                        C pred = C{},
0851                        P1 proj1 = P1{},
0852                        P2 proj2 = P2{}) const
0853             {
0854                 return {all(static_cast<Rng1 &&>(rng1)),
0855                         all(static_cast<Rng2 &&>(rng2)),
0856                         std::move(pred),
0857                         std::move(proj1),
0858                         std::move(proj2)};
0859             }
0860         };
0861 
0862         struct set_symmetric_difference_fn : set_symmetric_difference_base_fn
0863         {
0864             using set_symmetric_difference_base_fn::operator();
0865 
0866             template(typename Rng2, typename C = less, typename P1 = identity,
0867                      typename P2 = identity)(
0868                 requires viewable_range<Rng2> AND input_range<Rng2> AND (!range<C>))
0869             constexpr auto operator()(Rng2 && rng2,
0870                                       C && pred = C{},
0871                                       P1 proj1 = P1{},
0872                                       P2 proj2 = P2{}) const
0873             {
0874                 return make_view_closure(bind_back(set_symmetric_difference_base_fn{},
0875                                                    all(rng2),
0876                                                    static_cast<C &&>(pred),
0877                                                    std::move(proj1),
0878                                                    std::move(proj2)));
0879             }
0880         };
0881 
0882         /// \relates set_symmetric_difference_fn
0883         RANGES_INLINE_VARIABLE(set_symmetric_difference_fn, set_symmetric_difference)
0884     } // namespace views
0885     /// @}
0886 } // namespace ranges
0887 
0888 #include <range/v3/detail/epilogue.hpp>
0889 
0890 #endif