All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.reactors.common.QuadMatrix.scala Maven / Gradle / Ivy

The newest version!
package io.reactors
package common



import io.reactors.algebra._



/** Quad-based matrix for spatial querying of sparse data.
 */
class QuadMatrix[@specialized(Int, Long, Double) T](
  private[reactors] val blockExponent: Int = 8,
  private[reactors] val poolSize: Int = 32
)(
  implicit val arrayable: Arrayable[T]
) extends Matrix[T] {
  private[reactors] var blockSize: Int = _
  private[reactors] var blockMask: Int = _
  private[reactors] var removedValue: T = _
  private[reactors] var roots: HashMatrix[QuadMatrix.Node[T]] = _
  private[reactors] var empty: QuadMatrix.Node.Empty[T] = _
  private[reactors] var forkPool: FixedSizePool[QuadMatrix.Node.Fork[T]] = _
  private[reactors] var leafPool: FixedSizePool[QuadMatrix.Node.Leaf[T]] = _
  private[reactors] var flatPool: FixedSizePool[QuadMatrix.Node.Flat[T]] = _
  val nil = arrayable.nil

  private[reactors] def init(self: QuadMatrix[T]) {
    roots = new HashMatrix[QuadMatrix.Node[T]]
    blockSize = 1 << blockExponent
    blockMask = blockSize - 1
    empty = new QuadMatrix.Node.Empty[T]
    forkPool = new FixedSizePool(
      poolSize,
      () => QuadMatrix.Node.Fork.empty(this),
      n => n.clear(self))
    leafPool = new FixedSizePool(
      poolSize,
      () => QuadMatrix.Node.Leaf.empty[T],
      n => n.clear())
    flatPool = new FixedSizePool(
      poolSize,
      () => QuadMatrix.Node.Flat.empty[T],
      n => {})
    removedValue = nil
  }
  init(this)

  private[reactors] def fillPools(self: QuadMatrix[T]) {
    var i = 0
    while (i < poolSize) {
      forkPool.release(QuadMatrix.Node.Fork.empty(self))
      leafPool.release(QuadMatrix.Node.Leaf.empty[T])
      flatPool.release(QuadMatrix.Node.Flat.empty[T])
      i += 1
    }
  }

  private[reactors] def isTopLevelLeafAt(gx: Int, gy: Int): Boolean = {
    val bx = gx >> blockExponent
    val by = gy >> blockExponent
    val quad = roots(bx, by)
    quad != null && quad.isLeaf
  }

  private[reactors] def release(n: QuadMatrix.Node[T]) = n match {
    case l: QuadMatrix.Node.Leaf[T] => leafPool.release(l)
    case f: QuadMatrix.Node.Fork[T] => forkPool.release(f)
    case f: QuadMatrix.Node.Flat[T] => flatPool.release(f)
    case _ => // Not releasing Empty nodes.
  }

  def fillPools() {
    fillPools(this)
  }

  def update(gx: Int, gy: Int, v: T): Unit = applyAndUpdate(gx, gy, v)

  def applyAndUpdate(gx: Int, gy: Int, v: T): T = {
    if (v == nil) remove(gx, gy)
    else {
      val bx = gx >> blockExponent
      val by = gy >> blockExponent
      val qx = gx & blockMask
      val qy = gy & blockMask
      var root = roots(bx, by)
      if (root == null) {
        root = empty
        roots(bx, by) = root
      }
      val nroot = root.update(qx, qy, v, blockExponent, this)
      if (root ne nroot) {
        roots(bx, by) = nroot
      }
      val prev = removedValue
      if (removedValue != nil) removedValue = nil
      prev
    }
  }

  def remove(gx: Int, gy: Int): T = {
    val bx = gx >> blockExponent
    val by = gy >> blockExponent
    val qx = gx & blockMask
    val qy = gy & blockMask
    val root = roots(bx, by)
    if (root == null) nil
    else {
      val nroot = root.remove(qx, qy, blockExponent, this)
      if (nroot ne root) {
        roots(bx, by) = nroot
        release(root)
      }
      if (nroot.isEmpty) roots.remove(bx, by)
      val prev = removedValue
      removedValue = nil
      prev
    }
  }

  protected def clearSpecialized(self: QuadMatrix[T]) {
    roots.clear()
  }

  def clear() {
    clearSpecialized(this)
  }

  def apply(gx: Int, gy: Int): T = {
    val bx = gx >> blockExponent
    val by = gy >> blockExponent
    val qx = gx & blockMask
    val qy = gy & blockMask
    val root = roots(bx, by)
    if (root == null) nil
    else root.apply(qx, qy, blockExponent, this)
  }

  def orElse(xr: Int, yr: Int, v: T): T = {
    val cur = apply(xr, yr)
    if (cur != nil) cur else v
  }

  def foreach(f: XY => Unit): Unit = {
    for (rxy <- roots) {
      val root = roots(rxy.x, rxy.y)
      val x0 = rxy.x << blockExponent
      val y0 = rxy.y << blockExponent
      root.foreach(blockExponent, x0, y0, f)
    }
  }

  def copy(a: Array[T], gxf: Int, gyf: Int, gxu: Int, gyu: Int): Unit = {
    new QuadMatrix.Area[T](this, gxf, gyf, gxu, gyu, true).copy(a)
  }

  def area(gxf: Int, gyf: Int, gxu: Int, gyu: Int): Matrix.Area[T] =
    new QuadMatrix.Area[T](this, gxf, gyf, gxu, gyu, true)

  def nonNilArea(gxf: Int, gyf: Int, gxu: Int, gyu: Int): Matrix.Area[T] =
    new QuadMatrix.Area[T](this, gxf, gyf, gxu, gyu, false)
}


