Skip to content

Commit 0702342

Browse files
committed
SI-9605 Searching does not use binary search for Array
Binary search should be used for every `IndexedSeqLike` instance and not only for `IndexedSeq`. According the Scaladoc, it is `IndexedSeqLike` that guarantees "constant-time or near constant-time element access and length computation".
1 parent 6792b57 commit 0702342

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

src/library/scala/collection/Searching.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ object Searching {
3636

3737
class SearchImpl[A, Repr](val coll: SeqLike[A, Repr]) {
3838
/** Search the sorted sequence for a specific element. If the sequence is an
39-
* `IndexedSeq`, a binary search is used. Otherwise, a linear search is used.
39+
* `IndexedSeqLike`, a binary search is used. Otherwise, a linear search is used.
4040
*
4141
* The sequence should be sorted with the same `Ordering` before calling; otherwise,
4242
* the results are undefined.
4343
*
44-
* @see [[scala.collection.IndexedSeq]]
44+
* @see [[scala.collection.IndexedSeqLike]]
4545
* @see [[scala.math.Ordering]]
4646
* @see [[scala.collection.SeqLike]], method `sorted`
4747
*
@@ -54,18 +54,18 @@ object Searching {
5454
*/
5555
final def search[B >: A](elem: B)(implicit ord: Ordering[B]): SearchResult =
5656
coll match {
57-
case _: IndexedSeq[A] => binarySearch(elem, 0, coll.length)(ord)
57+
case _: IndexedSeqLike[A, Repr] => binarySearch(elem, 0, coll.length)(ord)
5858
case _ => linearSearch(coll.view, elem, 0)(ord)
5959
}
6060

6161
/** Search within an interval in the sorted sequence for a specific element. If the
62-
* sequence is an IndexedSeq, a binary search is used. Otherwise, a linear search
62+
* sequence is an `IndexedSeqLike`, a binary search is used. Otherwise, a linear search
6363
* is used.
6464
*
6565
* The sequence should be sorted with the same `Ordering` before calling; otherwise,
6666
* the results are undefined.
6767
*
68-
* @see [[scala.collection.IndexedSeq]]
68+
* @see [[scala.collection.IndexedSeqLike]]
6969
* @see [[scala.math.Ordering]]
7070
* @see [[scala.collection.SeqLike]], method `sorted`
7171
*
@@ -81,7 +81,7 @@ object Searching {
8181
final def search[B >: A](elem: B, from: Int, to: Int)
8282
(implicit ord: Ordering[B]): SearchResult =
8383
coll match {
84-
case _: IndexedSeq[A] => binarySearch(elem, from, to)(ord)
84+
case _: IndexedSeqLike[A, Repr] => binarySearch(elem, from, to)(ord)
8585
case _ => linearSearch(coll.view(from, to), elem, from)(ord)
8686
}
8787

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package scala.collection
2+
3+
import org.junit.runner.RunWith
4+
import org.junit.runners.JUnit4
5+
import org.junit.Assert._
6+
import org.junit.Test
7+
import scala.collection.Searching._
8+
9+
@RunWith(classOf[JUnit4])
10+
class SearchingTest {
11+
12+
@Test
13+
def doesLinearSearchOnLinearSeqs() {
14+
15+
class TestSeq[A](list: List[A]) extends SeqLike[A, TestSeq[A]] {
16+
var elementsAccessed = Set.empty[Int]
17+
18+
protected[this] def newBuilder = ??? // not needed for this test
19+
def seq = list
20+
def iterator = list.iterator
21+
def length = list.length
22+
def apply(idx: Int) = { elementsAccessed += idx; list(idx) }
23+
}
24+
25+
val coll = new TestSeq((0 to 6).toList)
26+
27+
assertEquals(Found(5), coll.search(5))
28+
assertEquals(Set.empty, coll.elementsAccessed) // linear search should not access elements via apply()
29+
}
30+
31+
@Test
32+
def doesBinarySearchOnIndexedSeqs() {
33+
34+
class TestIndexedSeq[A](vec: Vector[A]) extends IndexedSeqLike[A, TestIndexedSeq[A]] {
35+
var elementsAccessed = Set.empty[Int]
36+
37+
protected[this] def newBuilder = ??? // not needed for this test
38+
def seq = vec
39+
def length = vec.length
40+
def apply(idx: Int) = { elementsAccessed += idx; vec(idx) }
41+
}
42+
43+
val coll = new TestIndexedSeq((0 to 6).toVector)
44+
45+
assertEquals(Found(5), coll.search(5))
46+
assertEquals(Set(3, 5), coll.elementsAccessed)
47+
}
48+
}

0 commit comments

Comments
 (0)