Skip to content

Commit

Permalink
remove patch based implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Bob R committed Mar 10, 2017
1 parent 6ee6233 commit 5d67174
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 129 deletions.
120 changes: 38 additions & 82 deletions collection/shared/src/main/scala/hokko/collection/DeltaADT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import scala.collection.{
}

object Delta {

def combineDelta[El, Coll](d1: Delta[El, Coll],
d2: Delta[El, Coll]): Delta[El, Coll] =
(d1, d2) match {
Expand Down Expand Up @@ -39,31 +40,24 @@ object Delta {
case Id() => acc
case Combined(d1, d2) =>
applyFoldUndo(applyFoldUndo(acc, d1, op, undo), d2, op, undo)
case Concat(others) => others.foldLeft(acc)(op)
case p @ Patch(_, patch, _, removed) =>
val accWithNewElements = patch.foldLeft(acc)(op)
removed.foldLeft(accWithNewElements)(undo)
case Concat(others) => others.foldLeft(acc)(op)
case u @ Updated(_, previous, next) => undo(op(acc, next), previous)
case p @ Prepend(el) => op(acc, el)
case a @ Append(el) => op(acc, el)
}
}

def map[A, B, Repr[_]](delta: Delta[A, Repr[A]], f: A => B)(
implicit cbfMap: CanBuildFrom[Repr[A], B, Repr[B]],
cbfDelta: CanBuildFrom[Repr[B], B, Repr[B]]): Delta[B, Repr[B]] =
delta match {
case Id() => Id()
case Combined(d1, d2) => combineDelta(map(d1, f), map(d2, f))
case c @ Concat(_) => c.map(f)
case p @ Patch(_, _, _, _) => p.map(f)
case Id() => Id()
case Combined(d1, d2) => combineDelta(map(d1, f), map(d2, f))
case c @ Concat(_) => c.map(f)
case u @ Updated(_, _, _) => u.map(f)
case p @ Prepend(_) => p.map(f)
case a @ Append(_) => a.map(f)
}

// def filter[A, Repr[_]](delta: Delta[A, Repr[A]],
// p: A => Boolean): Delta[A, Repr[A]] =
// delta match {
// case Id() => Id()
// case Combined(d1, d2) => combineDelta(filter(d1, p), filter(d2, p))
// case c @ Concat(_) => c.filter(p)
// case p @ Patch(_, _, _, _) => p.filter(p)
// }
}

