Skip to content

Commit

Permalink
Map now defaults to unpadded Refs
Browse files Browse the repository at this point in the history
  • Loading branch information
durban committed Dec 21, 2024
1 parent ea4023d commit 86041df
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ object ResourceAllocationRxn {
Vector.fill(nRes)(scala.util.Random.nextString(10))

val rss: Array[Ref[String]] =
initialValues.map(Ref.unsafe).toArray
initialValues.map(Ref.unsafe(_)).toArray

@TearDown
def checkResults(): Unit = {
Expand Down
4 changes: 4 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ lazy val data = crossProject(JVMPlatform, JSPlatform)
ProblemFilters.exclude[ReversedMissingMethodProblem]("dev.tauri.choam.data.Map#Extra.keys"), // sealed
ProblemFilters.exclude[ReversedMissingMethodProblem]("dev.tauri.choam.data.Map#Extra.valuesUnsorted"), // sealed
ProblemFilters.exclude[ReversedMissingMethodProblem]("dev.tauri.choam.data.Map#Extra.items"), // sealed
ProblemFilters.exclude[ReversedMissingMethodProblem]("dev.tauri.choam.data.AbstractMapPlatform.hashMap"), //private
ProblemFilters.exclude[ReversedMissingMethodProblem]("dev.tauri.choam.data.AbstractMapPlatform.orderedMap"), // private
ProblemFilters.exclude[DirectMissingMethodProblem]("dev.tauri.choam.data.Ttrie.skipListBased"), // private
ProblemFilters.exclude[DirectMissingMethodProblem]("dev.tauri.choam.data.Ttrie.apply"), // private
),
)

