std.BoundedArray em Zig — Referência e Exemplos

std.BoundedArray — Array de Capacidade Fixa

O std.BoundedArray é uma estrutura de dados que oferece uma interface similar ao ArrayList, mas com capacidade máxima definida em tempo de compilação. Ele não requer nenhum alocador de memória, pois armazena todos os dados diretamente na stack (ou inline na struct que o contém). É ideal para situações onde o tamanho máximo é conhecido e alocação dinâmica não é desejável — como em sistemas embarcados, contextos de tempo real ou hot paths de desempenho crítico.

Visão Geral

const std = @import("std");
const BoundedArray = std.BoundedArray;

Tipo e Assinatura

pub fn BoundedArray(comptime T: type, comptime capacity: usize) type

O tipo resultante contém:

  • Um array fixo [capacity]T para armazenamento
  • Um campo len indicando quantos elementos estão em uso

Funções Principais

Criação

// Cria array vazio
pub fn init(len: usize) error{Overflow}!BoundedArray(T, N)

// Cria a partir de um slice
pub fn fromSlice(slice: []const T) error{Overflow}!BoundedArray(T, N)

Adição e Remoção

// Adiciona ao final
pub fn append(self: *Self, item: T) error{Overflow}!void

// Adiciona um slice inteiro
pub fn appendSlice(self: *Self, items: []const T) error{Overflow}!void

// Remove e retorna o último
pub fn pop(self: *Self) T

// Remove e retorna o último, ou null
pub fn popOrNull(self: *Self) ?T

// Remove em índice específico
pub fn orderedRemove(self: *Self, index: usize) T

// Remove por troca (O(1))
pub fn swapRemove(self: *Self, index: usize) T

Acesso

// Retorna slice dos elementos ativos
pub fn slice(self: *Self) []T
pub fn constSlice(self: *const Self) []const T

// Acesso por índice com bounds checking
pub fn get(self: Self, index: usize) T

// Define valor em índice
pub fn set(self: *Self, index: usize, value: T) void

// Número de elementos
// Campo: self.len

Redimensionamento

// Redefine o comprimento
pub fn resize(self: *Self, new_len: usize) error{Overflow}!void

// Limpa todos os elementos
pub fn clear(self: *Self) void

Exemplo 1: Buffer de Mensagens sem Alocação

const std = @import("std");

const MAX_MENSAGENS = 10;
const Mensagem = struct {
    texto: [64]u8,
    texto_len: usize,
    prioridade: u8,
};

pub fn main() !void {
    var fila = try std.BoundedArray(Mensagem, MAX_MENSAGENS).init(0);

    // Adiciona mensagens
    const textos = [_][]const u8{
        "Sistema iniciado",
        "Conexão estabelecida",
        "Dados recebidos",
    };

    for (textos, 0..) |texto, i| {
        var msg: Mensagem = .{
            .texto = [_]u8{0} ** 64,
            .texto_len = texto.len,
            .prioridade = @intCast(i),
        };
        @memcpy(msg.texto[0..texto.len], texto);
        try fila.append(msg);
    }

    const stdout = std.io.getStdOut().writer();
    try stdout.print("Mensagens na fila: {d}/{d}\n", .{ fila.len, MAX_MENSAGENS });

    for (fila.constSlice()) |msg| {
        try stdout.print("  [{d}] {s}\n", .{
            msg.prioridade,
            msg.texto[0..msg.texto_len],
        });
    }
}

Exemplo 2: Coletor de Argumentos de Linha de Comando

const std = @import("std");

const MAX_ARGS = 32;

const ArgsParser = struct {
    flags: std.BoundedArray([]const u8, MAX_ARGS),
    valores: std.BoundedArray([]const u8, MAX_ARGS),

    pub fn init() ArgsParser {
        return .{
            .flags = std.BoundedArray([]const u8, MAX_ARGS).init(0) catch unreachable,
            .valores = std.BoundedArray([]const u8, MAX_ARGS).init(0) catch unreachable,
        };
    }

    pub fn parse(self: *ArgsParser, args: []const []const u8) !void {
        for (args) |arg| {
            if (std.mem.startsWith(u8, arg, "--")) {
                try self.flags.append(arg[2..]);
            } else {
                try self.valores.append(arg);
            }
        }
    }

    pub fn temFlag(self: *const ArgsParser, nome: []const u8) bool {
        for (self.flags.constSlice()) |flag| {
            if (std.mem.eql(u8, flag, nome)) return true;
        }
        return false;
    }
};

pub fn main() !void {
    var parser = ArgsParser.init();

    const args_simulados = [_][]const u8{
        "arquivo.txt", "--verbose", "--output", "resultado.txt",
    };
    try parser.parse(&args_simulados);

    const stdout = std.io.getStdOut().writer();
    try stdout.print("Flags: {d}\n", .{parser.flags.len});
    try stdout.print("Valores: {d}\n", .{parser.valores.len});
    try stdout.print("Verbose: {}\n", .{parser.temFlag("verbose")});
}

Exemplo 3: Buffer Circular com BoundedArray

const std = @import("std");

fn BufferCircular(comptime T: type, comptime N: usize) type {
    return struct {
        dados: std.BoundedArray(T, N),
        inicio: usize = 0,

        const Self = @This();

        pub fn init() Self {
            return .{
                .dados = std.BoundedArray(T, N).init(0) catch unreachable,
            };
        }

        pub fn push(self: *Self, valor: T) void {
            if (self.dados.len < N) {
                self.dados.append(valor) catch unreachable;
            } else {
                self.dados.set(self.inicio, valor);
                self.inicio = (self.inicio + 1) % N;
            }
        }

        pub fn ultimosN(self: *const Self, n: usize) void {
            const total = @min(n, self.dados.len);
            const stdout = std.io.getStdOut().writer() catch return;
            _ = stdout;
            var i: usize = 0;
            while (i < total) : (i += 1) {
                const idx = (self.inicio + self.dados.len - total + i) % self.dados.len;
                std.debug.print("{d} ", .{self.dados.constSlice()[idx]});
            }
            std.debug.print("\n", .{});
        }
    };
}

pub fn main() void {
    var buf = BufferCircular(i32, 5).init();

    // Insere mais que a capacidade
    for (0..8) |i| {
        buf.push(@intCast(i * 10));
    }

    std.debug.print("Buffer (últimos 5): ", .{});
    const slice = buf.dados.constSlice();
    for (slice) |v| {
        std.debug.print("{d} ", .{v});
    }
    std.debug.print("\n", .{});
    std.debug.print("Tamanho: {d}\n", .{buf.dados.len});
}

BoundedArray vs ArrayList

CaracterísticaBoundedArrayArrayList
AlocaçãoStack / inlineHeap
Requer allocatorNãoSim
CapacidadeFixa (comptime)Dinâmica
OverheadZeroPonteiro + metadados
Uso em embarcadosIdealDepende do allocator

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.