130. Circular Buffer Indexing

#include <iostream>

class AudioBuffer {
private:
    int head_index;
    static const int BUFFER_SIZE = 8;

public:
    AudioBuffer() : head_index(0) {}

    // Safe state update: Enforces circular invariant
    void advanceHead(int steps) {
        // Update and wrap using modulo arithmetic
        head_index = (head_index + steps) % BUFFER_SIZE;
    }

    // Read-only access
    int getHeadIndex() const {
        return head_index;
    }
};

int main() {
    int N;
    if (!(std::cin >> N)) return 0;

    AudioBuffer buffer;

    for (int i = 0; i < N; ++i) {
        int steps;
        std::cin >> steps;

        // Use the encapsulated interface
        buffer.advanceHead(steps);

        std::cout << "Head: " << buffer.getHeadIndex() << std::endl;
    }

    return 0;
}

Explanation & Logic Summary: 

The problem addresses Invariant Preservation. A circular buffer relies on the invariant 0 <= index < SIZE.

  1. The Flaw: Exposing head_index allows users to write index += steps. If index exceeds 7, it points to invalid memory.
  2. The Fix: Encapsulation forces all index updates to go through advanceHead().
  3. The Logic: The method applies (current + steps) % 8. This guarantees that no matter how large steps is, the resulting index wraps correctly back to the start of the buffer.

Firmware Relevance & Real-World Context:

  • DMA Buffers: Ring buffers are the standard structure for handling continuous data streams (UART, ADC, Audio) in firmware.
  • Memory Safety: Accessing buffer[8] in a system with 8 bytes of RAM allocated to it is a buffer overflow that can corrupt the stack or trigger a Hard Fault.
  • Atomic Logic: Encapsulating the increment ensures that the wrapping logic is never forgotten, preventing "off-by-one" errors scattered across the codebase.

 

 

 

 

Loading...

Input

3 5 4 10

Expected Output

Head: 5 Head: 1 Head: 3