object QuadMatrix {
  private[reactors] class Area[@specialized(Int, Long, Double) T](
    val self: QuadMatrix[T], val gxf: Int, val gyf: Int, val gxu: Int, val gyu: Int,
    val includeNil: Boolean
  ) extends Matrix.Area[T] {
    def foreach(a: Matrix.Action[T]) {
      val exp = self.blockExponent
      var byc = gyf >> exp
      val byt = gyu >> exp
      while (byc <= byt) {
        var bxc = gxf >> exp
        val bxt = gxu >> exp
        while (bxc <= bxt) {
          val root = self.roots(bxc, byc)
          if (root != null) {
            root.areaForeach(
              math.max(bxc << exp, gxf),
              math.max(byc << exp, gyf),
              math.min((bxc << exp) + (1 << exp), gxu),
              math.min((byc << exp) + (1 << exp), gyu),
              (bxc << exp) + (1 << (exp - 1)),
              (byc << exp) + (1 << (exp - 1)),
              1 << (exp - 1),
              a, includeNil, self.nil)
          } else {
            if (includeNil) {
              foreachNil(
                math.max(bxc << exp, gxf),
                math.max(byc << exp, gyf),
                math.min((bxc << exp) + (1 << exp), gxu),
                math.min((byc << exp) + (1 << exp), gyu),
                a)
            }
          }
          bxc += 1
        }
        byc += 1
      }
    }

    def copy(a: Array[T]) {
      val width = gxu - gxf
      val exp = self.blockExponent
      var byc = gyf >> exp
      val byt = gyu >> exp
      while (byc <= byt) {
        var bxc = gxf >> exp
        val bxt = gxu >> exp
        while (bxc <= bxt) {
          val root = self.roots(bxc, byc)
          if (root != null) {
            root.copy(
              math.max(bxc << exp, gxf),
              math.max(byc << exp, gyf),
              math.min((bxc << exp) + (1 << exp), gxu),
              math.min((byc << exp) + (1 << exp), gyu),
              (bxc << exp) + (1 << (exp - 1)),
              (byc << exp) + (1 << (exp - 1)),
              1 << (exp - 1),
              a, this, self.nil)
          } else {
            copyNil(
              math.max(bxc << exp, gxf),
              math.max(byc << exp, gyf),
              math.min((bxc << exp) + (1 << exp), gxu),
              math.min((byc << exp) + (1 << exp), gyu),
              gxf, gyf, width, a)
          }
          bxc += 1
        }
        byc += 1
      }
    }

    def foreachNil(gxf: Int, gyf: Int, gxu: Int, gyu: Int, a: Matrix.Action[T]) {
      val nil = self.nil
      var y = gyf
      while (y < gyu) {
        var x = gxf
        while (x < gxu) {
          a(x, y, nil)
          x += 1
        }
        y += 1
      }
    }

    def copyNil(gxf: Int, gyf: Int, gxu: Int, gyu: Int, x0: Int, y0: Int, width: Int,
      a: Array[T]) {
      val nil = self.nil
      var y = gyf
      while (y < gyu) {
        var x = gxf
        while (x < gxu) {
          a((y - y0) * width + (x - x0)) = nil
          x += 1
        }
        y += 1
      }
    }
  }

