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

packer.PackerDeque.scala Maven / Gradle / Ivy

// Copyright 2015-2022 by Carnegie Mellon University
// See license information in LICENSE.txt

package org.cert.netsa.mothra.packer

/**
  * The type of objects that are contained in a [[PackerDeque]].  The
  * contstructor is protected indicating the class is to be subclassed.
  */
private[mothra] class PackerDequeNode[T <: PackerDequeNode[T]] protected () {
  var prev: T = _
  var next: T = _
}

private[mothra] case class PackerDeque[T <: PackerDequeNode[T]]() {

  /** The head of the deque; its `prev` is the tail of the deque. */
  private[this] var root = Option.empty[T]

  /** Iterates over the objects in the deque */
  private[this] class Iterator(start: Option[T]) extends
      scala.collection.Iterator[T]
  {
    private[this] var nextNode = start

    def hasNext: Boolean = ( nextNode.nonEmpty )

    def next(): T = {
      val ret = nextNode.get
      nextNode = Option(ret.next)
      if ( nextNode == start ) {
        nextNode = Option.empty[T]
      }
      ret
    }
  }

  /** Returns an interator over the objects in the deque. */
  def iterator: scala.collection.Iterator[T] = {
    new Iterator(root)
  }

  /** Adds `newNode` after `nodePrev`.  Does not move `root`. */
  private[this] def _addAfter(newNode: T, nodePrev: T):
      T =
  {
    newNode.prev = nodePrev
    newNode.next = nodePrev.next
    newNode.next.prev = newNode
    nodePrev.next = newNode
    newNode
  }

  /** Adds `newNode` after `nodeNext`.  Does not move `root`. */
  private[this] def _addBefore(newNode: T, nodeNext: T):
      T =
  {
    newNode.next = nodeNext
    newNode.prev = nodeNext.prev
    newNode.prev.next = newNode
    nodeNext.prev = newNode
    newNode
  }

  /** Sets `newRoot` as `root` when the deque is empty. */
  private[this] def _makeRoot(newRoot: T): T = {
    newRoot.next = newRoot
    newRoot.prev = newRoot
    root = Option(newRoot)
    newRoot
  }

  /** Selects the first item; throws exception when empty. */
  def head: T = {
    root.getOrElse {
      throw new NoSuchElementException("PackerDeque is empty")
    }
  }

  /** Optionally selects the first item. */
  def headOption: Option[T] = {
    root
  }

  /** Removes the first item and returns it; throws exception when empty. */
  def removeHead: T = {
    val r = root.getOrElse {
      throw new NoSuchElementException("PackerDeque is empty")
    }
    remove(r)
  }

  /** Optionally removes the first item and returns it. */
  def removeHeadOption: Option[T] = {
    root match {
      case Some(r) => Option(remove(r))
      case None => root
    }
  }

  /** Selects the last item; throws exception when empty. */
  def last: T = {
    val r = root.getOrElse {
      throw new NoSuchElementException("PackerDeque is empty")
    }
    r.prev
  }

  /** Optionally selects the last item. */
  def lastOption: Option[T] = {
    root match {
      case Some(r) => Option(r.prev)
      case None => root
    }
  }

  /** Removes the last item and returns it; throws exception when empty. */
  def removeLast: T = {
    val r = root.getOrElse {
      throw new NoSuchElementException("PackerDeque is empty")
    }
    remove(r.prev)
  }

  /** Optionally removes the last item and returns it. */
  def removeLastOption: Option[T] = {
    root match {
      case Some(r) => Option(remove(r.prev))
      case None => root
    }
  }

  /**
    * Returns the number of items in the deque.  Walks the deque to count the
    * items.
    */
  def size: Int = {
    var count = 0
    for ( r <- root ) {
      var n = r
      do {
        count += 1
        n = n.next
      } while ( n != r );
    }
    count
  }

  /**
    * Adds `newNode` to the front of the deque and makes it the `head`.
    * Returns the newly added node.
    */
  def prepend(newNode: T): T = {
    root match {
      case Some(r) =>
        root = Option(_addBefore(newNode, r))
        newNode
      case None => _makeRoot(newNode)
    }
  }

  /**
    * Adds `newNode` to the end of the deque and makes it the `tail`.  Returns
    * the newly added node.
    */
  def append(newNode: T): T = {
    root match {
      case Some(r) => _addBefore(newNode, r)
      case None => _makeRoot(newNode)
    }
  }

  /** Returns `true` when the deque is empty. */
  def isEmpty: Boolean = root.isEmpty

  /** Returns `true` when the deque is not empty. */
  def nonEmpty: Boolean = root.nonEmpty

  /** Returns `true` when `node` is in this deque. */
  def contains(node: T): Boolean = {
    root match {
      case None => false
      case Some(r) =>
        var n = r
        while ( n != node && n.next != r ) {
          n = n.next
        }
        n == node
    }
  }

  /**
    * Adds `newNode` after `nodePrev`.  If `nodePrev` is `tail`, `newNode`
    * becomes the new tail.  Returns `newNode`.
    *
    * Assumes `nodePrev` exists in the deque.
    */
  def addAfter(newNode: T, nodePrev: T): T =
    _addAfter(newNode, nodePrev)

  /**
    * Adds `newNode` before `nodeNext`.  If `nodeNext` is `head`, `newNode`
    * becomes the new head.  Returns `newNode`.
    *
    * Assumes `nodeNext` exists in the deque.
    */
  def addBefore(newNode: T, nodeNext: T): T = {
    val n = _addBefore(newNode, nodeNext)
    if ( root.get == nodeNext ) {
      root = Option(newNode)
    }
    n
  }

  /**
    * Moves `node` to the head of the deque and returns it.
    *
    * Assumes `node` exists in the deque.
    */
  def moveToHead(node: T): T = {
    for {
      r <- root
      // Workaround scala/bug#11175 -Ywarn-unused:params false positive
      _ = r
      if r != node
    } {
      node.prev.next = node.next
      node.next.prev = node.prev
      root = Option(_addBefore(node, root.get))
    }
    node
  }

  /**
    * Moves `node` to the tail of the deque and returns it.
    *
    * Assumes `node` exists in the deque.
    */
  def moveToLast(node: T): T = {
    for (
      r <- root
      if r.prev != node
    ) {
      if ( r == node ) {
        root = Option(r.next)
      }
      node.prev.next = node.next
      node.next.prev = node.prev
      _addBefore(node, root.get)
    }
    node
  }

  /**
    * Removes `node` from the deque and returns it.  The `next` and `prev`
    * pointers of `node` are set to itself.
    *
    * Assumes `node` exists in the deque.
    */
  def remove(node: T): T = {
    for ( r <- root ) {
      if ( r == node ) {
        if ( r.next == r ) {
          root = Option.empty[T]
        } else {
          root = Option(r.next)
        }
      }
    }
    node.prev.next = node.next
    node.next.prev = node.prev
    node.prev = node
    node.next = node
    node
  }

  /**
    * Removes all nodes from the deque.  The `next` and `prev` values on each
    * node are set to itself.
    */
  def clear(): Unit = {
    for ( r <- root ) {
      var n = r.next
      do {
        r.next = n.next
        n.next = n
        n.prev = n
        n = r.next
      } while ( n != r );
    }
    root = Option.empty[T]
  }

  /**
    * Prints the contents of the deque.
    */
  def verify(): Unit = {
    for ( r <- root ) {
      var count = 0
      var n = r
      do {
        println(s"${count}, value: ${n}, prev: ${n.prev}, next: ${n.next}")
        n = n.next
        count += 1
      } while (n != r);
    }
  }
}


