queue.pony

class Queue[A]
  embed _array: Array[A]
  var _size: USize
  var _start: USize
  var _next: USize

  new create(space': USize = 0) =>
    _array = Array[A](space')
    _size = 0
    _start = 0
    _next = 0

  fun size(): USize =>
    _size

  fun space(): USize =>
    _array.space()

  fun apply(i: USize): this->A ? =>
    if i >= _size then
      error
    end
    let index = (_start + i) % _array.size()
    _array(index)?

  fun ref clear() =>
    _array.clear()
    _array.compact()
    _size = 0
    _start = 0
    _next = 0

  fun ref compact() =>
    _array.compact()

  fun ref pop(): A ? =>
    if _size == 0 then
      error
    end
    let index = _start
    _start = (_start + 1) % _array.size()
    _size = _size - 1
    _array(index)?

  fun ref push(value: A) =>
    if _size < _array.size() then
      try
        if _next == _array.size() then
          _next = 0
        end
        _array.update(_next, consume value)?
        _next = _next + 1
        _size = _size + 1
      end
    else
      try
        _array.insert(_next, consume value)?
        if _start > _next then
          _start = _start + 1
        end
        _next = _next + 1
        _size = _size + 1
      end
    end

  fun values(): _QueueIterator[A, this->Queue[A]] =>
    _QueueIterator[A, this->Queue[A]](this)

class _QueueIterator[A, B: Queue[A] #read] is Iterator[B->A]
  let _queue: B
  var _cur: USize = 0

  new create(queue: B) =>
    _queue = queue

  fun has_next(): Bool =>
    _cur < _queue.size()

  fun ref next(): B->A ? =>
    _queue(_cur = _cur + 1)?