  trait Node[@specialized(Int, Long, Double) T] {
    def isEmpty: Boolean
    def isLeaf: Boolean
    def apply(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): T
    def update(x: Int, y: Int, v: T, exp: Int, self: QuadMatrix[T]): Node[T]
    def remove(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): Node[T]
    def foreach(exp: Int, x0: Int, y0: Int, f: XY => Unit): Unit
    def areaForeach(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
      hsz: Int, a: Matrix.Action[T], includeNil: Boolean, nil: T): Unit
    def copy(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
      hsz: Int, a: Array[T], area: Area[T], nil: T): Unit
  }

  object Node {
    class Empty[@specialized(Int, Long, Double) T]
    extends Node[T] {
      def isEmpty = true
      def isLeaf = false
      def apply(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): T =
        self.arrayable.nil
      def update(x: Int, y: Int, v: T, exp: Int, self: QuadMatrix[T]): Node[T] = {
        val leaf = self.leafPool.acquire()
        leaf.update(x, y, v, exp, self)
        leaf
      }
      def remove(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): Node[T] = this
      def foreach(exp: Int, x0: Int, y0: Int, f: XY => Unit): Unit = {}
      def areaForeach(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
        hsz: Int, a: Matrix.Action[T], includeNil: Boolean, nil: T) {
        if (includeNil) {
          var y = gyf
          while (y < gyu) {
            var x = gxf
            while (x < gxu) {
              a(x, y, nil)
              x += 1
            }
            y += 1
          }
        }
      }
      def copy(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
        hsz: Int, a: Array[T], area: Area[T], nil: T): Unit = {
        val x0 = area.gxf
        val y0 = area.gyf
        val width = area.gxu - x0
        var y = gyf
        while (y < gyu) {
          var x = gxf
          while (x < gxu) {
            a((y - y0) * width + (x - x0)) = nil
            x += 1
          }
          y += 1
        }
      }
    }

