The circular buffer operations keep the queue in the right cells full
This proof shows: correctness.
Setting. A buffer B has an array A[0..N−1] with N≥1, an index h and a count n. For 0≤i<N, write ci=(h+i)modN.
Lemma. For a fixed h, the cells c0,…,cN−1 are distinct, so they are all N cells.
Proof. If ci=cj with 0≤i<j<N, then N divides j−i, which is between 1 and N−1. That is impossible. □
Invariant (I). 0≤h<N, 0≤n≤N, and the queue held is Q=⟨A[c0],…,A[cn−1]⟩.
(I) holds for a new buffer with h=0 and n=0. For each operation, assume (I) and the precondition, and write Q=⟨q0,…,qn−1⟩ with qi=A[ci].
ENQUEUE(B,x). If n=N, line L1 stops with an error and nothing changes. Otherwise n<N. Line L2 writes x into cell cn. By the lemma, cn differs from c0,…,cn−1, so the items q0,…,qn−1 stay in their cells. Line L3 sets the count to n+1≤N, and h does not change. So the new queue is ⟨q0,…,qn−1,x⟩, and (I) holds.
DEQUEUE(B). If n=0, line L4 stops with an error. Otherwise line L5 reads x=A[c0]=q0. Line L6 sets h′=(h+1)modN, which is in [0,N), and n′=n−1≥0. No cell is written. The new cells are ci′=(h′+i)modN=(h+1+i)modN=ci+1. So the new queue is ⟨A[c1],…,A[cn−1]⟩=⟨q1,…,qn−1⟩, and line L7 returns q0.
PUSH-FRONT(B,x), n<N. Line L8 sets h′=(h−1)modN, taken in [0,N), writes x into A[h′] and sets n′=n+1. The new cells are c0′=h′ and ci′=(h−1+i)modN=ci−1 for i≥1. The cell h′=cN−1 is not one of c0,…,cn−1 because n≤N−1, by the lemma. So the write does not touch an item, and the new queue is ⟨x,q0,…,qn−1⟩.
POP-BACK(B), n≥1. Line L9 sets n′=n−1, and line L10 returns A[(h+n′)modN]=A[cn−1]=qn−1. No cell is written and h does not change, so the new queue is ⟨q0,…,qn−2⟩.
GET(B,i), 0≤i<n. Line L11 returns A[ci]=qi, and nothing changes. ■