---
title: "Ring Buffer (Buffer Circular) em Zig — Implementação Completa"
url: "https://ziglang.com.br/estruturas-dados/ring-buffer-buffer-circular-em-zig-implementa%C3%A7%C3%A3o-completa/"
markdown_url: "https://ziglang.com.br/estruturas-dados/ring-buffer-buffer-circular-em-zig-implementa%C3%A7%C3%A3o-completa.MD"
description: "Aprenda Ring Buffer em Zig. Buffer circular com leitura e escrita em O(1), ideal para streams e filas de tamanho fixo. Código funcional completo."
date: "2026-02-21"
author: "Zig Brasil"
---

# Ring Buffer (Buffer Circular) em Zig — Implementação Completa

Aprenda Ring Buffer em Zig. Buffer circular com leitura e escrita em O(1), ideal para streams e filas de tamanho fixo. Código funcional completo.


# Ring Buffer (Buffer Circular) em Zig — Implementação Completa

Um **Ring Buffer** (buffer circular) é uma estrutura de dados de tamanho fixo que funciona como se o final do array estivesse conectado ao início. Quando o buffer está cheio e um novo elemento é escrito, ele sobrescreve o mais antigo. É extremamente eficiente para filas de produtores/consumidores, streaming de dados, logs rotativos e comunicação entre threads.

## Conceito

```
Ring Buffer com capacidade 6:

Estado após inserir A, B, C, D:
  [A][B][C][D][ ][ ]
   ^           ^
   leitura     escrita

Após ler A e B:
  [ ][ ][C][D][ ][ ]
         ^     ^
         leit  escrita

Após inserir E, F, G (wrap around):
  [G][ ][C][D][E][F]
   ^  ^
   es leit → Escrita voltou ao início!

Índices circulares: pos = (pos + 1) % capacidade
```

## Implementação em Zig

