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

Add partial implementation of java.util.EnumSet #3397

Merged
merged 1 commit into from
Jul 19, 2023
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
120 changes: 103 additions & 17 deletions javalib/src/main/scala/java/util/EnumSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,113 @@ package java.util

import java.lang.Enum

final class EnumSet[E <: Enum[E]] private (values: Array[E])
final class EnumSet[E <: Enum[E]] private (values: Set[E])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could still be an array where the index corresponds to ordinal, and the max ordinal + 1 is the size of the array? (never shrink, only grow by powers of 2?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, it could have been, but it's not going to be frequently used, and that way we get the Set ops for free. At some point it could be rewriten to be more optimal, but for current usages its good enough, especially since we cannot support the relection based semantics to populate it with all values

extends AbstractSet[E]
with Cloneable
with Serializable {
def iterator(): Iterator[E] =
new Iterator[E] {
private var i = 0
override def hasNext(): Boolean = i < values.length
override def next(): E = {
val r = values(i)
i += 1
r
}
override def remove(): Unit = throw new UnsupportedOperationException()
}
def size(): Int = values.length
// Unsupported requires reflection
// def this(elementType: Class[E], universe: Array[Enum[E]]) = ???

override def iterator(): Iterator[E] = values.iterator()
override def size(): Int = values.size()
override def isEmpty(): Boolean = values.isEmpty()
override def contains(o: Any): Boolean = values.contains(o)
override def toArray(): Array[AnyRef] = values.toArray()
override def toArray[T <: AnyRef](a: Array[T]): Array[T] = values.toArray(a)
override def add(e: E): Boolean = values.add(e)
override def remove(o: Any): Boolean = values.remove(o)
override def containsAll(c: Collection[_]): Boolean = values.containsAll(c)
override def addAll(c: Collection[_ <: E]): Boolean = values.addAll(c)
override def removeAll(c: Collection[_]): Boolean = values.removeAll(c)
override def retainAll(c: Collection[_]): Boolean = values.retainAll(c)
override def clear(): Unit = values.clear()
override def equals(o: Any): Boolean = values.equals(o)
override def hashCode(): Int = values.hashCode()

override protected[util] def clone(): EnumSet[E] =
super.clone().asInstanceOf[EnumSet[E]]
}

object EnumSet {
def noneOf[E <: Enum[E]: scala.reflect.ClassTag](
elementType: Class[E]
): EnumSet[E] =
new EnumSet[E](Array.empty[E])
def noneOf[E <: Enum[E]](elementType: Class[E]): EnumSet[E] =
new EnumSet[E](new HashSet[E]())

// Unsupported, requires reflection
// def allOf[E <: Enum[E]](elementType: Class[E]): EnumSet[E] = ???

def copyOf[E <: Enum[E]](s: EnumSet[E]): EnumSet[E] =
s.clone().asInstanceOf[EnumSet[E]]

def copyOf[E <: Enum[E]](c: Collection[E]): EnumSet[E] = c match {
case c: EnumSet[E] => copyOf(c)
case c =>
if (c.isEmpty()) throw new IllegalArgumentException("Collection is empty")
val i = c.iterator()
val set = EnumSet.of(i.next())
while (i.hasNext()) {
set.add(i.next())
}
set
}

// Unsupported, requires reflection
// def complementOf[E <: Enum[E]](s: EnumSet[E]): EnumSet[E] = {
// val result = copyOf(s)
// result.complement()
// result
// }

def of[E <: Enum[E]](e: E): EnumSet[E] = {
val s = emptySetOf(e)
s.add(e)
s
}

def of[E <: Enum[E]](e1: E, e2: E): EnumSet[E] = {
val s = emptySetOf(e1)
s.add(e1)
s.add(e2)
s
}

def of[E <: Enum[E]](e1: E, e2: E, e3: E): EnumSet[E] = {
val s = emptySetOf(e1)
s.add(e1)
s.add(e2)
s.add(e3)
s
}

def of[E <: Enum[E]](e1: E, e2: E, e3: E, e4: E): EnumSet[E] = {
val s = emptySetOf(e1)
s.add(e1)
s.add(e2)
s.add(e3)
s.add(e4)
s
}

def of[E <: Enum[E]](e1: E, e2: E, e3: E, e4: E, e5: E): EnumSet[E] = {
val s = emptySetOf(e1)
s.add(e1)
s.add(e2)
s.add(e3)
s.add(e4)
s.add(e5)
s
}

def of[E <: Enum[E]](first: E, rest: Array[E]): EnumSet[E] = {
val s = emptySetOf(first)
s.add(first)
rest.foreach(s.add)
s
}

// Unsupported, requires reflection
// def range[E <: Enum[E]](from: E, to: E): EnumSet[E] = ???

@inline
private def emptySetOf[E <: Enum[E]](e: E): EnumSet[E] =
new EnumSet[E](new HashSet[E]())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package org.scalanative.testsuite.javalib.util

import java.lang._
import java.util.EnumSet

import org.junit.Test
import org.junit.Assert._

// Tested only in Scala 3 becouse we cannot create Java enums in Scala 2

object EnumSetTest {
enum Value extends java.lang.Enum[Value]:
case A, B, C, D, E, F
}

class EnumSetTest {
import EnumSetTest.Value

@Test def noneOf(): Unit = {
val s = EnumSet.noneOf(classOf[Value])
assertTrue(s.isEmpty())
assertEquals(0, s.size())
assertFalse(s.iterator().hasNext())
}

@Test def of1(): Unit = {
val s = EnumSet.of(Value.A)
assertFalse(s.isEmpty())
assertEquals(1, s.size())
val it = s.iterator()
assertTrue(it.hasNext())
assertEquals(Value.A, it.next())
}

@Test def of2(): Unit = {
val s = EnumSet.of(Value.A, Value.B)
assertFalse(s.isEmpty())
assertEquals(2, s.size())
assertTrue(s.contains(Value.A))
assertTrue(s.contains(Value.B))
}

@Test def of3(): Unit = {
val s = EnumSet.of(Value.A, Value.B, Value.C)
assertFalse(s.isEmpty())
assertEquals(3, s.size())
assertTrue(s.contains(Value.A))
assertTrue(s.contains(Value.B))
assertTrue(s.contains(Value.C))
}

@Test def of4(): Unit = {
val s = EnumSet.of(Value.A, Value.B, Value.C, Value.D)
assertFalse(s.isEmpty())
assertEquals(4, s.size())
assertTrue(s.contains(Value.A))
assertTrue(s.contains(Value.B))
assertTrue(s.contains(Value.C))
assertTrue(s.contains(Value.D))
}

@Test def of5(): Unit = {
val s = EnumSet.of(Value.A, Value.B, Value.C, Value.D, Value.E)
assertFalse(s.isEmpty())
assertEquals(5, s.size())
assertTrue(s.contains(Value.A))
assertTrue(s.contains(Value.B))
assertTrue(s.contains(Value.C))
assertTrue(s.contains(Value.D))
assertTrue(s.contains(Value.E))
}

@Test def ofVarArg(): Unit = {
val s = EnumSet.of(Value.A, Value.B, Value.C, Value.D, Value.E, Value.F)
assertFalse(s.isEmpty())
assertEquals(6, s.size())
assertTrue(s.contains(Value.A))
assertTrue(s.contains(Value.B))
assertTrue(s.contains(Value.C))
assertTrue(s.contains(Value.D))
assertTrue(s.contains(Value.E))
assertTrue(s.contains(Value.F))
}

@Test def ofVarArg2(): Unit = {
val s =
EnumSet.of(Value.A, Seq(Value.B, Value.C, Value.D, Value.E, Value.F): _*)
assertFalse(s.isEmpty())
assertEquals(6, s.size())
assertTrue(s.contains(Value.A))
assertTrue(s.contains(Value.B))
assertTrue(s.contains(Value.C))
assertTrue(s.contains(Value.D))
assertTrue(s.contains(Value.E))
assertTrue(s.contains(Value.F))
}

@Test def copyOf(): Unit = {
val s = EnumSet.of(Value.A, Value.B, Value.C)
val c = EnumSet.copyOf(s)
assertNotSame(s, c)
assertEquals(s, c)
}

@Test def copyOfCollection(): Unit = {
val c: java.util.Collection[Value] = new java.util.LinkedList[Value]()
c.add(Value.A)
c.add(Value.B)
c.add(Value.C)
val s = EnumSet.copyOf(c)

assertNotSame(s, c)
assertEquals(3, s.size())
assertTrue(s.contains(Value.A))
assertTrue(s.contains(Value.B))
assertTrue(s.contains(Value.C))
}

@Test def uniqness(): Unit = {
val s = EnumSet.of(Value.A, Value.A, Value.B, Value.C, Value.B)
assertEquals(3, s.size())
assertTrue(s.contains(Value.A))
assertTrue(s.contains(Value.B))
assertTrue(s.contains(Value.C))
}

}