Expand Down
31 changes: 31 additions & 0 deletions core/shared/src/main/scala/dev/tauri/choam/refs/Ref.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,24 @@ private[refs] trait UnsealedRef[A] extends Ref[A] { this: MemoryLocation[A] =>

object Ref extends RefInstances0 {

final case class AllocationStrategy private (padded: Boolean) {

final def withPadded(padded: Boolean): AllocationStrategy =
this.copy(padded = padded)

final def toArrayAllocationStrategy: Array.AllocationStrategy =
Array.AllocationStrategy.Default.withPadded(padded = this.padded)
}

final object AllocationStrategy {

final val Default: AllocationStrategy =
AllocationStrategy(padded = false)

final def apply(padded: Boolean): AllocationStrategy =
new AllocationStrategy(padded = padded)
}

sealed trait Array[A] {

def size: Int
Expand Down Expand Up @@ -129,6 +147,9 @@ object Ref extends RefInstances0 {

final def apply(sparse: Boolean, flat: Boolean, padded: Boolean): AllocationStrategy =
new AllocationStrategy(sparse = sparse, flat = flat, padded = padded)

final def fromRefAllocationStrategy(ras: Ref.AllocationStrategy): AllocationStrategy =
ras.toArrayAllocationStrategy
}
}

Expand Down Expand Up @@ -164,6 +185,11 @@ object Ref extends RefInstances0 {
private[choam] final def apply[A](initial: A): Axn[Ref[A]] =
padded(initial)

final def apply[A](initial: A, str: Ref.AllocationStrategy): Axn[Ref[A]] = {
if (str.padded) padded(initial)
else unpadded(initial)
}

// TODO: How to avoid allocating RefArrayRef objects?
// TODO: Create getAndUpdate(idx: Int, f: A => A) methods.
// TODO: (Implement them with something like `OffsetMemoryLocation`.)
Expand Down Expand Up @@ -331,6 +357,11 @@ object Ref extends RefInstances0 {
private[choam] final def unsafe[A](initial: A): Ref[A] = // TODO: don't use this (except in tests)
unsafePadded(initial)

private[choam] final def unsafe[A](initial: A, str: AllocationStrategy, rig: RefIdGen): Ref[A] = {
if (str.padded) unsafePadded(initial, rig)
else unsafeUnpadded(initial, rig)
}

private[choam] final def unsafePadded[A](initial: A): Ref[A] =
this.unsafePadded(initial, RefIdGen.global)

Expand Down
6 changes: 6 additions & 0 deletions data/js/src/main/scala/dev/tauri/choam/data/MapPlatform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ private[data] abstract class MapPlatform extends AbstractMapPlatform {
final override def hashMap[K: Hash, V]: Axn[Map[K, V]] =
this.simpleHashMap[K, V]

final override def hashMap[K: Hash, V](str: Ref.AllocationStrategy): Axn[Map[K, V]] =
hashMap[K, V]

final override def orderedMap[K: Order, V]: Axn[Map[K, V]] =
this.simpleOrderedMap[K, V]

final override def orderedMap[K: Order, V](str: Ref.AllocationStrategy): Axn[Map[K, V]] =
orderedMap[K, V]

private[data] override def unsafeSnapshot[F[_], K, V](m: Map[K, V])(implicit F: Reactive[F]) = {
m match {
case m: SimpleMap[_, _] =>
Expand Down
10 changes: 8 additions & 2 deletions data/jvm/src/main/scala/dev/tauri/choam/data/MapPlatform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ import cats.kernel.{ Hash, Order }
private[data] abstract class MapPlatform extends AbstractMapPlatform {

final override def hashMap[K: Hash, V]: Axn[Map[K, V]] =
Ttrie.apply[K, V]
hashMap(Ref.AllocationStrategy.Default)

final override def hashMap[K: Hash, V](str: Ref.AllocationStrategy): Axn[Map[K, V]] =
Ttrie.apply[K, V](str)

final override def orderedMap[K: Order, V]: Axn[Map[K, V]] =
Ttrie.skipListBased[K, V]
orderedMap(Ref.AllocationStrategy.Default)

final override def orderedMap[K: Order, V](str: Ref.AllocationStrategy): Axn[Map[K, V]] =
Ttrie.skipListBased[K, V](str)

private[data] override def unsafeSnapshot[F[_], K, V](m: Map[K, V])(implicit F: Reactive[F]) = {
m match {
Expand Down
11 changes: 6 additions & 5 deletions data/jvm/src/main/scala/dev/tauri/choam/data/Ttrie.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import Ttrie._
*/
private final class Ttrie[K, V] private (
m: CMap[K, Ref[V]],
str: Ref.AllocationStrategy,
) extends Map.UnsealedMap[K, V] { self =>

/*
Expand Down Expand Up @@ -114,7 +115,7 @@ private final class Ttrie[K, V] private (

private[this] final def getRefWithKey(k: K): Axn[Ref[V]] = {
Axn.unsafe.suspendContext { ctx =>
val newRef = Ref.unsafePadded[V](Init[V], ctx.refIdGen) // TODO: do we really need padded?
val newRef = Ref.unsafe[V](Init[V], str, ctx.refIdGen)
val ref = m.putIfAbsent(k, newRef) match {
case Some(existingRef) =>
existingRef
Expand Down Expand Up @@ -401,20 +402,20 @@ private object Ttrie {
final override def needsCleanup = true
}

def apply[K, V](implicit K: Hash[K]): Axn[Ttrie[K, V]] = {
def apply[K, V](str: Ref.AllocationStrategy)(implicit K: Hash[K]): Axn[Ttrie[K, V]] = {
Axn.unsafe.delay {
val m = new TrieMap[K, Ref[V]](
hashf = { k => byteswap32(K.hash(k)) },
ef = K.eqv(_, _),
)
new Ttrie[K, V](m)
new Ttrie[K, V](m, str)
}
}

def skipListBased[K, V](implicit K: Order[K]): Axn[Ttrie[K, V]] = {
def skipListBased[K, V](str: Ref.AllocationStrategy)(implicit K: Order[K]): Axn[Ttrie[K, V]] = {
Axn.unsafe.delay {
val m = new SkipListMap[K, Ref[V]]()(K)
new Ttrie[K, V](m)
new Ttrie[K, V](m, str)
}
}
}
4 changes: 2 additions & 2 deletions data/jvm/src/test/scala/dev/tauri/choam/data/MapSpecPar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ final class MapSpecPar_TtrieOrder_Emcas_IO

trait MapSpecParTtrieHash[F[_]] extends MapSpecPar[F] { this: McasImplSpec =>
def mkEmptyMap[K : Hash : Order, V]: F[Map[K, V]] =
Ttrie.apply[K, V].run[F].widen
Ttrie.apply[K, V](Ref.AllocationStrategy.Default).run[F].widen
}

trait MapSpecParTtrieOrder[F[_]] extends MapSpecPar[F] { this: McasImplSpec =>
def mkEmptyMap[K : Hash : Order, V]: F[Map[K, V]] =
Ttrie.skipListBased[K, V].run[F].widen
Ttrie.skipListBased[K, V](Ref.AllocationStrategy.Default).run[F].widen
}

trait MapSpecPar[F[_]] extends BaseSpecAsyncF[F] with ScalaCheckEffectSuite { this: McasImplSpec =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ final class RefSpec_Map_SimpleOrdered_SpinLockMcas_IO

trait RefSpec_Map_TtrieHash[F[_]] extends RefSpec_Map_Ttrie[F] { this: McasImplSpec =>
final override def newMap[K : Hash : Order, V]: F[MapType[K, V]] =
Ttrie[K, V].run[F]
Ttrie[K, V](Ref.AllocationStrategy.Default).run[F]
}

trait RefSpec_Map_TtrieOrder[F[_]] extends RefSpec_Map_Ttrie[F] { this: McasImplSpec =>
final override def newMap[K : Hash : Order, V]: F[MapType[K, V]] =
Ttrie.skipListBased[K, V].run[F]
Ttrie.skipListBased[K, V](Ref.AllocationStrategy.Default).run[F]
}

trait RefSpec_Map_Ttrie[F[_]] extends RefSpecMap[F] { this: McasImplSpec =>
Expand Down
4 changes: 2 additions & 2 deletions data/jvm/src/test/scala/dev/tauri/choam/data/mapSpecJvm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ trait MapSpecTtrieHash[F[_]] extends MapSpec[F] { this: McasImplSpec =>
override type MyMap[K, V] = Map[K, V]

def mkEmptyMap[K : Hash : Order, V]: F[Map[K, V]] =
Ttrie.apply[K, V].run[F].widen
Ttrie.apply[K, V](Ref.AllocationStrategy.Default).run[F].widen
}

trait MapSpecTtrieOrder[F[_]] extends MapSpec[F] { this: McasImplSpec =>

override type MyMap[K, V] = Map[K, V]

def mkEmptyMap[K : Hash : Order, V]: F[Map[K, V]] =
Ttrie.skipListBased[K, V].run[F].widen
Ttrie.skipListBased[K, V](Ref.AllocationStrategy.Default).run[F].widen
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ private abstract class AbstractMapPlatform {
def simpleHashMap[K: Hash, V]: Axn[Map.Extra[K, V]]
def simpleOrderedMap[K: Order, V]: Axn[Map.Extra[K, V]]
def hashMap[K: Hash, V]: Axn[Map[K, V]]
def hashMap[K: Hash, V](str: Ref.AllocationStrategy): Axn[Map[K, V]]
def orderedMap[K: Order, V]: Axn[Map[K, V]]
def orderedMap[K: Order, V](str: Ref.AllocationStrategy): Axn[Map[K, V]]
private[data] final def unsafeGetSize[F[_], K, V](m: Map[K, V])(implicit F: Reactive[F]): F[Int] =
F.monad.map(this.unsafeSnapshot(m))(_.size)
private[data] def unsafeSnapshot[F[_], K, V](m: Map[K, V])(implicit F: Reactive[F]): F[ScalaMap[K, V]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ import cats.kernel.Hash
object MapHelper {

def ttrie[K: Hash, V]: Axn[Map[K, V]] =
Ttrie.apply[K, V]
Ttrie.apply[K, V](Ref.AllocationStrategy.Default)
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ private[data] object TtrieModelTest {

class TrieMapTestState extends AbstractTestState {
protected[this] override val m: Ttrie[String, String] =
Ttrie[String, String].unsafeRun(emcas)
Ttrie[String, String](Ref.AllocationStrategy.Default).unsafeRun(emcas)
}

class SkipListTestState extends AbstractTestState {
protected[this] override val m: Ttrie[String, String] =
Ttrie.skipListBased[String, String].flatMapF { (m: Ttrie[String, String]) =>
Ttrie.skipListBased[String, String](Ref.AllocationStrategy.Default).flatMapF { (m: Ttrie[String, String]) =>
m.get.provide("dummy").as(m) // FIXME?
}.unsafeRun(emcas)
}
Expand Down

0 comments on commit 86041df

Please sign in to comment.