private[mothra] object PackerDeque {
  /** Creates an empty deque. */
  def empty[T <: PackerDequeNode[T]]: PackerDeque[T] = {
    new PackerDeque[T]()
  }
}

// @LICENSE_FOOTER@
//
// Copyright 2015-2022 Carnegie Mellon University. All Rights Reserved.
//
// This material is based upon work funded and supported by the
// Department of Defense and Department of Homeland Security under
// Contract No. FA8702-15-D-0002 with Carnegie Mellon University for the
// operation of the Software Engineering Institute, a federally funded
// research and development center sponsored by the United States
// Department of Defense. The U.S. Government has license rights in this
// software pursuant to DFARS 252.227.7014.
//
// NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE ENGINEERING
// INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON
// UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR
// IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF
// FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS
// OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
// MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT,
// TRADEMARK, OR COPYRIGHT INFRINGEMENT.
//
// Released under a GNU GPL 2.0-style license, please see LICENSE.txt or
// contact [email protected] for full terms.
//
// [DISTRIBUTION STATEMENT A] This material has been approved for public
// release and unlimited distribution. Please see Copyright notice for
// non-US Government use and distribution.
//
// Carnegie Mellon(R) and CERT(R) are registered in the U.S. Patent and
// Trademark Office by Carnegie Mellon University.
//
// This software includes and/or makes use of third party software each
// subject to its own license as detailed in LICENSE-thirdparty.tx
//
// DM20-1143




© 2015 - 2024 Weber Informatics LLC | Privacy Policy