Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #3308, #3350: better reporting of javalib stream & spliterator characteristics #3354

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions javalib/src/main/scala/java/util/ArrayList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,14 @@ class ArrayList[E] private (
* collections.
*/

// Flaw: This method makes no attempt to detect ConcurrentModification.

new Spliterators.AbstractSpliterator[E](
_size,
Spliterator.SIZED | Spliterator.SUBSIZED
Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED
) {
private var cursor = 0
private val limit = _size
private lazy val limit = _size // late binding

def tryAdvance(action: Consumer[_ >: E]): Boolean = {
if (cursor >= limit) false
Expand Down
19 changes: 11 additions & 8 deletions javalib/src/main/scala/java/util/stream/DoubleStreamImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -154,22 +154,25 @@ private[stream] class DoubleStreamImpl(
}

def unordered(): DoubleStream = {
/* JVM has an unenforced requirment that a stream and its spliterator
* (can you say Harlan Ellison?) should have the same characteristics.
*/

val masked = _spliter.characteristics() & Spliterator.ORDERED

if (masked == Spliterator.ORDERED) this
if (masked != Spliterator.ORDERED) this // already unordered.
else {
commenceOperation()

// Clear ORDERED
val unordered = _spliter.characteristics() & ~(Spliterator.ORDERED)
val bitsToClear =
(Spliterator.CONCURRENT
| Spliterator.IMMUTABLE
| Spliterator.NONNULL
| Spliterator.ORDERED
| Spliterator.SIZED
| Spliterator.SUBSIZED)

val purifiedBits = _characteristics & ~(bitsToClear)

val spl = new Spliterators.AbstractDoubleSpliterator(
_spliter.estimateSize(),
unordered
purifiedBits
) {
def tryAdvance(action: DoubleConsumer): Boolean =
_spliter.tryAdvance((e: scala.Double) => action.accept(e))
Expand Down
19 changes: 11 additions & 8 deletions javalib/src/main/scala/java/util/stream/ObjectStreamImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,22 +149,25 @@ private[stream] class ObjectStreamImpl[T](
}

def unordered(): Stream[T] = {
/* JVM has an unenforced requirment that a stream and its spliterator
* (can you say Harlan Ellison?) should have the same characteristics.
*/

val masked = _spliter.characteristics() & Spliterator.ORDERED

if (masked == Spliterator.ORDERED) this
if (masked != Spliterator.ORDERED) this // already unordered.
else {
commenceOperation()

// Clear ORDERED
val unordered = _spliter.characteristics() & ~(Spliterator.ORDERED)
val bitsToClear =
(Spliterator.CONCURRENT
| Spliterator.IMMUTABLE
| Spliterator.NONNULL
| Spliterator.ORDERED
| Spliterator.SIZED
| Spliterator.SUBSIZED)

val purifiedBits = _characteristics & ~(bitsToClear)

val spl = new Spliterators.AbstractSpliterator[T](
_spliter.estimateSize(),
unordered
purifiedBits
) {
def tryAdvance(action: Consumer[_ >: T]): Boolean =
_spliter.tryAdvance((e) => action.accept(e))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,54 @@ class DoubleStreamTest {

final val epsilon = 0.00001 // tolerance for Floating point comparisons.

// Methods specified in interface BaseStream ----------------------------

@Test def streamUnorderedOnUnorderedStream(): Unit = {
val dataSet = new ju.HashSet[Double]()
dataSet.add(0.1)
dataSet.add(1.1)
dataSet.add(-1.1)
dataSet.add(2.2)
dataSet.add(-2.2)

val s0 = dataSet.stream()
val s0Spliter = s0.spliterator()
assertFalse(
"Unexpected ORDERED stream from hashset",
s0Spliter.hasCharacteristics(Spliterator.ORDERED)
)

val su = dataSet.stream().unordered()
val suSpliter = su.spliterator()

assertFalse(
"Unexpected ORDERED stream",
suSpliter.hasCharacteristics(Spliterator.ORDERED)
)
}

@Test def streamUnorderedOnOrderedStream(): Unit = {
val s = DoubleStream.of(0.1, 1.1, -1.1, 2.2, -2.2)
val sSpliter = s.spliterator()

assertTrue(
"Expected ORDERED on stream from array",
sSpliter.hasCharacteristics(Spliterator.ORDERED)
)

// s was ordered, 'so' should be same same. Avoid "already used" exception
val so = DoubleStream.of(0.1, 1.1, -1.1, 2.2, -2.2)
val su = so.unordered()
val suSpliter = su.spliterator()

assertFalse(
"ORDERED stream after unordered()",
suSpliter.hasCharacteristics(Spliterator.ORDERED)
)
}

// Methods specified in interface Stream --------------------------------

@Test def doubleStreamBuilderCanBuildAnEmptyStream(): Unit = {
val s = DoubleStream.builder().build()
val it = s.iterator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,53 @@ class StreamTest {
al.stream()
}

// Methods specified in interface BaseStream ----------------------------

@Test def streamUnorderedOnUnorderedStream(): Unit = {
val dataSet = new ju.HashSet[String]()
dataSet.add("T")
dataSet.add("S")
dataSet.add("X")
dataSet.add("Y")

val s0 = dataSet.stream()
val s0Spliter = s0.spliterator()
assertFalse(
"Unexpected ORDERED stream from hashset",
s0Spliter.hasCharacteristics(Spliterator.ORDERED)
)

val su = dataSet.stream().unordered()
val suSpliter = su.spliterator()

assertFalse(
"Unexpected ORDERED stream",
suSpliter.hasCharacteristics(Spliterator.ORDERED)
)
}

@Test def streamUnorderedOnOrderedStream(): Unit = {
val s = Stream.of("V", "W", "X", "Y", "Z")
val sSpliter = s.spliterator()

assertTrue(
"Expected ORDERED on stream from array",
sSpliter.hasCharacteristics(Spliterator.ORDERED)
)

// s was ordered, 'so' should be same same. Avoid "already used" exception
val so = Stream.of("V", "W", "X", "Y", "Z")
val su = so.unordered()
val suSpliter = su.spliterator()

assertFalse(
"ORDERED stream after unordered()",
suSpliter.hasCharacteristics(Spliterator.ORDERED)
)
}

// Methods specified in interface Stream --------------------------------

@Test def streamBuilderCanBuildAnEmptyStream(): Unit = {
val s = Stream.builder().build()
val it = s.iterator()
Expand Down