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

LF: drop ad-hoc FrontStack builders #10839

Merged
merged 1 commit into from
Sep 13, 2021
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ abstract class AbstractImmArraySeq[+A](array: ImmArray[A])
bf match {
case _: IASCanBuildFrom[A] => this
case _: ImmArrayInstances.IACanBuildFrom[A] => toImmArray
case _: FrontStackInstances.FSCanBuildFrom[A] => FrontStack(toImmArray)
case _: FrontStackInstances.FSCanBuildFrom[A] => FrontStack.from(toImmArray)
case _ => super.to(bf)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ import ScalazEqual.{equalBy, toIterableForScalazInstances}
import scalaz.Equal

import scala.collection.generic.CanBuildFrom
import scala.collection.mutable

private[data] abstract class FrontStackInstances {

def apply[T](elements: T*): FrontStack[T] = elements.to[FrontStack]

implicit def equalInstance[A: Equal]: Equal[FrontStack[A]] = {
import scalaz.std.iterable._
equalBy(fs => toIterableForScalazInstances(fs.iterator), true)
Expand All @@ -28,9 +32,9 @@ private[data] abstract class FrontStackInstances {

private[data] object FrontStackInstances {
final class FSCanBuildFrom[A] extends CanBuildFrom[FrontStack[_], A, FrontStack[A]] {
override def apply(from: FrontStack[_]) = apply()
override def apply(from: FrontStack[_]): mutable.Builder[A, FrontStack[A]] = apply()

override def apply() =
ImmArray.newBuilder[A].mapResult(FrontStack(_))
override def apply(): mutable.Builder[A, FrontStack[A]] =
ImmArray.newBuilder[A].mapResult(FrontStack.from)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ package com.daml.lf.data
import ScalazEqual.{equalBy, toIterableForScalazInstances}

import scalaz.Equal
import scala.collection.mutable.Builder
import scala.collection.mutable

abstract class FrontStackInstances extends scala.collection.IterableFactory[FrontStack] {
override def from[A](it: IterableOnce[A]) = (newBuilder ++= it).result()
override def newBuilder[A]: Builder[A, FrontStack[A]] =
ImmArray.newBuilder.mapResult(FrontStack(_))
override def from[A](it: IterableOnce[A]): FrontStack[A] =
FrontStack.from(ImmArray.from(it))
override def newBuilder[A]: mutable.Builder[A, FrontStack[A]] =
ImmArray.newBuilder.mapResult(FrontStack.from)
implicit def equalInstance[A: Equal]: Equal[FrontStack[A]] = {
import scalaz.std.iterable._
equalBy(fs => toIterableForScalazInstances(fs.iterator), true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ final class BackStack[+A] private (fq: BQ[A], val length: Int) {
case BQAppend(init, last) => go(init, last ++: acc)
case BQEmpty => acc
}
go(fq, FrontStack.empty)
go(fq, FrontStack.Empty)
}

/** O(1) */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@

package com.daml.lf.data

import FrontStack.{FQ, FQCons, FQEmpty, FQPrepend}
import ScalazEqual.{orderBy, toIterableForScalazInstances}

import scalaz.syntax.applicative._
import scalaz.syntax.traverse._
import scalaz.{Applicative, Order, Traverse}

import scala.annotation.tailrec
import scala.util.hashing.MurmurHash3

/** A stack which allows to cons, prepend, and pop in constant time, and generate an ImmArray in linear time.
* Very useful when needing to traverse stuff in topological order or similar situations.
*/
final class FrontStack[+A] private (fq: FQ[A], val length: Int) {
final class FrontStack[+A] private (fq: FrontStack.FQ[A], val length: Int) {

import FrontStack._

/** O(n) */
@throws[IndexOutOfBoundsException]
Expand Down Expand Up @@ -84,9 +85,7 @@ final class FrontStack[+A] private (fq: FQ[A], val length: Int) {
}

/** O(n) */
def map[B](f: A => B): FrontStack[B] = {
this.toImmArray.map(f) ++: FrontStack.empty
}
def map[B](f: A => B): FrontStack[B] = from(toImmArray.map(f))

/** O(1) */
def isEmpty: Boolean = length == 0
Expand Down Expand Up @@ -135,36 +134,20 @@ final class FrontStack[+A] private (fq: FQ[A], val length: Int) {
case _ => false
}

override def hashCode(): Int = toImmArray.hashCode()
override def hashCode(): Int =
MurmurHash3.orderedHash(toIterableForScalazInstances(iterator))

/** O(n) */
override def toString: String = "FrontStack(" + iterator.map(_.toString).mkString(",") + ")"
}

object FrontStack extends FrontStackInstances {
private[this] val emptySingleton: FrontStack[Nothing] = new FrontStack(FQEmpty, 0)

def empty[A]: FrontStack[A] = emptySingleton

def apply[A](xs: ImmArray[A]): FrontStack[A] =
if (xs.length > 0) {
new FrontStack(FQPrepend(xs, FQEmpty), length = xs.length)
} else {
empty
}

def apply[T](element: T): FrontStack[T] =
new FrontStack(FQCons(element, FQEmpty), length = 1)

def apply[T](a: T, b: T): FrontStack[T] =
new FrontStack(FQCons(a, FQCons(b, FQEmpty)), length = 2)
val Empty: FrontStack[Nothing] = new FrontStack(FQEmpty, 0)

// Slow; only use this in tests.
def apply[T](a: T, b: T, c: T, elements: T*): FrontStack[T] =
a +: b +: c +: apply(elements.to(ImmArray))
def empty[A]: FrontStack[A] = FrontStack.Empty

def apply[T](elements: Seq[T]): FrontStack[T] =
apply(elements.to(ImmArray))
def from[A](xs: ImmArray[A]): FrontStack[A] =
if (xs.isEmpty) Empty else new FrontStack(FQPrepend(xs, FQEmpty), length = xs.length)

def unapply[T](xs: FrontStack[T]): Boolean = xs.isEmpty

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ final class ImmArray[+A] private (
collect { case x if f(x) => x }

override def hashCode(): Int = toSeq.hashCode()

def toFrontStack: FrontStack[A] = FrontStack.from(this)

}

object ImmArray extends ImmArrayInstances {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,6 @@ class FrontStackSpec
FrontStack(x, y) should ===(x +: y +: FrontStack.empty)
}
}

"more than 2 elements are provided" should {
"behave the same as prepend" in forAll { (x: Int, y: Int, z: Int, rest: Seq[Int]) =>
FrontStack(x, y, z, rest: _*) should ===(
(Seq(x, y, z) ++ rest).to(ImmArray) ++: FrontStack.empty
)
}
}

"a sequence of elements is provided" should {
"behave the same as prepend" in forAll { xs: Seq[Int] =>
FrontStack(xs) should ===(xs.to(ImmArray) ++: FrontStack.empty)
}
}
}

"++:" should {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ object Blinding {
}

GenTransaction(
roots = go(BackStack.empty, FrontStack(tx.roots)),
roots = go(BackStack.empty, tx.roots.toFrontStack),
nodes = filteredNodes,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ private[lf] final class CommandPreprocessor(
}
}

go(FrontStack(cmds), BackStack.empty)
go(cmds.toFrontStack, BackStack.empty)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,7 @@ class EngineTest
.translateValue(TList(TBuiltin(BTInt64)), list)
.consume(lookupContract, lookupPackage, lookupKey)

res shouldEqual Right(SList(FrontStack(ImmArray(SInt64(1)))))
res shouldEqual Right(SList(FrontStack(SInt64(1))))
}

"translate average list" in {
Expand All @@ -1174,7 +1174,7 @@ class EngineTest
.consume(lookupContract, lookupPackage, lookupKey)

res shouldEqual Right(
SValue.SList(FrontStack(ImmArray(SInt64(1), SInt64(2), SInt64(3), SInt64(4), SInt64(5))))
SValue.SList(FrontStack(SInt64(1), SInt64(2), SInt64(3), SInt64(4), SInt64(5)))
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ class LargeTransactionTest extends AnyWordSpec with Matchers with BazelRunfiles
): ExerciseCommand = {
val choice = "Size"
val choiceDefRef = Identifier(templateId.packageId, qn(s"LargeTransaction:$choice"))
val damlList = ValueList(FrontStack(elements = List.range(0L, size.toLong).map(ValueInt64)))
val damlList = ValueList(List.range(0L, size.toLong).map(ValueInt64).to(FrontStack))
val choiceArgs = ValueRecord(Some(choiceDefRef), ImmArray((None, damlList)))
ExerciseCommand(templateId, contractId, choice, choiceArgs)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ private[lf] object SBuiltin {
//
final case object SBExplodeText extends SBuiltinPure(1) {
override private[speedy] def executePure(args: util.ArrayList[SValue]): SList =
SList(FrontStack(Utf8.explode(getSText(args, 0)).map(SText)))
SList(FrontStack.from(Utf8.explode(getSText(args, 0)).map(SText)))
}

final case object SBImplodeText extends SBuiltinPure(1) {
Expand Down Expand Up @@ -507,7 +507,7 @@ private[lf] object SBuiltin {
override private[speedy] def executePure(args: util.ArrayList[SValue]): SList = {
val string = getSText(args, 0)
val codePoints = Utf8.unpack(string)
SList(FrontStack(codePoints.map(SInt64)))
SList(FrontStack.from(codePoints.map(SInt64)))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,13 +366,11 @@ object SValue {

def toList(entries: TreeMap[SValue, SValue]): SList =
SList(
FrontStack(
entries.iterator
.map { case (k, v) =>
entry(k, v)
}
.to(ImmArray)
)
entries.view
.map { case (k, v) =>
entry(k, v)
}
.to(FrontStack)
)

private def mapArrayList(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1045,15 +1045,15 @@ class SBuiltinTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChe
"returns the keys in order" in {

eval(e"GENMAP_KEYS @Text @Int64 ${buildMap("Int64", words: _*)}") shouldBe
Right(SList(FrontStack(sortedWords.map { case (k, _) => SText(k) })))
Right(SList(sortedWords.map { case (k, _) => SText(k) }.to(FrontStack)))
}
}

"GENMAP_VALUES" - {

"returns the values in order" in {
eval(e"GENMAP_VALUES @Text @Int64 ${buildMap("Int64", words: _*)}") shouldBe
Right(SList(FrontStack(sortedWords.map { case (_, v) => SInt64(v.toLong) })))
Right(SList(sortedWords.map { case (_, v) => SInt64(v.toLong) }.to(FrontStack)))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ object ValueGenerators {
private def valueListGen(nesting: Int): Gen[ValueList[ContractId]] =
for {
values <- Gen.listOf(Gen.lzy(valueGen(nesting)))
} yield ValueList[ContractId](FrontStack(values))
} yield ValueList[ContractId](values.to(FrontStack))

def valueListGen: Gen[ValueList[ContractId]] = valueListGen(0)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ final case class GenTransaction[Nid, +Cid](
}
}
}
val (errors, visited) = go(Set.empty, Set.empty, FrontStack(roots))
val (errors, visited) = go(Set.empty, Set.empty, FrontStack.from(roots))
val orphaned = nodes.keys.toSet.diff(visited).map(nid => NotWellFormedError(nid, OrphanedNode))
errors ++ orphaned
}
Expand Down Expand Up @@ -217,7 +217,7 @@ final case class GenTransaction[Nid, +Cid](
if (roots.length != other.roots.length)
false
else
go(FrontStack(roots.zip(other.roots)))
go(roots.zip(other.roots).toFrontStack)

}

Expand Down Expand Up @@ -321,7 +321,7 @@ sealed abstract class HasTxNodes[Nid, +Cid] {
}
}

go(FrontStack(roots))
go(roots.toFrontStack)
}

/** Traverses the transaction tree in pre-order traversal (i.e. exercise nodes are traversed before their children)
Expand Down Expand Up @@ -361,7 +361,7 @@ sealed abstract class HasTxNodes[Nid, +Cid] {
}
}

go(FrontStack(roots.map(_ -> pathState0)))
go(roots.map(_ -> pathState0).toFrontStack)
globalState
}

Expand Down Expand Up @@ -672,13 +672,13 @@ sealed abstract class HasTxNodes[Nid, +Cid] {
nodes(nid) match {
case rb: Node.NodeRollback[_] =>
if (rollbackBegin(nid, rb)) {
loop(FrontStack(rb.children), ((nid, Left(rb)), rest) +: stack)
loop(rb.children.toFrontStack, ((nid, Left(rb)), rest) +: stack)
} else {
loop(rest, stack)
}
case exe: Node.NodeExercises[Nid, Cid] =>
if (exerciseBegin(nid, exe)) {
loop(FrontStack(exe.children), ((nid, Right(exe)), rest) +: stack)
loop(exe.children.toFrontStack, ((nid, Right(exe)), rest) +: stack)
} else {
loop(rest, stack)
}
Expand All @@ -701,7 +701,7 @@ sealed abstract class HasTxNodes[Nid, +Cid] {
}
}

loop(FrontStack(roots), FrontStack.empty)
loop(roots.toFrontStack, FrontStack.empty)
}

// This method visits to all nodes of the transaction in execution order.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,7 @@ object ValueCoder {
)
case proto.Value.SumCase.LIST =>
ValueList(
FrontStack(
protoValue.getList.getElementsList.asScala.map(go(newNesting, _)).to(ImmArray)
)
protoValue.getList.getElementsList.asScala.map(go(newNesting, _)).to(FrontStack)
)

case proto.Value.SumCase.VARIANT =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,15 +408,15 @@ object Converter {
("contractId", fromAnyContractId(scriptIds, toApiIdentifier(tplId), contractId.coid)),
("choice", SText(choiceName)),
("argument", anyChoice),
("childEvents", SList(FrontStack(evs))),
("childEvents", SList(evs.to(FrontStack))),
),
)
}
for {
events <- tree.rootEvents.traverse(translateTreeEvent(_)): Either[String, List[SValue]]
} yield record(
scriptIds.damlScript("SubmitFailure"),
("rootEvents", SList(FrontStack(events))),
("rootEvents", SList(events.to(FrontStack))),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ object ScriptF {
)
acs <- client.query(parties, tplId)
res <- Converter.toFuture(
FrontStack(acs)
acs
.to(FrontStack)
.traverse(
Converter
.fromCreated(env.valueTranslator, _)
Expand Down Expand Up @@ -329,7 +330,7 @@ object ScriptF {
partyDetails
.traverse(details => Converter.fromPartyDetails(env.scriptIds, details))
)
} yield SEApp(SEValue(continue), Array(SEValue(SList(FrontStack(partyDetails_)))))
} yield SEApp(SEValue(continue), Array(SEValue(SList(partyDetails_.to(FrontStack)))))

}
final case class GetTime(stackTrace: StackTrace, continue: SValue) extends Cmd {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ object LedgerValue {
private def convertList(apiList: api.value.List) = {
for {
values <- apiList.elements.toList.traverse(_.convert)
} yield V.ValueList(FrontStack(values))
} yield V.ValueList(values.to(FrontStack))
}

private def convertVariant(apiVariant: api.value.Variant) = {
Expand Down
Loading