@@ -2547,6 +2547,8 @@ rb_ary_sort(VALUE ary)
2547
2547
return ary ;
2548
2548
}
2549
2549
2550
+ static long ary_bsearch_index (VALUE ary );
2551
+
2550
2552
/*
2551
2553
* call-seq:
2552
2554
* ary.bsearch {|x| block } -> elem
@@ -2602,22 +2604,52 @@ rb_ary_sort(VALUE ary)
2602
2604
2603
2605
static VALUE
2604
2606
rb_ary_bsearch (VALUE ary )
2607
+ {
2608
+ long index_result = ary_bsearch_index (ary );
2609
+
2610
+ if (index_result < 0 ) return rb_ary_entry (ary , index_result );
2611
+ return INT2FIX (index_result );
2612
+ }
2613
+
2614
+ /*
2615
+ * call-seq:
2616
+ * ary.bsearch_index {|x| block } -> int or nil
2617
+ *
2618
+ * By using binary search, finds an index of a value from this array which
2619
+ * meets the given condition in O(log n) where n is the size of the array.
2620
+ *
2621
+ * It supports two modes, depending on the nature of the block and they are
2622
+ * exactly the same as in the case of #bsearch method with the only difference
2623
+ * being that this method returns the index of the element instead of the
2624
+ * element itself. For more details consult the documentation for #bsearch.
2625
+ */
2626
+
2627
+ static VALUE
2628
+ rb_ary_bsearch_index (VALUE ary )
2629
+ {
2630
+ long index_result = ary_bsearch_index (ary );
2631
+
2632
+ returns INT2FIX (index_result );
2633
+ }
2634
+
2635
+ static long
2636
+ ary_bsearch_index (VALUE ary )
2605
2637
{
2606
2638
long low = 0 , high = RARRAY_LEN (ary ), mid ;
2607
- int smaller = 0 ;
2608
- VALUE v , val , satisfied = Qnil ;
2639
+ int smaller = 0 , satisfied = 0 ;
2640
+ VALUE v , val ;
2609
2641
2610
2642
RETURN_ENUMERATOR (ary , 0 , 0 );
2611
2643
while (low < high ) {
2612
2644
mid = low + ((high - low ) / 2 );
2613
2645
val = rb_ary_entry (ary , mid );
2614
2646
v = rb_yield (val );
2615
2647
if (FIXNUM_P (v )) {
2616
- if (v == INT2FIX (0 )) return val ;
2648
+ if (v == INT2FIX (0 )) return mid ;
2617
2649
smaller = (SIGNED_VALUE )v < 0 ; /* Fixnum preserves its sign-bit */
2618
2650
}
2619
2651
else if (v == Qtrue ) {
2620
- satisfied = val ;
2652
+ satisfied = 1 ;
2621
2653
smaller = 1 ;
2622
2654
}
2623
2655
else if (v == Qfalse || v == Qnil ) {
@@ -2626,7 +2658,7 @@ rb_ary_bsearch(VALUE ary)
2626
2658
else if (rb_obj_is_kind_of (v , rb_cNumeric )) {
2627
2659
const VALUE zero = INT2FIX (0 );
2628
2660
switch (rb_cmpint (rb_funcallv (v , id_cmp , 1 , & zero ), v , zero )) {
2629
- case 0 : return val ;
2661
+ case 0 : return mid ;
2630
2662
case 1 : smaller = 1 ; break ;
2631
2663
case -1 : smaller = 0 ;
2632
2664
}
@@ -2643,7 +2675,8 @@ rb_ary_bsearch(VALUE ary)
2643
2675
low = mid + 1 ;
2644
2676
}
2645
2677
}
2646
- return satisfied ;
2678
+ if (!satisfied ) return -1 ;
2679
+ return low ;
2647
2680
}
2648
2681
2649
2682
@@ -5858,6 +5891,7 @@ Init_Array(void)
5858
5891
rb_define_method (rb_cArray , "drop" , rb_ary_drop , 1 );
5859
5892
rb_define_method (rb_cArray , "drop_while" , rb_ary_drop_while , 0 );
5860
5893
rb_define_method (rb_cArray , "bsearch" , rb_ary_bsearch , 0 );
5894
+ rb_define_method (rb_cArray , "bsearch_index" , rb_ary_bsearch_index , 0 );
5861
5895
rb_define_method (rb_cArray , "any?" , rb_ary_any_p , 0 );
5862
5896
5863
5897
id_cmp = rb_intern ("<=>" );
0 commit comments