@@ -465,14 +465,108 @@ void medianOf(alias less, Iterator)
465
465
}
466
466
}
467
467
468
+ /+ +
469
+ Returns: `true` if a sorted array contains the value.
470
+
471
+ Params:
472
+ test = strict ordering symmetric predicate
473
+
474
+ For non-symmetric predicates please use a structure with two `opCall`s or an alias of two global functions,
475
+ that correponds to `(array[i], value)` and `(value, array[i])` cases.
468
476
477
+ See_also: $(LREF transitionIndex).
478
+ +/
479
+ template assumeSortedContains (alias test = " a < b" )
480
+ {
481
+ import mir.functional: naryFun;
482
+ static if (__traits(isSame, naryFun! test, test))
483
+ {
484
+ @optmath:
485
+ /+ +
486
+ Params:
487
+ slice = sorted one-dimensional slice or array.
488
+ v = value to test with. It is passed to second argument.
489
+ +/
490
+ bool assumeSortedContains (Iterator, SliceKind kind, V)
491
+ (auto ref Slice! (Iterator, 1 , kind) slice, auto ref scope const V v)
492
+ {
493
+ auto ti = transitionIndex! test(slice, v);
494
+ return ti < slice.length && ! test(v, slice[ti]);
495
+ }
469
496
497
+ // / ditto
498
+ bool assumeSortedContains (T, V)(scope T[] ar, auto ref scope const V v)
499
+ {
500
+ return .assumeSortedContains! test(ar.sliced, v);
501
+ }
502
+ }
503
+ else
504
+ alias assumeSortedContains = .assumeSortedContains! (naryFun! test);
505
+ }
506
+
507
+ /+ +
508
+ Returns: the smallest index of a sorted array such
509
+ that the index corresponds to the arrays element at the index according to the predicate
510
+ and array length if the array doesn't contain corresponding element.
511
+
512
+ Params:
513
+ test = strict ordering symmetric predicate.
514
+
515
+ For non-symmetric predicates please use a structure with two `opCall`s or an alias of two global functions,
516
+ that correponds to `(array[i], value)` and `(value, array[i])` cases.
517
+
518
+ See_also: $(LREF transitionIndex).
519
+ +/
520
+ template assumeSortedEqualIndex (alias test = " a < b" )
521
+ {
522
+ import mir.functional: naryFun;
523
+ static if (__traits(isSame, naryFun! test, test))
524
+ {
525
+ @optmath:
526
+ /+ +
527
+ Params:
528
+ slice = sorted one-dimensional slice or array.
529
+ v = value to test with. It is passed to second argument.
530
+ +/
531
+ size_t assumeSortedEqualIndex (Iterator, SliceKind kind, V)
532
+ (auto ref Slice! (Iterator, 1 , kind) slice, auto ref scope const V v)
533
+ {
534
+ auto ti = transitionIndex! test(slice, v);
535
+ return ti < slice.length && ! test(v, slice[ti]) ? ti : slice.length;
536
+ }
537
+
538
+ // / ditto
539
+ size_t assumeSortedEqualIndex (T, V)(scope T[] ar, auto ref scope const V v)
540
+ {
541
+ return .assumeSortedEqualIndex! test(ar.sliced, v);
542
+ }
543
+ }
544
+ else
545
+ alias assumeSortedEqualIndex = .assumeSortedEqualIndex! (naryFun! test);
546
+ }
547
+
548
+ // /
549
+ version (mir_test)
550
+ @safe pure unittest
551
+ {
552
+ // sorted: a < b
553
+ auto a = [0 , 1 , 2 , 3 , 4 , 6 ];
554
+
555
+ assert (a.assumeSortedEqualIndex(2 ) == 2 );
556
+ assert (a.assumeSortedEqualIndex(5 ) == a.length);
557
+
558
+ // <= non strict predicates doesn't work
559
+ assert (a.assumeSortedEqualIndex! " a <= b" (2 ) == a.length);
560
+ }
470
561
471
562
/+ +
472
563
Computes transition index using binary search.
473
564
It is low-level API for lower and upper bounds of a sorted array.
474
565
475
- See_also: $(SUBREF topology, flattened).
566
+ Params:
567
+ test = ordering predicate for (`(array[i], value)`) pairs.
568
+
569
+ See_also: $(SUBREF topology, assumeSortedEqualIndex).
476
570
+/
477
571
template transitionIndex (alias test = " a < b" )
478
572
{
@@ -517,6 +611,7 @@ template transitionIndex(alias test = "a < b")
517
611
}
518
612
519
613
// /
614
+ version (mir_test)
520
615
@safe pure unittest
521
616
{
522
617
// sorted: a < b
@@ -570,6 +665,7 @@ I[] makeIndex(I = size_t, alias less = "a < b", T)(scope T[] r)
570
665
}
571
666
572
667
// /
668
+ version (mir_test)
573
669
@system unittest
574
670
{
575
671
import mir.algorithm.iteration: all;
0 commit comments