sealed trait Delta[+El, Coll] {
Expand Down Expand Up @@ -95,80 +89,42 @@ case class Concat[A0, Repr[A] <: TraversableLike[A, Repr[A]]](
def map[B](f: A0 => B)(
implicit cbfMap: CanBuildFrom[Repr[B], B, Repr[B]]): Concat[B, Repr] =
Concat(that.map(f))
}

case class Append[A0, Repr[A] <: SeqLike[A, Repr[A]]](el: A0)(
implicit canBuildFrom: CanBuildFrom[Repr[A0], A0, Repr[A0]]
) extends Delta[A0, Repr[A0]] {
def apply(c: Repr[A0]): Repr[A0] = c :+ el
def mapIndex(f: (Int) => Int): Delta[A0, Repr[A0]] = ???

def map[B](f: A0 => B)(
implicit cbfMap: CanBuildFrom[Repr[B], B, Repr[B]]): Append[B, Repr] =
Append(f(el))
}

// def filter[B](p: A0 => B)(implicit cbfMap: CanBuildFrom[Repr[B], B, Repr[B]])
// : Delta[B, Repr[B]] = {
// val filtered = that.filter(p)
// if (filtered.isEmpty) Id()
// else Concat(filtered)
// }
case class Prepend[A0, Repr[A] <: SeqLike[A, Repr[A]]](el: A0)(
implicit canBuildFrom: CanBuildFrom[Repr[A0], A0, Repr[A0]]
) extends Delta[A0, Repr[A0]] {
def apply(c: Repr[A0]): Repr[A0] = el +: c
def mapIndex(f: (Int) => Int): Delta[A0, Repr[A0]] = ???

def map[B](f: A0 => B)(
implicit cbfMap: CanBuildFrom[Repr[B], B, Repr[B]]): Prepend[B, Repr] =
Prepend(f(el))
}

case class Patch[A0, Repr[A] <: SeqLike[A, Repr[A]]](
from: Int,
patch: GenSeq[A0],
replaced: Int,
removedElements: TraversableOnce[A0])(
case class Updated[A0, Repr[A] <: SeqLike[A, Repr[A]]](index: Int,
previous: A0,
next: A0)(
implicit cbf: CanBuildFrom[Repr[A0], A0, Repr[A0]]
) extends Delta[A0, Repr[A0]] {
override def apply(c: Repr[A0]): Repr[A0] =
c.patch(from, patch, replaced)
c.updated(index, next)

override def mapIndex(f: (Int) => Int) = this.copy(from = f(this.from))
override def mapIndex(f: (Int) => Int) = this.copy(index = f(this.index))

def map[B](f: A0 => B)(
implicit cbfMap: CanBuildFrom[Repr[B], B, Repr[B]]): Patch[B, Repr] = {
Patch(from, patch.map(f), replaced, removedElements.map(f))
implicit cbfMap: CanBuildFrom[Repr[B], B, Repr[B]]): Updated[B, Repr] = {
Updated(index, f(previous), f(next))
}

// def filter[B](p: A0 => B)(implicit cbfMap: CanBuildFrom[Repr[B], B, Repr[B]])
// : Delta[B, Repr[B]] = {
// val filtered = patch.filter(p)
// if (filtered.isEmpty) Id()
// else {}
// }
}

//
//// def filter[A](f: A => Boolean)(d: Delta[A]): Delta[A] = d match {
//// case Empty => Empty
//// case Update(pel, nel, idx) =>
//// if (f(nel)) Update(pel, nel, idx)
//// else Remove(pel, idx)
//// case Insert(el, idx) =>
//// if (f(el)) Insert(el, idx)
//// else Remove(el, idx)
//// case Remove(el, idx) =>
//// Remove(el, idx)
//// case Combined(d1, d2) => combine(filter(f)(d), filter(f)(d))
//// }
//
// def map[A, B](d: Delta[A])(f: (A, Int) => (B, Int)): Delta[B] =
// d match {
// case Combined(d1, d2) => combine(map(d1)(f), map(d2)(f))
// case Update(pel, nel, idx) =>
// val (pel0, newIdx) = f(pel, idx)
// val (nel0, _) = f(nel, idx)
// Update(pel0, nel0, newIdx)
// case Insert(a, idx) =>
// val (b, newIdx) = f(a, idx)
// Insert(b, newIdx)
// case Remove(a, idx) =>
// val (b, newIdx) = f(a, idx)
// Remove(b, newIdx)
// case Empty => Empty
// }
//
// def mapIndex[A](d: Delta[A])(f: Int => Int): Delta[A] =
// map(d) { (el, idx) =>
// (el, f(idx))
// }
//
// def mapElement[A, B](d: Delta[A])(f: A => B): Delta[B] =
// map(d) { (el, idx) =>
// (f(el), idx)
// }
//
// def translate[A](d: Delta[A], sum: Int): Delta[A] =
// mapIndex(d)(_ + sum)
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,33 @@ trait SeqIBehaviorOps {
implicit class SeqIBehavior[A0, Repr[A0] <: SeqLike[A0, Repr[A0]]](
rep: ICollection[A0, Repr[A0]])(implicit isl: IslAux[Repr[A0], A0]) {

def patch(patches: Event[(Int, GenSeq[A0], Int)])(
private def pendOperation(pend: Event[A0])(f: A0 => Delta[A0, Repr[A0]]) = {
val prependsDelta = pend.map(f)
val newDeltas = Delta.combine(rep.deltas, prependsDelta)
Delta.foldApply(rep.initial, newDeltas)
}

def :+(append: Event[A0])(
implicit cbf: CanBuildFrom[Repr[A0], A0, Repr[A0]])
: ICollection[A0, Repr[A0]] =
pendOperation(append)(Append.apply[A0, Repr])

def +:(prepends: Event[A0])(
implicit cbf: CanBuildFrom[Repr[A0], A0, Repr[A0]])
: ICollection[A0, Repr[A0]] =
pendOperation(prepends)(Prepend.apply[A0, Repr])

def updated(updates: Event[(Int, A0)])(
implicit cbf: CanBuildFrom[Repr[A0], A0, Repr[A0]])
: ICollection[A0, Repr[A0]] = {

// map deltas and patches onto left and right
val lefties =
rep.deltas.map(Ior.left[Delta[A0, Repr[A0]], (Int, GenSeq[A0], Int)])
rep.deltas.map(Ior.left[Delta[A0, Repr[A0]], (Int, A0)])
val righties =
patches.map(Ior.right[Delta[A0, Repr[A0]], (Int, GenSeq[A0], Int)])
updates.map(Ior.right[Delta[A0, Repr[A0]], (Int, A0)])

// combine deltas and patches into one event (simultaneous occurences
// combine deltas and updates into one event (simultaneous occurences
// are merged into Ior.both
val combined = lefties.unionWith(righties) {
case (Ior.Left(delta), Ior.Right(prepatch)) =>
Expand All @@ -32,9 +48,9 @@ trait SeqIBehaviorOps {
// fold combined deltas and patches into an incremental behavior that
// tracks both the value as well as any patches that were applied
// 1. start with (initial value, None)
val ib: IBehavior[(Repr[A0], Option[Patch[A0, Repr]]),
Ior[Delta[A0, Repr[A0]], (Int, GenSeq[A0], Int)]] =
combined.fold(rep.initial -> Option.empty[Patch[A0, Repr]]) {
val ib: IBehavior[(Repr[A0], Option[Updated[A0, Repr]]),
Ior[Delta[A0, Repr[A0]], (Int, A0)]] =
combined.fold(rep.initial -> Option.empty[Updated[A0, Repr]]) {
(acc, ior) =>
ior match {
// 2. delta (left) => (apply to previous value, None)
Expand All @@ -43,19 +59,15 @@ trait SeqIBehaviorOps {
// a) calculate removed elements
// b) create patch delta
// c) (apply patch, patch)
case Ior.Right((from, newElements, replaced)) =>
val oldElements = acc._1.slice(from, from + replaced)
val patch =
Patch[A0, Repr](from, newElements, replaced, oldElements)
patch(acc._1) -> Some(patch)
case Ior.Right((idx, next)) =>
val update = Updated[A0, Repr](idx, acc._1(idx), next)
update(acc._1) -> Some(update)
// 4. new delta and patch =>
// repeat 3.
// (apply patch apply delta, patch)
case Ior.Both(delta, (from, newElements, replaced)) =>
val oldElements = acc._1.slice(from, from + replaced)
val patch =
Patch[A0, Repr](from, newElements, replaced, oldElements)
patch(delta(acc._1)) -> Some(patch)
case Ior.Both(delta, (idx, next)) =>
val update = Updated[A0, Repr](idx, acc._1(idx), next)
update(delta(acc._1)) -> Some(update)
}
}

Expand All @@ -78,29 +90,5 @@ trait SeqIBehaviorOps {
x(acc)
}
}

def :+(appends: Event[A0])(
implicit cbf: CanBuildFrom[Repr[A0], A0, Repr[A0]])
: ICollection[A0, Repr[A0]] = {
val nbAppends = appends.fold(0) { (acc, _) =>
acc + 1
}
val size = rep.toDBehavior.map2(nbAppends.toDBehavior)(_.length + _)

val patches = size.snapshotWith(appends) { (size, newElement) =>
(size, List(newElement), 0)
}
patch(patches)
}

def +:(prepends: Event[A0])(
implicit cbf: CanBuildFrom[Repr[A0], A0, Repr[A0]])
: ICollection[A0, Repr[A0]] =
patch(prepends.map(x => (0, List(x), 0)))

def updated(updates: Event[(Int, A0)])(
implicit cbf: CanBuildFrom[Repr[A0], A0, Repr[A0]])
: ICollection[A0, Repr[A0]] =
patch(updates.map { case (idx, el) => (idx, List(el), 1) })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@ trait TraversableIBehaviorOps {
foldedIBehavior.toDBehavior
}

// def filter(p: A0 => Boolean): ICollection[A0, Repr[A0]] = {
// rep.incMap(_ filter p)(Delta.filter(_, p)) { (repr, delta) =>
// delta.apply(repr)
// }
// }

def map[B, That](f: A0 => B)(
implicit cbf: CanBuildFrom[Repr[A0], B, Repr[B]],
cbfDelta: CanBuildFrom[Repr[B], B, Repr[B]],
Expand Down

0 comments on commit 5d67174

Please sign in to comment.