Skip to content

Commit 8b510ca

Browse files
authored
Merge pull request scala#7805 from NthPortal/topic/sizeCompare-tweaks
Clean up length/size comparison methods
2 parents 502ad0f + f7c7527 commit 8b510ca

File tree

6 files changed

+83
-26
lines changed

6 files changed

+83
-26
lines changed

src/library/scala/collection/ArrayOps.scala

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,18 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal {
239239
*/
240240
def lastOption: Option[A] = if(isEmpty) None else Some(last)
241241

242+
/** Compares the size of this array to a test value.
243+
*
244+
* @param otherSize the test value that gets compared with the size.
245+
* @return A value `x` where
246+
* {{{
247+
* x < 0 if this.size < otherSize
248+
* x == 0 if this.size == otherSize
249+
* x > 0 if this.size > otherSize
250+
* }}}
251+
*/
252+
def sizeCompare(otherSize: Int): Int = Integer.compare(xs.length, otherSize)
253+
242254
/** Compares the length of this array to a test value.
243255
*
244256
* @param len the test value that gets compared with the length.
@@ -251,6 +263,40 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal {
251263
*/
252264
def lengthCompare(len: Int): Int = Integer.compare(xs.length, len)
253265

266+
/** Method mirroring [[SeqOps.sizeIs]] for consistency, except it returns an `Int`
267+
* because `size` is known and comparison is constant-time.
268+
*
269+
* These operations are equivalent to [[sizeCompare(Int) `sizeCompare(Int)`]], and
270+
* allow the following more readable usages:
271+
*
272+
* {{{
273+
* this.sizeIs < size // this.sizeCompare(size) < 0
274+
* this.sizeIs <= size // this.sizeCompare(size) <= 0
275+
* this.sizeIs == size // this.sizeCompare(size) == 0
276+
* this.sizeIs != size // this.sizeCompare(size) != 0
277+
* this.sizeIs >= size // this.sizeCompare(size) >= 0
278+
* this.sizeIs > size // this.sizeCompare(size) > 0
279+
* }}}
280+
*/
281+
def sizeIs: Int = xs.length
282+
283+
/** Method mirroring [[SeqOps.lengthIs]] for consistency, except it returns an `Int`
284+
* because `length` is known and comparison is constant-time.
285+
*
286+
* These operations are equivalent to [[lengthCompare(Int) `lengthCompare(Int)`]], and
287+
* allow the following more readable usages:
288+
*
289+
* {{{
290+
* this.lengthIs < len // this.lengthCompare(len) < 0
291+
* this.lengthIs <= len // this.lengthCompare(len) <= 0
292+
* this.lengthIs == len // this.lengthCompare(len) == 0
293+
* this.lengthIs != len // this.lengthCompare(len) != 0
294+
* this.lengthIs >= len // this.lengthCompare(len) >= 0
295+
* this.lengthIs > len // this.lengthCompare(len) > 0
296+
* }}}
297+
*/
298+
def lengthIs: Int = xs.length
299+
254300
/** Selects an interval of elements. The returned array is made up
255301
* of all elements `x` which satisfy the invariant:
256302
* {{{

src/library/scala/collection/IndexedSeq.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self =>
7272

7373
override def knownSize: Int = length
7474

75-
override final def sizeCompare(that: Iterable[_]): Int = {
75+
override final def lengthCompare(that: Iterable[_]): Int = {
7676
val res = that.sizeCompare(length)
7777
// can't just invert the result, because `-Int.MinValue == Int.MinValue`
7878
if (res == Int.MinValue) 1 else -res

src/library/scala/collection/Iterable.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,12 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable
258258
* x == 0 if this.size == otherSize
259259
* x > 0 if this.size > otherSize
260260
* }}}
261+
*
261262
* The method as implemented here does not call `size` directly; its running time
262-
* is `O(size min _size)` instead of `O(size)`. The method should be overwritten
263-
* if computing `size` is cheap.
263+
* is `O(size min otherSize)` instead of `O(size)`. The method should be overridden
264+
* if computing `size` is cheap and `knownSize` returns `-1`.
265+
*
266+
* @see [[sizeIs]]
264267
*/
265268
def sizeCompare(otherSize: Int): Int = {
266269
if (otherSize < 0) 1
@@ -299,14 +302,16 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable
299302
/** Compares the size of this $coll to the size of another `Iterable`.
300303
*
301304
* @param that the `Iterable` whose size is compared with this $coll's size.
305+
* @return A value `x` where
302306
* {{{
303307
* x < 0 if this.size < that.size
304308
* x == 0 if this.size == that.size
305309
* x > 0 if this.size > that.size
306310
* }}}
311+
*
307312
* The method as implemented here does not call `size` directly; its running time
308313
* is `O(this.size min that.size)` instead of `O(this.size + that.size)`.
309-
* The method should be overwritten if computing `size` is cheap.
314+
* The method should be overridden if computing `size` is cheap and `knownSize` returns `-1`.
310315
*/
311316
def sizeCompare(that: Iterable[_]): Int = {
312317
val thatKnownSize = that.knownSize

src/library/scala/collection/LinearSeq.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeq
7979
else loop(0, coll)
8080
}
8181

82-
override def sizeCompare(that: Iterable[_]): Int = {
82+
override def lengthCompare(that: Iterable[_]): Int = {
8383
val thatKnownSize = that.knownSize
8484

8585
if (thatKnownSize >= 0) this lengthCompare thatKnownSize

src/library/scala/collection/Seq.scala

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -774,11 +774,30 @@ trait SeqOps[+A, +CC[_], +C] extends Any
774774
* x > 0 if this.length > len
775775
* }}}
776776
* The method as implemented here does not call `length` directly; its running time
777-
* is `O(length min len)` instead of `O(length)`. The method should be overwritten
778-
* if computing `length` is cheap.
777+
* is `O(length min len)` instead of `O(length)`. The method should be overridden
778+
* if computing `length` is cheap and `knownSize` returns `-1`.
779+
*
780+
* @see [[lengthIs]]
779781
*/
780782
def lengthCompare(len: Int): Int = super.sizeCompare(len)
781783

784+
override final def sizeCompare(that: Iterable[_]): Int = lengthCompare(that)
785+
786+
/** Compares the length of this $coll to the size of another `Iterable`.
787+
*
788+
* @param that the `Iterable` whose size is compared with this $coll's length.
789+
* @return A value `x` where
790+
* {{{
791+
* x < 0 if this.length < that.size
792+
* x == 0 if this.length == that.size
793+
* x > 0 if this.length > that.size
794+
* }}}
795+
* The method as implemented here does not call `length` or `size` directly; its running time
796+
* is `O(this.length min that.size)` instead of `O(this.length + that.size)`.
797+
* The method should be overridden if computing `size` is cheap and `knownSize` returns `-1`.
798+
*/
799+
def lengthCompare(that: Iterable[_]): Int = super.sizeCompare(that)
800+
782801
/** Returns a value class containing operations for comparing the length of this $coll to a test value.
783802
*
784803
* These operations are implemented in terms of [[lengthCompare(Int) `lengthCompare(Int)`]], and
@@ -969,25 +988,6 @@ trait SeqOps[+A, +CC[_], +C] extends Any
969988
}
970989

971990
object SeqOps {
972-
/** Operations for comparing the length of a collection to a test value.
973-
*
974-
* These operations are implemented in terms of
975-
* [[scala.collection.SeqOps.lengthCompare(Int) `lengthCompare(Int)`]].
976-
*/
977-
final class LengthCompareOps private[SeqOps](val seq: SeqOps[_, AnyConstr, _]) extends AnyVal {
978-
/** Tests if the length of the collection is less than some value. */
979-
@inline def <(len: Int): Boolean = seq.lengthCompare(len) < 0
980-
/** Tests if the length of the collection is less than or equal to some value. */
981-
@inline def <=(len: Int): Boolean = seq.lengthCompare(len) <= 0
982-
/** Tests if the length of the collection is equal to some value. */
983-
@inline def ==(len: Int): Boolean = seq.lengthCompare(len) == 0
984-
/** Tests if the length of the collection is not equal to some value. */
985-
@inline def !=(len: Int): Boolean = seq.lengthCompare(len) != 0
986-
/** Tests if the length of the collection is greater than or equal to some value. */
987-
@inline def >=(len: Int): Boolean = seq.lengthCompare(len) >= 0
988-
/** Tests if the length of the collection is greater than some value. */
989-
@inline def >(len: Int): Boolean = seq.lengthCompare(len) > 0
990-
}
991991

992992
// KMP search utilities
993993

src/library/scala/collection/StringOps.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,14 @@ final class StringOps(private val s: String) extends AnyVal {
168168
/** Get the char at the specified index. */
169169
@`inline` def apply(i: Int): Char = s.charAt(i)
170170

171+
def sizeCompare(otherSize: Int): Int = Integer.compare(s.length, otherSize)
172+
171173
def lengthCompare(len: Int): Int = Integer.compare(s.length, len)
172174

175+
def sizeIs: Int = s.length
176+
177+
def lengthIs: Int = s.length
178+
173179
/** Builds a new collection by applying a function to all chars of this string.
174180
*
175181
* @param f the function to apply to each char.

0 commit comments

Comments
 (0)