    class Fork[@specialized(Int, Long, Double) T]
    extends Node[T] {
      private[reactors] var children: Array[Node[T]] = _

      private[reactors] def init(self: Fork[T]) {
        children = new Array(4)
      }
      init(this)

      def isEmpty = false

      def isLeaf = false

      def clear(self: QuadMatrix[T]) {
        children(0) = self.empty
        children(1) = self.empty
        children(2) = self.empty
        children(3) = self.empty
      }

      def apply(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): T = {
        val nexp = exp - 1
        val xidx = x >>> nexp
        val yidx = y >>> nexp
        val idx = (yidx << 1) + (xidx)
        val nx = x - (xidx << nexp)
        val ny = y - (yidx << nexp)
        children(idx).apply(nx, ny, nexp, self)
      }

      def update(x: Int, y: Int, v: T, exp: Int, self: QuadMatrix[T]): Node[T] = {
        val nexp = exp - 1
        val xidx = x >>> nexp
        val yidx = y >>> nexp
        val idx = (yidx << 1) + (xidx)
        val nx = x - (xidx << nexp)
        val ny = y - (yidx << nexp)
        val child = children(idx)
        val nchild = child.update(nx, ny, v, nexp, self)
        if (child ne nchild) {
          children(idx) = nchild
          self.release(child)
        }
        this
      }

      def remove(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): Node[T] = {
        val nexp = exp - 1
        val xidx = x >>> nexp
        val yidx = y >>> nexp
        val idx = (yidx << 1) + (xidx)
        val nx = x - (xidx << nexp)
        val ny = y - (yidx << nexp)
        val child = children(idx)
        val nchild = child.remove(nx, ny, nexp, self)
        if (child ne nchild) {
          children(idx) = nchild
          self.release(child)
          if (nchild.isEmpty || nchild.isLeaf) {
            val cs = children
            var emptynum = 0
            if (cs(0).isEmpty) emptynum += 1
            if (cs(1).isEmpty) emptynum += 1
            if (cs(2).isEmpty) emptynum += 1
            if (cs(3).isEmpty) emptynum += 1
            if (emptynum == cs.length) self.empty
            else if (emptynum == cs.length - 1) {
              var i = 0
              while (i < cs.length) {
                if (cs(i).isInstanceOf[Leaf[_]]) {
                  val leaf = cs(i).asInstanceOf[Leaf[T]]
                  leaf.rise((i % 2) * (1 << nexp), (i / 2) * (1 << nexp))
                  return leaf
                }
                i += 1
              }
              this
            } else this
          } else this
        } else this
      }

      def foreach(exp: Int, x0: Int, y0: Int, f: XY => Unit): Unit = {
        val nexp = exp - 1
        val m = 1 << nexp
        children(0).foreach(nexp, x0, y0, f)
        children(1).foreach(nexp, x0 + m, y0, f)
        children(2).foreach(nexp, x0, y0 + m, f)
        children(3).foreach(nexp, x0 + m, y0 + m, f)
      }

      def areaForeach(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
        hsz: Int, a: Matrix.Action[T], includeNil: Boolean, nil: T) {
        val nhsz = hsz >> 1
        if (gxf < gxm && gyf < gym)
          children(0).areaForeach(
            gxf, gyf, math.min(gxm, gxu), math.min(gym, gyu),
            gxm - nhsz, gym - nhsz, nhsz, a, includeNil, nil)
        if (gxu >= gxm && gyf < gym)
          children(1).areaForeach(
            math.max(gxf, gxm), gyf, gxu, math.min(gym, gyu),
            gxm + nhsz, gym - nhsz, nhsz, a, includeNil, nil)
        if (gxf < gxm && gyu >= gym)
          children(2).areaForeach(
            gxf, math.max(gyf, gym), math.min(gxm, gxu), gyu,
            gxm - nhsz, gym + nhsz, nhsz, a, includeNil, nil)
        if (gxu >= gxm && gyu >= gym)
          children(3).areaForeach(
            math.max(gxf, gxm), math.max(gyf, gym), gxu, gyu,
            gxm + nhsz, gym + nhsz, nhsz, a, includeNil, nil)
      }

      def copy(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
        hsz: Int, a: Array[T], area: Area[T], nil: T): Unit = {
        val nhsz = hsz >> 1
        if (gxf < gxm && gyf < gym)
          children(0).copy(
            gxf, gyf, math.min(gxm, gxu), math.min(gym, gyu),
            gxm - nhsz, gym - nhsz, nhsz, a, area, nil)
        if (gxu >= gxm && gyf < gym)
          children(1).copy(
            math.max(gxf, gxm), gyf, gxu, math.min(gym, gyu),
            gxm + nhsz, gym - nhsz, nhsz, a, area, nil)
        if (gxf < gxm && gyu >= gym)
          children(2).copy(
            gxf, math.max(gyf, gym), math.min(gxm, gxu), gyu,
            gxm - nhsz, gym + nhsz, nhsz, a, area, nil)
        if (gxu >= gxm && gyu >= gym)
          children(3).copy(
            math.max(gxf, gxm), math.max(gyf, gym), gxu, gyu,
            gxm + nhsz, gym + nhsz, nhsz, a, area, nil)
      }
    }

    object Fork {
      def empty[@specialized(Int, Long, Double) T](quad: QuadMatrix[T]) = {
        val fork = new Fork[T]
        fork.clear(quad)
        fork
      }
    }

