/* Linked lists and queues
 * 15-122 Principles of Imperative Computation, Spring 2011
 * Frank Pfenning
 */

typedef string elem;

/* Interface to queues of elems */

typedef struct queue* queue;

bool queue_empty(queue Q);	/* O(1) */
queue queue_new();		/* O(1) */
void enq(queue Q, elem e);	/* O(1) */
elem deq(queue Q)		/* O(1) */
//@requires !queue_empty(Q);
  ;

/* Implementation of queues */

typedef struct list* list;
struct list {
  elem data;
  list next;
};

struct queue {
  list front;
  list back;
};

/* is_segment for finite lists only!! */
bool is_segment(list start, list end) {
  while (start != end) {
    if (start == NULL) return false;
    start = start->next;
  }
  return true;
}

bool is_queue(queue Q) {
  if (Q == NULL) return false;
  if (Q->front == NULL || Q->back == NULL) return false;
  return is_segment(Q->front, Q->back);
}

bool queue_empty(queue Q)
//@requires is_queue(Q);
{
  return Q->front == Q->back;
}

queue queue_new()
//@ensures is_queue(\result);
//@ensures queue_empty(\result);
{
  list l = alloc(struct list);
  queue Q = alloc(struct queue);
  Q->front = l;
  Q->back = l;
  return Q;
}

void enq(queue Q, elem e)
//@requires is_queue(Q);
//@ensures is_queue(Q);
{
  list l = alloc(struct list);
  Q->back->data = e;
  Q->back->next = l;
  Q->back = l;
  return;
}

elem deq(queue Q)
//@requires is_queue(Q);
//@requires !is_empty(Q);
//@ensures is_queue(Q);
{
  assert(!queue_empty(Q));
  elem e = Q->front->data;
  Q->front = Q->front->next;
  return e;
}
