File indexing completed on 2024-11-15 09:54:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifndef RANGES_V3_ALGORITHM_PERMUTATION_HPP
0022 #define RANGES_V3_ALGORITHM_PERMUTATION_HPP
0023
0024 #include <meta/meta.hpp>
0025
0026 #include <range/v3/range_fwd.hpp>
0027
0028 #include <range/v3/algorithm/mismatch.hpp>
0029 #include <range/v3/algorithm/reverse.hpp>
0030 #include <range/v3/functional/comparisons.hpp>
0031 #include <range/v3/functional/identity.hpp>
0032 #include <range/v3/functional/invoke.hpp>
0033 #include <range/v3/iterator/concepts.hpp>
0034 #include <range/v3/iterator/operations.hpp>
0035 #include <range/v3/iterator/traits.hpp>
0036 #include <range/v3/range/access.hpp>
0037 #include <range/v3/range/concepts.hpp>
0038 #include <range/v3/range/traits.hpp>
0039 #include <range/v3/utility/static_const.hpp>
0040 #include <range/v3/utility/swap.hpp>
0041
0042 #include <range/v3/detail/prologue.hpp>
0043
0044 namespace ranges
0045 {
0046
0047
0048
0049
0050 namespace detail
0051 {
0052 template<typename I1, typename S1, typename I2, typename S2, typename C,
0053 typename P1, typename P2>
0054 constexpr bool is_permutation_impl(I1 begin1,
0055 S1 end1,
0056 I2 begin2,
0057 S2 end2,
0058 C pred,
0059 P1 proj1,
0060 P2 proj2)
0061 {
0062
0063 const auto mismatch =
0064 ranges::mismatch(begin1, end1, begin2, end2, pred, proj1, proj2);
0065 begin1 = mismatch.in1;
0066 begin2 = mismatch.in2;
0067 if(begin1 == end1 || begin2 == end2)
0068 {
0069 return begin1 == end1 && begin2 == end2;
0070 }
0071
0072 auto l1 = distance(begin1, end1);
0073 auto l2 = distance(begin2, end2);
0074 if(l1 != l2)
0075 return false;
0076
0077
0078
0079 for(I1 i = begin1; i != end1; ++i)
0080 {
0081
0082 const auto should_continue = [&] {
0083 for(I1 j = begin1; j != i; ++j)
0084 if(invoke(pred, invoke(proj1, *j), invoke(proj1, *i)))
0085 return true;
0086 return false;
0087 }();
0088 if(should_continue)
0089 {
0090 continue;
0091 }
0092
0093 iter_difference_t<I2> c2 = 0;
0094 for(I2 j = begin2; j != end2; ++j)
0095 if(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))
0096 ++c2;
0097 if(c2 == 0)
0098 return false;
0099
0100 iter_difference_t<I1> c1 = 1;
0101 for(I1 j = next(i); j != end1; ++j)
0102 if(invoke(pred, invoke(proj1, *i), invoke(proj1, *j)))
0103 ++c1;
0104 if(c1 != c2)
0105 return false;
0106 }
0107 return true;
0108 }
0109 }
0110
0111
0112 RANGES_FUNC_BEGIN(is_permutation)
0113
0114
0115 template(typename I1,
0116 typename S1,
0117 typename I2,
0118 typename C = equal_to,
0119 typename P1 = identity,
0120 typename P2 = identity)(
0121 requires forward_iterator<I1> AND sentinel_for<S1, I1> AND
0122 forward_iterator<I2> AND indirectly_comparable<I1, I2, C, P1, P2>)
0123 RANGES_DEPRECATED(
0124 "Use the variant of ranges::is_permutation that takes an upper bound "
0125 "for both sequences")
0126 bool RANGES_FUNC(is_permutation)(I1 begin1,
0127 S1 end1,
0128 I2 begin2,
0129 C pred = C{},
0130 P1 proj1 = P1{},
0131 P2 proj2 = P2{})
0132 {
0133
0134 for(; begin1 != end1; ++begin1, ++begin2)
0135 if(!invoke(pred, invoke(proj1, *begin1), invoke(proj2, *begin2)))
0136 goto not_done;
0137 return true;
0138 not_done:
0139
0140 auto l1 = distance(begin1, end1);
0141 if(l1 == 1)
0142 return false;
0143 I2 end2 = next(begin2, l1);
0144
0145
0146 for(I1 i = begin1; i != end1; ++i)
0147 {
0148
0149 for(I1 j = begin1; j != i; ++j)
0150 if(invoke(pred, invoke(proj1, *j), invoke(proj1, *i)))
0151 goto next_iter;
0152 {
0153
0154 iter_difference_t<I2> c2 = 0;
0155 for(I2 j = begin2; j != end2; ++j)
0156 if(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))
0157 ++c2;
0158 if(c2 == 0)
0159 return false;
0160
0161 iter_difference_t<I1> c1 = 1;
0162 for(I1 j = next(i); j != end1; ++j)
0163 if(invoke(pred, invoke(proj1, *i), invoke(proj1, *j)))
0164 ++c1;
0165 if(c1 != c2)
0166 return false;
0167 }
0168 next_iter:;
0169 }
0170 return true;
0171 }
0172
0173
0174 template(typename I1,
0175 typename S1,
0176 typename I2,
0177 typename S2,
0178 typename C = equal_to,
0179 typename P1 = identity,
0180 typename P2 = identity)(
0181 requires forward_iterator<I1> AND sentinel_for<S1, I1> AND
0182 forward_iterator<I2> AND sentinel_for<S2, I2> AND
0183 indirectly_comparable<I1, I2, C, P1, P2>)
0184 constexpr bool RANGES_FUNC(is_permutation)(I1 begin1,
0185 S1 end1,
0186 I2 begin2,
0187 S2 end2,
0188 C pred = C{},
0189 P1 proj1 = P1{},
0190 P2 proj2 = P2{})
0191 {
0192 if(RANGES_CONSTEXPR_IF(sized_sentinel_for<S1, I1> &&
0193 sized_sentinel_for<S2, I2>))
0194 {
0195 RANGES_DIAGNOSTIC_PUSH
0196 RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
0197 return distance(begin1, end1) == distance(begin2, end2) &&
0198 (*this)(std::move(begin1),
0199 std::move(end1),
0200 std::move(begin2),
0201 std::move(pred),
0202 std::move(proj1),
0203 std::move(proj2));
0204 RANGES_DIAGNOSTIC_POP
0205 }
0206 return detail::is_permutation_impl(std::move(begin1),
0207 std::move(end1),
0208 std::move(begin2),
0209 std::move(end2),
0210 std::move(pred),
0211 std::move(proj1),
0212 std::move(proj2));
0213 }
0214
0215
0216 template(typename Rng1,
0217 typename I2Ref,
0218 typename C = equal_to,
0219 typename P1 = identity,
0220 typename P2 = identity)(
0221 requires forward_range<Rng1> AND forward_iterator<uncvref_t<I2Ref>> AND
0222 indirectly_comparable<iterator_t<Rng1>, uncvref_t<I2Ref>, C, P1, P2>)
0223 RANGES_DEPRECATED(
0224 "Use the variant of ranges::is_permutation that takes an upper bound "
0225 "for both sequences")
0226 bool RANGES_FUNC(is_permutation)(Rng1 && rng1,
0227 I2Ref && begin2,
0228 C pred = C{},
0229 P1 proj1 = P1{},
0230 P2 proj2 = P2{})
0231 {
0232 RANGES_DIAGNOSTIC_PUSH
0233 RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
0234 return (*this)(begin(rng1),
0235 end(rng1),
0236 (I2Ref &&) begin2,
0237 std::move(pred),
0238 std::move(proj1),
0239 std::move(proj2));
0240 RANGES_DIAGNOSTIC_POP
0241 }
0242
0243
0244 template(typename Rng1,
0245 typename Rng2,
0246 typename C = equal_to,
0247 typename P1 = identity,
0248 typename P2 = identity)(
0249 requires forward_range<Rng1> AND forward_range<Rng2> AND
0250 indirectly_comparable<iterator_t<Rng1>, iterator_t<Rng2>, C, P1, P2>)
0251 constexpr bool RANGES_FUNC(is_permutation)(
0252 Rng1 && rng1, Rng2 && rng2, C pred = C{}, P1 proj1 = P1{}, P2 proj2 = P2{})
0253 {
0254 if(RANGES_CONSTEXPR_IF(sized_range<Rng1> && sized_range<Rng2>))
0255 {
0256 RANGES_DIAGNOSTIC_PUSH
0257 RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
0258 return distance(rng1) == distance(rng2) && (*this)(begin(rng1),
0259 end(rng1),
0260 begin(rng2),
0261 std::move(pred),
0262 std::move(proj1),
0263 std::move(proj2));
0264 RANGES_DIAGNOSTIC_POP
0265 }
0266 return detail::is_permutation_impl(begin(rng1),
0267 end(rng1),
0268 begin(rng2),
0269 end(rng2),
0270 std::move(pred),
0271 std::move(proj1),
0272 std::move(proj2));
0273 }
0274
0275 RANGES_FUNC_END(is_permutation)
0276
0277 RANGES_FUNC_BEGIN(next_permutation)
0278
0279
0280 template(typename I, typename S, typename C = less, typename P = identity)(
0281 requires bidirectional_iterator<I> AND sentinel_for<S, I> AND
0282 sortable<I, C, P>)
0283 constexpr bool RANGES_FUNC(next_permutation)(I first, S end_, C pred = C{}, P proj = P{})
0284 {
0285 if(first == end_)
0286 return false;
0287 I last = ranges::next(first, end_), i = last;
0288 if(first == --i)
0289 return false;
0290 while(true)
0291 {
0292 I ip1 = i;
0293 if(invoke(pred, invoke(proj, *--i), invoke(proj, *ip1)))
0294 {
0295 I j = last;
0296 while(!invoke(pred, invoke(proj, *i), invoke(proj, *--j)))
0297 ;
0298 ranges::iter_swap(i, j);
0299 ranges::reverse(ip1, last);
0300 return true;
0301 }
0302 if(i == first)
0303 {
0304 ranges::reverse(first, last);
0305 return false;
0306 }
0307 }
0308 }
0309
0310
0311 template(typename Rng, typename C = less, typename P = identity)(
0312 requires bidirectional_range<Rng> AND sortable<iterator_t<Rng>, C, P>)
0313 constexpr bool RANGES_FUNC(next_permutation)(Rng && rng, C pred = C{}, P proj = P{})
0314 {
0315 return (*this)(begin(rng), end(rng), std::move(pred), std::move(proj));
0316 }
0317
0318 RANGES_FUNC_END(next_permutation)
0319
0320 RANGES_FUNC_BEGIN(prev_permutation)
0321
0322
0323 template(typename I, typename S, typename C = less, typename P = identity)(
0324 requires bidirectional_iterator<I> AND sentinel_for<S, I> AND
0325 sortable<I, C, P>)
0326 constexpr bool RANGES_FUNC(prev_permutation)(I first, S end_, C pred = C{}, P proj = P{})
0327 {
0328 if(first == end_)
0329 return false;
0330 I last = ranges::next(first, end_), i = last;
0331 if(first == --i)
0332 return false;
0333 while(true)
0334 {
0335 I ip1 = i;
0336 if(invoke(pred, invoke(proj, *ip1), invoke(proj, *--i)))
0337 {
0338 I j = last;
0339 while(!invoke(pred, invoke(proj, *--j), invoke(proj, *i)))
0340 ;
0341 ranges::iter_swap(i, j);
0342 ranges::reverse(ip1, last);
0343 return true;
0344 }
0345 if(i == first)
0346 {
0347 ranges::reverse(first, last);
0348 return false;
0349 }
0350 }
0351 }
0352
0353
0354 template(typename Rng, typename C = less, typename P = identity)(
0355 requires bidirectional_range<Rng> AND sortable<iterator_t<Rng>, C, P>)
0356 constexpr bool RANGES_FUNC(prev_permutation)(Rng && rng, C pred = C{}, P proj = P{})
0357 {
0358 return (*this)(begin(rng), end(rng), std::move(pred), std::move(proj));
0359 }
0360
0361 RANGES_FUNC_END(prev_permutation)
0362
0363 namespace cpp20
0364 {
0365 using ranges::is_permutation;
0366 using ranges::next_permutation;
0367 using ranges::prev_permutation;
0368 }
0369
0370 }
0371
0372 #include <range/v3/detail/epilogue.hpp>
0373
0374 #endif