text: "use strict";
  var ASSERT = require("./assert.js");
  //http://jsperf.com/deque-vs-array-2
  function arrayCopy(src, srcIndex, dst, dstIndex, len) {
      for (var j = 0; j < len; ++j) {
          dst[j + dstIndex] = src[j + srcIndex];
      }
  }
  
  function Queue(capacity) {
      this._capacity = capacity;
      this._length = 0;
      this._front = 0;
      this._makeCapacity();
  }
  
  Queue.prototype._willBeOverCapacity =
  function Queue$_willBeOverCapacity(size) {
      return this._capacity < size;
  };
  
  Queue.prototype._pushOne = function Queue$_pushOne(arg) {
      var length = this.length();
      this._checkCapacity(length + 1);
      var i = (this._front + length) & (this._capacity - 1);
      this[i] = arg;
      this._length = length + 1;
  };
  
  Queue.prototype.push = function Queue$push(fn, receiver, arg) {
      ASSERT(arguments.length === 3);
      ASSERT(typeof fn === "function");
      var length = this.length() + 3;
      if (this._willBeOverCapacity(length)) {
          //The fast array copies expect the
          //underlying array to be filled completely
          this._pushOne(fn);
          this._pushOne(receiver);
          this._pushOne(arg);
          return;
      }
      var j = this._front + length - 3;
      this._checkCapacity(length);
      var wrapMask = this._capacity - 1;
      this[(j + 0) & wrapMask] = fn;
      this[(j + 1) & wrapMask] = receiver;
      this[(j + 2) & wrapMask] = arg;
      this._length = length;
  };
  
  Queue.prototype.shift = function Queue$shift() {
      ASSERT(this.length() > 0);
      var front = this._front,
          ret = this[front];
  
      this[front] = void 0;
      this._front = (front + 1) & (this._capacity - 1);
      this._length--;
      return ret;
  };
  
  Queue.prototype.length = function Queue$length() {
      return this._length;
  };
  
  Queue.prototype._makeCapacity = function Queue$_makeCapacity() {
      var len = this._capacity;
      for (var i = 0; i < len; ++i) {
          this[i] = void 0;
      }
  };
  
  Queue.prototype._checkCapacity = function Queue$_checkCapacity(size) {
      if (this._capacity < size) {
          this._resizeTo(this._capacity << 3);
      }
  };
  
  Queue.prototype._resizeTo = function Queue$_resizeTo(capacity) {
      var oldFront = this._front;
      var oldCapacity = this._capacity;
      var oldQueue = new Array(oldCapacity);
      var length = this.length();
  
      arrayCopy(this, 0, oldQueue, 0, oldCapacity);
      this._capacity = capacity;
      this._makeCapacity();
      this._front = 0;
      //Can perform direct linear copy
      if (oldFront + length <= oldCapacity) {
          arrayCopy(oldQueue, oldFront, this, 0, length);
      } else {//Cannot perform copy directly, perform as much as possible
              //at the end, and then copy the rest to the beginning of the buffer
          var lengthBeforeWrapping =
              length - ((oldFront + length) & (oldCapacity - 1));
  
          arrayCopy(oldQueue, oldFront, this, 0, lengthBeforeWrapping);
          arrayCopy(oldQueue, 0, this, lengthBeforeWrapping,
                      length - lengthBeforeWrapping);
      }
  };
  
  module.exports = Queue;
  