Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Исходник Pattern struct for matching [Zig]

  • Автор темы Автор темы oldORM
  • Дата начала Дата начала
Уникальная группа
Уникальная группа
Статус
Оффлайн
Регистрация
24 Сен 2024
Сообщения
78
Реакции
29
Доброго дня/ночи всем👍. Небольшая структура для парсинга и векторного сравнения байтовых данных.


C:
Expand Collapse Copy
const std = @import("std");

pub const Pattern = struct {
    bytes: []u8,
    mask: []u8,
    sequence: SequenceResult = undefined,
    allocator: std.mem.Allocator,

    pub noinline fn init(allocator: std.mem.Allocator, input: []const u8) !Pattern {
        var bytes = std.ArrayList(u8).empty;
        var mask = std.ArrayList(u8).empty;
        
        errdefer bytes.deinit(allocator);
        errdefer mask.deinit(allocator);

        var it = std.mem.tokenizeScalar(u8, input, ' ');
        while (it.next()) |part|  {

            if (std.mem.eql(u8, part, "??") or std.mem.eql(u8, part, "?")) {
                try bytes.append(allocator, 0x00);
                try mask.append(allocator, 0x00);
            } else {
                try bytes.append(allocator, std.fmt.parseInt(u8, part, 16) catch return error.InvalidPattern);
                try mask.append(allocator, 0xFF);
            }
        }

        var pattern = Pattern {
            .bytes = try bytes.toOwnedSlice(allocator),
            .mask = try mask.toOwnedSlice(allocator),
            .allocator = allocator
        };

        const result = try findLongestRun(&pattern);
        pattern.sequence = result;
        return pattern;
    }

    const SequenceResult = struct {
        search_sequence: []const u8,
        offset: i32
    };

    noinline fn findLongestRun(self: *Pattern) !SequenceResult {
        var best_start: i32 = 0;
        var best_len: i32 = 0;

        var current_start: i32 = 0;
        var current_len: i32 = 0;

        for (self.mask, 0..) |byte, i| {
            if (byte == std.math.maxInt(u8)) {
                if (current_len == 0)
                    current_start = @intCast(i);

                current_len += 1;

                if (current_len > best_len) {
                    best_start = current_start;
                    best_len = current_len;
                }
            }
            else {
                current_len = 0;
            }
        }

        if (best_len == 0) {
            return SequenceResult{
                .search_sequence = &.{},
                .offset = -1
            };
        }

        return SequenceResult{
            .search_sequence = self.bytes[@intCast(best_start) .. @intCast(best_start + best_len)],
            .offset = best_start
        };
    }

    pub noinline fn isMatch(self: *Pattern, data: []const u8) bool {
        const length = self.bytes.len;
        if (data.len < length) return false;

        var i: usize = 0;

        const vec_len = std.simd.suggestVectorLength(u8) orelse 1;
        const Vec = @Vector(vec_len, u8);

        if (vec_len > 1) {
            while (i + vec_len <= length) : (i += vec_len) {
                const v_data: Vec = data[i..][0..vec_len].*;
                const v_mask: Vec = self.mask[i..][0..vec_len].*;
                const v_bytes: Vec = self.bytes[i..][0..vec_len].*;

                const match_vec = (v_data & v_mask) == v_bytes;
                
                if (!@reduce(.And, match_vec)) {
                    return false;
                }
            }
        }

        while (i < length) : (i += 1) {
            if ((data[i] & self.mask[i]) != self.bytes[i]) {
                return false;
            }
        }

        return true;
    }

    pub noinline fn deinit(self: *Pattern) void {
        self.allocator.free(self.bytes);
        self.allocator.free(self.mask);
    }
};


Использование:

C:
Expand Collapse Copy
const std = @import("std");
const pattern = @import("pattern.zig");
const console = @import("console.zig");
const win = std.os.windows;

pub fn main() !void {
    var buffer: [8192]u8 = undefined;
    var fixed = std.heap.FixedBufferAllocator.init(&buffer);
    const allocator = fixed.allocator();

    const pattern_str = console.readln();

    var parsed = pattern.Pattern.init(allocator, pattern_str) catch return;
    defer parsed.deinit();

    console.print("{any}\n", .{ parsed.isMatch(&[_]u8 { 0xAA, 0xAA }) });
}
 
КРутой язык, а теперь попробуй скомпилировать программу без импорта ws2_32.dll, а когда сделаешь не забудь ее все заново опять переписать потому что в новом патче опять breaking changes
 
КРутой язык, а теперь попробуй скомпилировать программу без импорта ws2_32.dll, а когда сделаешь не забудь ее все заново опять переписать потому что в новом патче опять breaking changes
ку. импорт ws2_32.dll происходит из-за новой системы io и добавления асинхронности, условно при вызове io, оно тянет за собой vtable на 105 функций, но так как пока компилятор не умеет в новых версиях успешно угадывать какие используются, а какие нет - то пока что есть то есть. Поэтому лучше пока сидеть на стабильной версии 0.15.2, на нём нет этой системы и всё компилируется в 8 кб без единого импорта. (Разве что RtlExitUserProcess для выхода).

Эндрю келли в курсе про раздувания бинарника, и он сказал что их команда разберется и компилятор будет улучшаться. В конце концов язык даже не релизнулся, поэтому лучше не заранее не надеяться на 100% стабильный api в master ветке.
 
Да я вкурсе почему это происходит, но в стабильном 0.16 это все еще останется, и я, честно, не верю в то что они в ближайшее время избавятся от этого
 
Да я вкурсе почему это происходит, но в стабильном 0.16 это все еще останется, и я, честно, не верю в то что они в ближайшее время избавятся от этого
Будем надеяться на лучшее. Давно на zig пишешь?
 
Будем надеяться на лучшее. Давно на zig пишешь?
года два вот, с 0.11 пришел. Чем больше кода и библиотек я пишу, тем больнее видеть breaking в патчноутах на самом деле. Виденье у Келли крутое, спорить сложно, но идти этот путь с ним тяжко, я не представляю как проекты типо bun или ghostty поддерживают.
 
года два вот, с 0.11 пришел. Чем больше кода и библиотек я пишу, тем больнее видеть breaking в патчноутах на самом деле. Виденье у Келли крутое, спорить сложно, но идти этот путь с ним тяжко, я не представляю как проекты типо bun или ghostty поддерживают.
Понял. А я с C# пришёл. Сделал вторым языком. Пишу на нём недели 3-4. По поводу обратной совместимости: там с каждой бетой они deprecated помечают функции которые в релизе будут переименованы. Наверно поэтому у ghostty, например, есть время понемногу переписывать всё (ну и сам проект популярный и там не только один разраб это всё пишет).
 
Назад
Сверху Снизу