    class Leaf[@specialized(Int, Long, Double) T](
      implicit val arrayable: Arrayable[T]
    ) extends Node[T] {
      private[reactors] var coordinates: Array[Int] = _
      private[reactors] var elements: Array[T] = _

      private[reactors] def init(self: Leaf[T]) {
        coordinates = new Array(8)
        elements = arrayable.newArray(4)
      }
      init(this)

      def isEmpty = false

      def isLeaf = true

      def apply(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): T = {
        var i = 0
        val nil = self.nil
        while (i < elements.length && elements(i) != nil) {
          val cx = coordinates(i * 2 + 0)
          val cy = coordinates(i * 2 + 1)
          if (cx == x && cy == y) {
            return elements(i)
          }
          i += 1
        }
        self.arrayable.nil
      }

      def update(x: Int, y: Int, v: T, exp: Int, self: QuadMatrix[T]): Node[T] = {
        var i = 0
        val nil = self.nil
        while (i < elements.length && elements(i) != nil) {
          val cx = coordinates(i * 2 + 0)
          val cy = coordinates(i * 2 + 1)
          if (cx == x && cy == y) {
            self.removedValue = elements(i)
            elements(i) = v
            return this
          }
          i += 1
        }
        if (i < elements.length) {
          elements(i) = v
          coordinates(i * 2 + 0) = x
          coordinates(i * 2 + 1) = y
          return this
        } else {
          assert(exp >= 2)
          var forkOrFlat: Node[T] = {
            if (exp > 2) self.forkPool.acquire()
            else self.flatPool.acquire()
          }
          var i = 0
          while (i < elements.length) {
            val cx = coordinates(i * 2 + 0)
            val cy = coordinates(i * 2 + 1)
            val cv = elements(i)
            forkOrFlat = forkOrFlat.update(cx, cy, cv, exp, self)
            i += 1
          }
          forkOrFlat = forkOrFlat.update(x, y, v, exp, self)
          forkOrFlat
        }
      }

      def remove(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): Node[T] = {
        val nil = self.nil
        var i = elements.length - 1
        var lasti = -1
        while (i >= 0) {
          val elem = elements(i)
          if (elem != nil) {
            val cx = coordinates(i * 2 + 0)
            val cy = coordinates(i * 2 + 1)
            if (cx == x && cy == y) {
              self.removedValue = elem
              if (lasti != -1) {
                elements(i) = elements(lasti)
                elements(lasti) = nil
                coordinates(i * 2 + 0) = coordinates(lasti * 2 + 0)
                coordinates(i * 2 + 1) = coordinates(lasti * 2 + 1)
                return this
              } else {
                elements(i) = nil
                if (i == 0) return self.empty
                else return this
              }
            }
            if (lasti == -1) lasti = i
          }
          i -= 1
        }
        return this
      }

      def rise(x: Int, y: Int) {
        var i = 0
        val nil = arrayable.nil
        while (i < elements.length && elements(i) != nil) {
          coordinates(i * 2 + 0) += x
          coordinates(i * 2 + 1) += y
          i += 1
        }
      }

      def clear() {
        val nil = arrayable.nil
        elements(0) = nil
        elements(1) = nil
        elements(2) = nil
        elements(3) = nil
      }

      def foreach(exp: Int, x0: Int, y0: Int, f: XY => Unit): Unit = {
        var i = 0
        val nil = arrayable.nil
        while (i < elements.length && elements(i) != nil) {
          val x = x0 + coordinates(i * 2 + 0)
          val y = y0 + coordinates(i * 2 + 1)
          f(XY(x, y))
          i += 1
        }
      }

      def areaForeach(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
        hsz: Int, a: Matrix.Action[T], includeNil: Boolean, nil: T) {
        if (!includeNil) {
          var i = 0
          while (i < elements.length && elements(i) != nil) {
            val cx = gxm - hsz + coordinates(i * 2 + 0)
            val cy = gym - hsz + coordinates(i * 2 + 1)
            if (cx >= gxf && cx < gxu && cy >= gyf && cy < gyu) {
              a(cx, cy, elements(i))
            }
            i += 1
          }
        } else {
          val cx0 = gxm - hsz + coordinates(0 * 2 + 0)
          val cy0 = gym - hsz + coordinates(0 * 2 + 1)
          val cx1 = gxm - hsz + coordinates(1 * 2 + 0)
          val cy1 = gym - hsz + coordinates(1 * 2 + 1)
          val cx2 = gxm - hsz + coordinates(2 * 2 + 0)
          val cy2 = gym - hsz + coordinates(2 * 2 + 1)
          val cx3 = gxm - hsz + coordinates(3 * 2 + 0)
          val cy3 = gym - hsz + coordinates(3 * 2 + 1)
          var y = gyf
          while (y < gyu) {
            var x = gxf
            while (x < gxu) {
              if (x == cx0 && y == cy0) a(x, y, elements(0))
              else if (x == cx1 && y == cy1) a(x, y, elements(1))
              else if (x == cx2 && y == cy2) a(x, y, elements(2))
              else if (x == cx3 && y == cy3) a(x, y, elements(3))
              else a(x, y, nil)
              x += 1
            }
            y += 1
          }
        }
      }

      def copy(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
        hsz: Int, a: Array[T], area: Area[T], nil: T): Unit = {
        val cx0 = gxm - hsz + coordinates(0 * 2 + 0)
        val cy0 = gym - hsz + coordinates(0 * 2 + 1)
        val cx1 = gxm - hsz + coordinates(1 * 2 + 0)
        val cy1 = gym - hsz + coordinates(1 * 2 + 1)
        val cx2 = gxm - hsz + coordinates(2 * 2 + 0)
        val cy2 = gym - hsz + coordinates(2 * 2 + 1)
        val cx3 = gxm - hsz + coordinates(3 * 2 + 0)
        val cy3 = gym - hsz + coordinates(3 * 2 + 1)
        val x0 = area.gxf
        val y0 = area.gyf
        val width = area.gxu - x0
        var y = gyf
        while (y < gyu) {
          var x = gxf
          while (x < gxu) {
            val idx = (y - y0) * width + (x - x0)
            if (x == cx0 && y == cy0) a(idx) = elements(0)
            else if (x == cx1 && y == cy1) a(idx) = elements(1)
            else if (x == cx2 && y == cy2) a(idx) = elements(2)
            else if (x == cx3 && y == cy3) a(idx) = elements(3)
            else a(idx) = nil
            x += 1
          }
          y += 1
        }
      }
    }

