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

Latest 2.13.x with Stepper and Accumulator tests. #28

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions laws/src/main/scala/Flag.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,34 @@ object Flag {
val SEQ = F // Is a sequence
val SET = F // Is a set
val STR = F // Uses strings as the element type
val VIEW = F // Is a view (normally doesn't matter, except views are lazy)

// Unusual "collections" that are not expected to behave exactly like others
val ARRAY = F // Is an Array
val STRING = F // Is a String
val STRAW = F // strawman collections (when used together with regular collections)
val ORDERLY = F // Collection is sorted, but can't maintain itself with all operations as it might lose its ordering
val ONCE = F // Collection is consumed on traversal
val INDEF = F // Collection's size is not yet fixed (lazy collections)
val SPECTYPE= F // Collection has constraints on element type, which makes some operations not work
val BITSET = F // Collection is specificially a bitset (mutable or immutable)
val INSORD = F // Collection traverses itself in insertion order even though it's not intrinsically ordered

val SPLITS = F // Collection can produce an efficiently splitting stepper
val STAGGER = F // Collection has an efficient stepper but traverses in unusual order

// Everything down here is _highly_ dubious behavior but is included to get tests to pass
val PRIORITYQUEUE_IS_SPECIAL = F // Inconsistent behavior regarding what is dequeued (ordered) vs. not
val ACC_SPEC = F // Specialized accumulators revert to more general type in more cases than some other collections

// Workarounds for identified bugs go here.
val BITSET_MAP_AMBIG = F // Bit maps don't know whether to use StrictOptimized or SortedSet ops for map.
val BITSET_ZIP_AMBIG = F // Same problem with zipping
val BITSET_ZIP_AMBIG = F // Same problem with zipping
val INEFFICIENT_BUG = F // Some things should split efficiently but don't

// Pure bugs that aren't fixed yet
val LISTBUF_PIP_11438 = F // ListBuffer throws an exception on a no-op patchInPlace
val QUEUE_SLIDE_11440 = F // Queue and ArrayStack will not give you an underfull sliding window (everything else does)
val PQ_MIP_NPE_11439 = F // Priority Queue can just give null when empty!
val LISTBUF_PIP_11438 = X // ListBuffer throws an exception on a no-op patchInPlace
Copy link
Contributor

@NthPortal NthPortal Dec 28, 2020

Choose a reason for hiding this comment

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

these all appear to be fixed

val QUEUE_SLIDE_11440 = X // Queue and ArrayStack will not give you an underfull sliding window (everything else does)
val PQ_MIP_NPE_11439 = X // Priority Queue can just give null when empty!
val CPMH_TYPE_11449 = X // CollisionProofHashMap loses its type even when it needn't

// Mysterious bugs that can't easily be replciated
val SORTWITH_INT_CCE = F // Array (but nothing else) gives class cast error in `sortWith` on ints! Can't reproduce in REPL.
Expand Down
27 changes: 25 additions & 2 deletions laws/src/main/scala/Generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,13 @@ object AllIntGenerators {
val wrappedArray = register(io.Mut)(_.wrappedArray())
}

/** Generator for accumulators and anything else used in conversions */
object Conv {
// TODO--get Ops-like abstractions to work; then this can be used
// val accumulator = register(io.Conv)(_.accumulator())
val anyAccumulator = register(io.Conv)(_.anyAccumulator())
}

/** Generator for iterators and views. */
object Root {
val iterator = register(io.Root)(_.iterator())
Expand All @@ -255,8 +262,13 @@ object AllIntGenerators {
val bitSet = register(io.MutInt)(_.bitSet(), "collection.mutable.BitSet")
}

/** Generator for Int-specialized accumulators */
object ConvInt {
val intAccumulator = register(io.ConvInt)(_.intAccumulator(), "scala.jdk.IntAccumulator")
}

/** This line is needed to actually perform the registration of all generators! */
val force = Imm :: Mut :: Root :: ImmInt :: MutInt :: Nil
val force = Imm :: Mut :: Conv :: Root :: ImmInt :: MutInt :: ConvInt :: Nil

/** All registered generators */
lazy val all = everyoneBuffer.result
Expand Down Expand Up @@ -347,6 +359,13 @@ object AllStrGenerators {
val wrappedArray = register(io.Mut)(_.wrappedArray())
}

/** Generator for accumulators and anything else used in conversions */
object Conv {
// TODO--get Ops-like abstractions to work; then this can be used
// val accumulator = register(io.Conv)(_.accumulator())
val anyAccumulator = register(io.Conv)(_.anyAccumulator())
}

/** Generator for iterators. */
object Root {
val iterator = register(io.Root)(_.iterator())
Expand All @@ -358,7 +377,7 @@ object AllStrGenerators {
}

/** This line is needed to actually perform the registration of all generators! */
val force = Imm :: Mut :: Root :: Nil
val force = Imm :: Mut :: Conv :: Root :: Nil

/** All registered generators */
lazy val all = everyoneBuffer.result
Expand Down Expand Up @@ -406,6 +425,8 @@ object AllLongStrGenerators {
}

object MutKV {
val collisionProofHashMap =
register(io.MutKV)(_.collisionProofHashMap())
val hashMap = register(io.MutKV)(_.hashMap())
val listMap = register(io.MutKV)(_.listMap())
val linkedHashMap = register(io.MutKV)(_.linkedHashMap())
Expand Down Expand Up @@ -463,6 +484,8 @@ object AllStrLongGenerators {
}

object MutKV {
val collisionProofHashMap =
register(io.MutKV)(_.collisionProofHashMap())
val hashMap = register(io.MutKV)(_.hashMap())
val listMap = register(io.MutKV)(_.listMap())
val linkedHashMap = register(io.MutKV)(_.linkedHashMap())
Expand Down
105 changes: 75 additions & 30 deletions laws/src/main/scala/Instantiator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ extends Exploratory[(A, Array[A], Array[A])] {
}

// MUST use lower-camel-cased collection class name for code generator to work properly!
val arraySeq = C(collection.immutable.ArraySeq unsafeWrapArray _, SEQ)
val hashSet = C(_.to(collection.immutable.HashSet), SET)
val indexedSeq = C(_.to(collection.immutable.IndexedSeq), SEQ)
val arraySeq = C(collection.immutable.ArraySeq unsafeWrapArray _, SEQ, SPLITS)
val hashSet = C(_.to(collection.immutable.HashSet), SET, SPLITS)
val indexedSeq = C(_.to(collection.immutable.IndexedSeq), SEQ, SPLITS)
val iterable = C(_.to(collection.immutable.Iterable))
val lazyList = C(
a => collection.immutable.LazyList.from(0).takeWhile(_ < a.length).map(i => a(i)),
Expand All @@ -100,8 +100,8 @@ extends Exploratory[(A, Array[A], Array[A])] {
SEQ, INDEF
)
val traversable = C(_.to(collection.immutable.Traversable))
val treeSet = C(_.to(collection.immutable.TreeSet), SET, ORDERLY)
val vector = C(_.toVector, SEQ)
val treeSet = C(_.to(collection.immutable.TreeSet), SET, ORDERLY, SPLITS)
val vector = C(_.toVector, SEQ, SPLITS)
}

object Mut extends Instance.PackagePath {
Expand All @@ -121,24 +121,46 @@ extends Exploratory[(A, Array[A], Array[A])] {
}

// MUST use lower-camel-cased collection class name for code generator to work properly!
val array = C(_.clone, SEQ, ARRAY, SORTWITH_INT_CCE).moreMethods(MethodChecker.from[collection.ArrayOps[A]])
val arrayBuffer = C(_.to(collection.mutable.ArrayBuffer), SEQ)
val arrayDeque = C(_.to(collection.mutable.ArrayDeque), SEQ, QUEUE_SLIDE_11440)
val arraySeq = C(_.to(collection.mutable.ArraySeq), SEQ)
val arrayStack = C(_.to(collection.mutable.ArrayStack), SEQ, QUEUE_SLIDE_11440)
val array = C(_.clone, SEQ, ARRAY, SORTWITH_INT_CCE, SPLITS).moreMethods(MethodChecker.from[collection.ArrayOps[A]])
val arrayBuffer = C(_.to(collection.mutable.ArrayBuffer), SEQ, SPLITS)
val arrayDeque = C(_.to(collection.mutable.ArrayDeque), SEQ, SPLITS, QUEUE_SLIDE_11440)
val arraySeq = C(_.to(collection.mutable.ArraySeq), SEQ, SPLITS)
val arrayStack = C(_.to(collection.mutable.ArrayStack), SEQ, SPLITS, QUEUE_SLIDE_11440)
val buffer = C(_.to(collection.mutable.Buffer), SEQ)
val hashSet = C(_.to(collection.mutable.HashSet), SET)
val indexedSeq = C(_.to(collection.mutable.IndexedSeq), SEQ)
val hashSet = C(_.to(collection.mutable.HashSet), SET, SPLITS)
val indexedSeq = C(_.to(collection.mutable.IndexedSeq), SEQ, SPLITS)
val iterable = C(_.to(collection.mutable.Iterable))
val linkedHashSet= C(_.to(collection.mutable.LinkedHashSet), SET)
val linkedHashSet= C(_.to(collection.mutable.LinkedHashSet), SET, SPLITS, STAGGER)
val listBuffer = C(_.to(collection.mutable.ListBuffer), SEQ, LISTBUF_PIP_11438)
val priorityQueue= C(_.to(collection.mutable.PriorityQueue), ORDERLY, PRIORITYQUEUE_IS_SPECIAL, PQ_MIP_NPE_11439)
val queue = C(_.to(collection.mutable.Queue), SEQ, QUEUE_SLIDE_11440)
val queue = C(_.to(collection.mutable.Queue), SEQ, SPLITS, QUEUE_SLIDE_11440)
val seq = C(_.to(collection.mutable.Seq), SEQ)
val stack = C(_.to(collection.mutable.Stack), QUEUE_SLIDE_11440)
val treeSet = C(_.to(collection.mutable.TreeSet), SET, ORDERLY)
val stack = C(_.to(collection.mutable.Stack), SPLITS, QUEUE_SLIDE_11440)
val treeSet = C(_.to(collection.mutable.TreeSet), SET, SPLITS, ORDERLY)
// val unrolledBuffer = C(_.to(collection.mutable.UnrolledBuffer), SEQ) // Unrolled buffer is weird!
val wrappedArray = C(_.clone: collection.mutable.WrappedArray[A], SEQ)
val wrappedArray = C(_.clone: collection.mutable.WrappedArray[A], SEQ, SPLITS)
}

object Conv extends Instance.PackagePath {
def nickname = "Conv"
def fullyQualified = "scala.jdk"
def C[CC: TypeTag: Sizable](ccf: Array[A] => CC, flags: Flag*)(implicit nm: sourcecode.Name): Deployed[A, CC] = {
val gen = inst.makeWith(ccf, flags: _*)(nm, implicitly[TypeTag[CC]], implicitly[Sizable[CC]])
val ans = new Deployed[A, CC] {
val secretly = gen
var accesses: Int = 0
val name = nm.value.toString
def group = typeTagA.tpe.toString + "in " + nickname
def apply(): Instance.FromArray[A, CC] = { accesses += 1; secretly }
}
registry += ans
ans
}

// TODO--use the generic builder in a productive way; hard because it's Ops-like not its own collection
// val accumulator = C(a => collection.convert.Accumulator from a, SEQ)

val anyAccumulator = C(a => scala.jdk.AnyAccumulator(a.toSeq: _*), SEQ, SPLITS)
}

object Root extends Instance.PackagePath {
Expand Down Expand Up @@ -172,7 +194,7 @@ extends Exploratory[(A, Array[A], Array[A])] {

// MUST use lower-camel-cased collection class name for code generator to work properly!
val iterator = C(a => (new IteratorKnowsSize[A](a)): Iterator[A], ONCE, INDEF)
val view = C(a => a.to(collection.immutable.Vector).view: scala.collection.View[A])
val view = C(a => a.to(collection.immutable.Vector).view: scala.collection.View[A], VIEW)

// These don't work because they take arguments of a different type than they are themselves
// val indexedSeqView = C(a => a.view: scala.collection.IndexedSeqView[A])
Expand Down Expand Up @@ -228,12 +250,12 @@ trait InstantiatorsOfKV[K, V] extends Exploratory[((K, V), Array[(K, V)], Array[
}

// MUST use lower-camel-cased collection class name for code generator to work properly!
val hashMap = C({ a => val mb = collection.immutable.HashMap.newBuilder[K, V]; for (kv <- a) mb += kv; mb.result })
val hashMap = C({ a => val mb = collection.immutable.HashMap.newBuilder[K, V]; for (kv <- a) mb += kv; mb.result }, SPLITS)
val listMap = C({ a => val mb = collection.immutable.ListMap.newBuilder[K, V]; for (kv <- a) mb += kv; mb.result })
val sortedMap = C({ a => val mb = collection.immutable.SortedMap.newBuilder[K, V]; for (kv <- a) mb += kv; mb.result })
val treeMap = C({ a => val mb = collection.immutable.TreeMap.newBuilder[K, V]; for (kv <- a) mb += kv; mb.result })
val treeMap = C({ a => val mb = collection.immutable.TreeMap.newBuilder[K, V]; for (kv <- a) mb += kv; mb.result }, SPLITS)
val treeSeqMap = C({ a => val mb = collection.immutable.TreeSeqMap.newBuilder[K, V]; for (kv <- a) mb += kv; mb.result }, INSORD)
val vectorMap = C({ a => val mb = collection.immutable.VectorMap.newBuilder[K, V]; for (kv <- a) mb += kv; mb.result }, INSORD)
val vectorMap = C({ a => val mb = collection.immutable.VectorMap.newBuilder[K, V]; for (kv <- a) mb += kv; mb.result }, INSORD, SPLITS, INEFFICIENT_BUG)
}

object MutKV extends Instance.PackagePath {
Expand All @@ -253,12 +275,15 @@ trait InstantiatorsOfKV[K, V] extends Exploratory[((K, V), Array[(K, V)], Array[
}

// MUST use lower-camel-cased collection class name for code generator to work properly!
val hashMap = C({ a => val m = new collection.mutable.HashMap[K, V]; for (kv <- a) m += kv; m })
import collection.mutable.CollisionProofHashMap
val collisionProofHashMap =
C({ a => val m = new CollisionProofHashMap[K, V]; for (kv <- a) m += kv; m }, CPMH_TYPE_11449)
val hashMap = C({ a => val m = new collection.mutable.HashMap[K, V]; for (kv <- a) m += kv; m }, SPLITS)
val listMap = C({ a => val m = new collection.mutable.ListMap[K, V]; for (kv <- a) m += kv; m })
val linkedHashMap = C({ a => val m = new collection.mutable.LinkedHashMap[K, V]; for (kv <- a) m += kv; m }, INSORD)
val linkedHashMap = C({ a => val m = new collection.mutable.LinkedHashMap[K, V]; for (kv <- a) m += kv; m }, INSORD, STAGGER)
val openHashMap = C({ a => val m = new collection.mutable.OpenHashMap[K, V]; for (kv <- a) m += kv; m })
val sortedMap = C({ a => val m = collection.mutable.SortedMap.empty[K, V]; for (kv <- a) m += kv; m })
val treeMap = C({ a => val m = new collection.mutable.TreeMap[K, V]; for (kv <- a) m += kv; m })
val treeMap = C({ a => val m = new collection.mutable.TreeMap[K, V]; for (kv <- a) m += kv; m }, SPLITS)
val weakHashMap = C({ a => val m = new collection.mutable.WeakHashMap[K, V]; for (kv <- a) m += kv; m })
}
}
Expand Down Expand Up @@ -298,9 +323,10 @@ object InstantiatorsOfInt extends InstantiatorsOf[Int] {
protected implicit def classTagA = ClassTagSource.classTagInt
protected def allFlags = Array(INT)

protected implicit val sizeOfRange = new Sizable[collection.immutable.Range] { def sizeof(r: collection.immutable.Range) = r.size }
protected implicit val sizeOfRange = new Sizable[collection.immutable.Range] { def sizeof(r: collection.immutable.Range) = r.size }
protected implicit val sizeOfIBitSet = new Sizable[collection.immutable.BitSet] { def sizeof(s: collection.immutable.BitSet) = s.size }
protected implicit val sizeOfMBitSet = new Sizable[collection.mutable.BitSet] { def sizeof(s: collection.mutable.BitSet) = s.size }
protected implicit val sizeOfMBitSet = new Sizable[collection.mutable.BitSet] { def sizeof(s: collection.mutable.BitSet) = s.size }
protected implicit val sizeOfIAccum = new Sizable[scala.jdk.IntAccumulator] { def sizeof(a: scala.jdk.IntAccumulator) = a.size }

/** Extra instantiators specific to Ints in immutable collections */
object ImmInt extends Instance.PackagePath {
Expand All @@ -323,7 +349,7 @@ object InstantiatorsOfInt extends InstantiatorsOf[Int] {
// MUST use lower-camel-cased collection clasTs name for code generator to work properly!
val bitSet = C(
{ a => val b = collection.immutable.BitSet.newBuilder; a.foreach{ x => if (x >= 0) b += x }; b.result },
SET, ORDERLY, SPECTYPE, BITSET, BITSET_MAP_AMBIG, BITSET_ZIP_AMBIG
SET, ORDERLY, SPECTYPE, BITSET, SPLITS, BITSET_MAP_AMBIG, BITSET_ZIP_AMBIG
)
//val range = C({ a => if (a.length % 3 == 0) 0 until a.length else 0 to a.length })
}
Expand All @@ -349,10 +375,29 @@ object InstantiatorsOfInt extends InstantiatorsOf[Int] {
// MUST use lower-camel-cased collection class name for code generator to work properly!
val bitSet = C(
{ a => val b = new collection.mutable.BitSet; a.foreach{ x => if (x >= 0) b += x }; b },
SET, ORDERLY, SPECTYPE, BITSET, BITSET_MAP_AMBIG, BITSET_ZIP_AMBIG
SET, ORDERLY, SPECTYPE, BITSET, SPLITS, BITSET_MAP_AMBIG, BITSET_ZIP_AMBIG
)
}

object ConvInt extends Instance.PackagePath {
def nickname = "ConvInt"
def fullyQualified = "scala.jdk"
def C[CC: TypeTag: Sizable](ccf: Array[Int] => CC, flags: Flag*)(implicit nm: sourcecode.Name): Deployed[Int, CC] = {
val gen = inst.makeWith(ccf, flags: _*)(nm, implicitly[TypeTag[CC]], implicitly[Sizable[CC]])
val ans = new Deployed[Int, CC] {
val secretly = gen
var accesses: Int = 0
val name = nm.value.toString
def group = typeTagA.tpe.toString + "in " + nickname
def apply(): Instance.FromArray[Int, CC] = { accesses += 1; secretly }
}
registry += ans
ans
}

val intAccumulator = C(a => scala.jdk.IntAccumulator(a.toSeq: _*), SEQ, SPECTYPE, SPLITS, ACC_SPEC)
}

/** Singleton `Int` values to test */
lazy val possible_a = Array(0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 23, 31, 47, 152, 3133, 1294814, -1, -2, -6, -19, -1915, -19298157)

Expand Down Expand Up @@ -454,7 +499,7 @@ object InstantiatorsOfLongStr extends InstantiatorsOf[(Long, String)] with Insta
registry += ans
ans
}
val longMap = C({ a => val m = new collection.mutable.LongMap[String]; for (kv <- a) m += kv; m }, SPECTYPE)
val longMap = C({ a => val m = new collection.mutable.LongMap[String]; for (kv <- a) m += kv; m }, SPECTYPE, SPLITS, INEFFICIENT_BUG)
}

/** Very limited set of possible singletons */
Expand Down Expand Up @@ -514,7 +559,7 @@ object InstantiatorsOfStrLong extends InstantiatorsOf[(String, Long)] with Insta
registry += ans
ans
}
val anyRefMap = C({ a => val m = new collection.mutable.AnyRefMap[String, Long]; for (kv <- a) m += kv; m }, SPECTYPE)
val anyRefMap = C({ a => val m = new collection.mutable.AnyRefMap[String, Long]; for (kv <- a) m += kv; m }, SPECTYPE, SPLITS, INEFFICIENT_BUG)
}

lazy val possible_a = Array("wish" -> 3L)
Expand Down
Loading