Уникальная группа
- Статус
- Оффлайн
- Регистрация
- 24 Сен 2024
- Сообщения
- 78
- Реакции
- 29
Доброго дня/ночи всем
. Небольшая структура для парсинга и векторного сравнения байтовых данных.
Использование:
C:
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:
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 }) });
}