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

com.twitter.finagle.http.headers.Header.scala Maven / Gradle / Ivy

package com.twitter.finagle.http.headers

import scala.annotation.tailrec
import scala.collection.mutable
import scala.collection.AbstractIterator
import com.twitter.finagle.http.HeaderMap

private[http] sealed class Header private (final val name: String, final val value: String)
    extends HeaderMap.NameValue {

  final protected var _next: Header = null

  final def next: Header = _next
}

private[http] object Header {

  final class Root private[Header] (name: String, value: String) extends Header(name, value) {
    self =>

    def iterator: Iterator[HeaderMap.NameValue] =
      if (next == null) Iterator.single(this)
      else {
        new AbstractIterator[HeaderMap.NameValue] {
          private[this] var cur: Header = self
          def hasNext: Boolean = cur != null
          def next(): HeaderMap.NameValue = {
            var n = cur
            cur = n.next
            n
          }
        }
      }

    // We want to keep a reference to the last element of this linked list
    // so we don't need to traverse the whole list to add an element.
    private[this] var last: Header = null

    def add(name: String, value: String): Unit = {
      val n = new Header(name, value)
      if (next == null) {
        // the second element.
        _next = n
      } else {
        last._next = n
      }
      // Set the reference to the last element for future `add` calls.
      last = n
    }

    def values: Seq[String] =
      if (next == null) value :: Nil
      else {
        val result = new mutable.ListBuffer[String] += value

        var i = next
        do {
          result += i.value
          i = i.next
        } while (i != null)

        result.toList
      }
  }

  /** Create a new root node */
  def root(name: String, value: String): Root =
    new Root(name, value)

  def uniqueNames(orig: Iterator[Header]): Iterator[String] = new Iterator[String] {
    private[this] val it = orig
    private[this] var current: Iterator[String] = Iterator.empty

    private[this] def collectUnique(from: Header): Iterator[String] = new Iterator[String] {

      // We need to keep `_next` current so that we can reliably determine `.hasNext`.
      // That means that if `_next` is not null, it is, in fact, the next value.
      private[this] var nextUnique = from

      // We keep a set of observed names so that we don't accidentally return
      // duplicates. Another way to have done this would be to simply add all names
      // to a set and return an iterator over that set, but this way is more lazy.
      private[this] var seen = Set.empty + from.name

      def hasNext: Boolean = nextUnique != null

      def next(): String = {
        if (!hasNext) throw new NoSuchElementException

        val result = nextUnique.name
        // We then need to determine the next `_next` so we can
        // again have a sane `.hasNext`.
        prepareNext()
        result
      }

      @tailrec
      private[this] def prepareNext(): Unit = {
        nextUnique = nextUnique.next
        if (nextUnique != null) {
          val prevSize = seen.size
          seen = seen + nextUnique.name
          if (seen.size == prevSize) {
            // already observed. Try again.
            prepareNext()
          }
        }
      }
    }

    def hasNext: Boolean =
      it.hasNext || current.hasNext

    def next(): String = {
      if (current.isEmpty) {
        val hs = it.next()
        if (hs.next == null) {
          // A shortcut to see if we have only a single entry for this name
          hs.name
        } else {
          // slow path: we need to make a sub-iterator
          current = collectUnique(hs)
          current.next()
        }
      } else {
        current.next()
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy