Fix various boundary cases in IcuCollation::findLowerBound()
authorTim Starling <tstarling@wikimedia.org>
Thu, 11 Oct 2012 09:01:46 +0000 (20:01 +1100)
committerTim Starling <tstarling@wikimedia.org>
Wed, 17 Oct 2012 03:30:49 +0000 (14:30 +1100)
Fix the following edge cases which were previously broken:

* Zero-length input array
* Target value before the start
* Target value past the end

They didn't really matter for my original application, but Liangent
wants to use this function for something else.

Change-Id: Ia5f5ed4ab3cb6c463177a4812fd3ce96c6d37b33

includes/Collation.php

index 8554c2b..3cc7902 100644 (file)
@@ -335,8 +335,12 @@ class IcuCollation extends Collation {
         *     sorts before all items.
         */
        function findLowerBound( $valueCallback, $valueCount, $comparisonCallback, $target ) {
+               if ( $valueCount === 0 ) {
+                       return false;
+               }
+
                $min = 0;
-               $max = $valueCount - 1;
+               $max = $valueCount;
                do {
                        $mid = $min + ( ( $max - $min ) >> 1 );
                        $item = call_user_func( $valueCallback, $mid );
@@ -351,12 +355,15 @@ class IcuCollation extends Collation {
                        }
                } while ( $min < $max - 1 );
 
-               if ( $min == 0 && $max == 0 && $comparison > 0 ) {
-                       // Before the first item
-                       return false;
-               } else {
-                       return $min;
+               if ( $min == 0 ) {
+                       $item = call_user_func( $valueCallback, $min );
+                       $comparison = call_user_func( $comparisonCallback, $target, $item );
+                       if ( $comparison < 0 ) {
+                               // Before the first item
+                               return false;
+                       }
                }
+               return $min;
        }
 
        static function isCjk( $codepoint ) {