    object Leaf {
      def empty[@specialized(Int, Long, Double) T: Arrayable] = new Leaf[T]
    }

    class Flat[@specialized(Int, Long, Double) T](
      implicit val arrayable: Arrayable[T]
    ) extends Node[T] {
      private[reactors] var matrix: Array[T] = _
      private[reactors] var count: Int =_

      private[reactors] def init(self: Flat[T]) {
        matrix = arrayable.newArray(16)
        count = 0
      }
      init(this)

      def isEmpty = false

      def isLeaf = false

      def apply(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): T =
        matrix(y * 4 + x)

      def update(x: Int, y: Int, v: T, exp: Int, self: QuadMatrix[T]): Node[T] = {
        val nil = self.nil
        val prev = matrix(y * 4 + x)
        matrix(y * 4 + x) = v
        if (prev != nil) count -= 1
        if (v != nil) count += 1
        this
      }

      def remove(x: Int, y: Int, exp: Int, self: QuadMatrix[T]): Node[T] = {
        val nil = self.nil
        val prev = matrix(y * 4 + x)
        if (prev != nil) {
          self.removedValue = prev
          matrix(y * 4 + x) = nil
          count -= 1
          if (count <= 2) {
            var leaf: Node[T] = self.leafPool.acquire()
            var y = 0
            while (y < 4) {
              var x = 0
              while (x < 4) {
                val v = matrix(y * 4 + x)
                if (v != nil) {
                  leaf = leaf.update(x, y, v, exp, self)
                  matrix(y * 4 + x) = nil
                }
                x += 1
              }
              y += 1
            }
            leaf
          } else this
        } else this
      }

      def foreach(exp: Int, x0: Int, y0: Int, f: XY => Unit): Unit = {
        var y = 0
        while (y < 4) {
          var x = 0
          while (x < 4) {
            f(XY(x0 + x, y0 + y))
            x += 1
          }
          y += 1
        }
      }

      def areaForeach(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
        hsz: Int, a: Matrix.Action[T], includeNil: Boolean, nil: T) {
        var y = gyf
        while (y < gyu) {
          var x = gxf
          while (x < gxu) {
            val cx = x - (gxm - hsz)
            val cy = y - (gym - hsz)
            val v = matrix(cy * 4 + cx)
            if (includeNil || v != nil) a(x, y, v)
            x += 1
          }
          y += 1
        }
      }

      def copy(gxf: Int, gyf: Int, gxu: Int, gyu: Int, gxm: Int, gym: Int,
        hsz: Int, a: Array[T], area: Area[T], nil: T): Unit = {
        val x0 = area.gxf
        val y0 = area.gyf
        val width = area.gxu - x0
        var y = gyf
        while (y < gyu) {
          var x = gxf
          while (x < gxu) {
            val cx = x - (gxm - hsz)
            val cy = y - (gym - hsz)
            val v = matrix(cy * 4 + cx)
            a((y - y0) * width + (x - x0)) = v
            x += 1
          }
          y += 1
        }
      }
    }

    object Flat {
      def empty[@specialized(Int, Long, Double) T: Arrayable] = new Flat[T]
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy