You still have a buffer or size X that may store X-Y items. I fail to see the "zero memory waste" (not that it's a good tradeoff).
An unfortunate effect of this implementation is that both indices are modified by the consumer. It's not safe to write/read dats from different contexts, something that would be very useful in a driver.
Now it makes sense.
It's easier to understand without the decrementing. Initialize head and tail to 0, keep incrementing and cycling through the end as usual. When removing an element check if head and tail are equal before removing. When adding an element check if head and tail are equal after adding, and set the head to a sentinel value, say MAX_INT. Now you can check for the sentinel before attempting to add an element.
Neat trick!