```zig
const std = @import("std");

/// Ring Buffer genérico de tamanho fixo (comptime).
pub fn RingBuffer(comptime T: type, comptime capacidade: usize) type {
    return struct {
        const Self = @This();

        dados: [capacidade]T = undefined,
        leitura: usize = 0,    // Índice do próximo elemento a ler
        escrita: usize = 0,    // Índice do próximo espaço a escrever
        contagem: usize = 0,   // Elementos atualmente no buffer

        /// Escreve um elemento no buffer.
        /// Retorna o elemento sobrescrito se o buffer estava cheio.
        pub fn escrever(self: *Self, item: T) ?T {
            var sobrescrito: ?T = null;

            if (self.contagem == capacidade) {
                sobrescrito = self.dados[self.leitura];
                self.leitura = (self.leitura + 1) % capacidade;
            } else {
                self.contagem += 1;
            }

            self.dados[self.escrita] = item;
            self.escrita = (self.escrita + 1) % capacidade;

            return sobrescrito;
        }

        /// Lê e remove o elemento mais antigo.
        pub fn ler(self: *Self) ?T {
            if (self.contagem == 0) return null;

            const item = self.dados[self.leitura];
            self.leitura = (self.leitura + 1) % capacidade;
            self.contagem -= 1;
            return item;
        }

        /// Espia o próximo elemento sem removê-lo.
        pub fn espiar(self: *const Self) ?T {
            if (self.contagem == 0) return null;
            return self.dados[self.leitura];
        }

        /// Verifica se está cheio.
        pub fn cheio(self: *const Self) bool {
            return self.contagem == capacidade;
        }

        /// Verifica se está vazio.
        pub fn vazio(self: *const Self) bool {
            return self.contagem == 0;
        }

        /// Retorna número de elementos.
        pub fn tamanho(self: *const Self) usize {
            return self.contagem;
        }

        /// Retorna espaço disponível.
        pub fn espacoLivre(self: *const Self) usize {
            return capacidade - self.contagem;
        }

        /// Limpa o buffer.
        pub fn limpar(self: *Self) void {
            self.leitura = 0;
            self.escrita = 0;
            self.contagem = 0;
        }

        /// Itera sobre os elementos (do mais antigo ao mais recente).
        pub fn iterar(self: *const Self) Iterator {
            return .{ .buffer = self, .pos = self.leitura, .restante = self.contagem };
        }

        pub const Iterator = struct {
            buffer: *const Self,
            pos: usize,
            restante: usize,

            pub fn next(it: *Iterator) ?T {
                if (it.restante == 0) return null;
                const item = it.buffer.dados[it.pos];
                it.pos = (it.pos + 1) % capacidade;
                it.restante -= 1;
                return item;
            }
        };
    };
}

/// Ring Buffer com alocação dinâmica.
pub fn RingBufferDinamico(comptime T: type) type {
    return struct {
        const Self = @This();

        dados: []T,
        leitura: usize,
        escrita: usize,
        contagem: usize,
        capacidade: usize,
        allocator: std.mem.Allocator,

        pub fn init(allocator: std.mem.Allocator, capacidade: usize) !Self {
            return .{
                .dados = try allocator.alloc(T, capacidade),
                .leitura = 0,
                .escrita = 0,
                .contagem = 0,
                .capacidade = capacidade,
                .allocator = allocator,
            };
        }

        pub fn deinit(self: *Self) void {
            self.allocator.free(self.dados);
        }

        pub fn escrever(self: *Self, item: T) ?T {
            var sobrescrito: ?T = null;
            if (self.contagem == self.capacidade) {
                sobrescrito = self.dados[self.leitura];
                self.leitura = (self.leitura + 1) % self.capacidade;
            } else {
                self.contagem += 1;
            }
            self.dados[self.escrita] = item;
            self.escrita = (self.escrita + 1) % self.capacidade;
            return sobrescrito;
        }

        pub fn ler(self: *Self) ?T {
            if (self.contagem == 0) return null;
            const item = self.dados[self.leitura];
            self.leitura = (self.leitura + 1) % self.capacidade;
            self.contagem -= 1;
            return item;
        }
    };
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // Ring buffer estático
    var buf = RingBuffer(u8, 5){};

    try stdout.writeAll("=== Ring Buffer (capacidade=5) ===\n");

    // Escreve dados
    for ("HELLO WORLD") |c| {
        const sobrescrito = buf.escrever(c);
        if (sobrescrito) |s| {
            try stdout.print("  Escreveu '{c}', sobrescreveu '{c}'\n", .{ c, s });
        } else {
            try stdout.print("  Escreveu '{c}'\n", .{c});
        }
    }

    try stdout.print("\nTamanho: {d}/{d}\n", .{ buf.tamanho(), @as(usize, 5) });

    // Lê todos os elementos
    try stdout.writeAll("Conteúdo: ");
    var iter = buf.iterar();
    while (iter.next()) |c| {
        try stdout.print("{c}", .{c});
    }
    try stdout.writeAll("\n");

    // Exemplo prático: log rotativo
    try stdout.writeAll("\n=== Log Rotativo ===\n");
    var log_buf = RingBuffer([]const u8, 4){};

    const mensagens = [_][]const u8{
        "Sistema iniciado",
        "Conexão recebida",
        "Query executada",
        "Cache atualizado",
        "Erro de timeout",    // Vai sobrescrever a mais antiga
        "Reconexão OK",       // Vai sobrescrever a segunda mais antiga
    };

    for (mensagens) |msg| {
        _ = log_buf.escrever(msg);
    }

    try stdout.writeAll("Últimas mensagens no log:\n");
    var log_iter = log_buf.iterar();
    while (log_iter.next()) |msg| {
        try stdout.print("  > {s}\n", .{msg});
    }
}
```

## Análise de Complexidade

| Operação | Tempo | Espaço |
|----------|-------|--------|
| **Escrever** | O(1) | O(1) |
| **Ler** | O(1) | O(1) |
| **Espiar** | O(1) | O(1) |
| **Espaço total** | — | O(n) |

## Casos de Uso

- **Audio/Video streaming** — buffer de reprodução
- **Logging** — últimas N mensagens
- **Comunicação entre threads** — fila lock-free
- **Rede** — buffer de pacotes
- **Sensores/IoT** — últimas N leituras

## Recursos Relacionados

- [Fila](/estruturas-dados/fila/) — Fila dinâmica (FIFO)
- [Deque](/estruturas-dados/deque/) — Fila dupla
- [LRU Cache](/estruturas-dados/lru-cache/) — Cache com evição
- [std.io](/stdlib/std-io/) — I/O bufferizado na stdlib
