std.mem em Zig — Referência e Exemplos

std.mem — Operações de Memória

O módulo std.mem fornece funções fundamentais para trabalhar com memória e slices no Zig. Ele inclui operações de comparação, busca, cópia, preenchimento, alinhamento e a interface Allocator — o mecanismo central de alocação de memória do Zig.

Visão Geral

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

O std.mem é um dos módulos mais usados em Zig, pois slices ([]const u8, []u8) são o tipo fundamental para strings e dados binários.

Funções de Comparação

// Compara dois slices para igualdade
pub fn eql(comptime T: type, a: []const T, b: []const T) bool

// Compara com ordenação (retorna .lt, .eq, .gt)
pub fn order(comptime T: type, a: []const T, b: []const T) std.math.Order

// Verifica se slice começa com prefixo
pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool

// Verifica se slice termina com sufixo
pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool

Funções de Busca

// Encontra primeira ocorrência de subsequência
pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize

// Encontra última ocorrência
pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize

// Encontra primeiro elemento igual a qualquer valor no conjunto
pub fn indexOfAny(comptime T: type, haystack: []const T, needles: []const T) ?usize

// Conta ocorrências de um valor
pub fn count(comptime T: type, haystack: []const T, needle: []const T) usize

// Verifica se contém subsequência
pub fn containsAtLeast(comptime T: type, haystack: []const T, n: usize, needle: []const T) bool

Funções de Manipulação

// Copia memória (src e dst não podem sobrepor)
pub fn copyForwards(comptime T: type, dst: []T, src: []const T) void

// Preenche com um valor
pub fn set(comptime T: type, slice: []T, value: T) void

// Substitui todas as ocorrências
pub fn replace(comptime T: type, input: []const T, needle: []const T, replacement: []const T, output: []T) usize

// Remove prefixo/sufixo
pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T
pub fn trimRight(comptime T: type, slice: []const T, values_to_strip: []const T) []const T
pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T

Exemplo 1: Comparação e Busca em Strings

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

pub fn main() void {
    const texto = "Zig é uma linguagem de programação de sistemas";

    // Comparação
    std.debug.print("Igual: {}\n", .{mem.eql(u8, "Zig", "Zig")}); // true
    std.debug.print("Igual: {}\n", .{mem.eql(u8, "Zig", "zig")}); // false

    // Busca
    if (mem.indexOf(u8, texto, "linguagem")) |pos| {
        std.debug.print("'linguagem' encontrada na posição {d}\n", .{pos});
    }

    // Prefixo e sufixo
    std.debug.print("Começa com 'Zig': {}\n", .{mem.startsWith(u8, texto, "Zig")});
    std.debug.print("Termina com 'sistemas': {}\n", .{mem.endsWith(u8, texto, "sistemas")});

    // Contagem
    const contagem = mem.count(u8, texto, "de");
    std.debug.print("Ocorrências de 'de': {d}\n", .{contagem});
}

Exemplo 2: Manipulação de Slices

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

pub fn main() void {
    // Trim
    const bruto = "   Olá, mundo!   ";
    const limpo = mem.trim(u8, bruto, " ");
    std.debug.print("Trim: '{s}'\n", .{limpo}); // 'Olá, mundo!'

    const apenas_esquerda = mem.trimLeft(u8, bruto, " ");
    std.debug.print("TrimLeft: '{s}'\n", .{apenas_esquerda}); // 'Olá, mundo!   '

    // Substituição
    var buf: [100]u8 = undefined;
    const entrada = "foo-bar-baz";
    const substituicoes = mem.replace(u8, entrada, "-", "_", &buf);
    std.debug.print("Substituição: '{s}' ({d} trocas)\n", .{
        buf[0..entrada.len],
        substituicoes,
    }); // 'foo_bar_baz' (2 trocas)

    // Preenchimento
    var dados: [10]u8 = undefined;
    mem.set(u8, &dados, 0xFF);
    std.debug.print("Preenchido: ", .{});
    for (dados) |byte| {
        std.debug.print("{x:0>2} ", .{byte});
    }
    std.debug.print("\n", .{});
}

Exemplo 3: Funções de Alinhamento

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

pub fn main() void {
    // Alinhamento de valores
    std.debug.print("alignForward(13, 8) = {d}\n", .{mem.alignForward(usize, 13, 8)}); // 16
    std.debug.print("alignBackward(13, 8) = {d}\n", .{mem.alignBackward(usize, 13, 8)}); // 8
    std.debug.print("isAligned(16, 8) = {}\n", .{mem.isAligned(16, 8)}); // true
    std.debug.print("isAligned(13, 8) = {}\n", .{mem.isAligned(13, 8)}); // false

    // Conversão de slices
    const bytes = [_]u8{ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 };
    const inteiros = mem.bytesAsSlice(u32, &bytes);
    std.debug.print("Inteiros: {d}, {d}\n", .{ inteiros[0], inteiros[1] }); // 1, 2 (little-endian)
}

Padrões Comuns

Comparação de Strings

Em Zig, strings são []const u8. Use mem.eql para comparar:

fn ehComando(entrada: []const u8, comando: []const u8) bool {
    return mem.eql(u8, entrada, comando);
}

Busca case-insensitive

fn indexOfInsensitive(haystack: []const u8, needle: []const u8) ?usize {
    if (needle.len > haystack.len) return null;
    for (0..haystack.len - needle.len + 1) |i| {
        if (std.ascii.eqlIgnoreCase(haystack[i..][0..needle.len], needle)) {
            return i;
        }
    }
    return null;
}

Conversão entre Tipos de Slice

// []u8 para []u32 (requer alinhamento!)
const aligned_bytes = mem.bytesAsSlice(u32, bytes_alinhados);

// []u32 para []u8
const raw_bytes = mem.sliceAsBytes(inteiros);

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

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