const std = @import("std"); const zid = @import("ZipponData"); const dtype = @import("dtype"); const ConditionValue = @import("../dataStructure/filter.zig").ConditionValue; const ArrayCondition = @import("../ziql/parts//newData.zig").ArrayCondition; // This shouldn't be here, to move somewhere, idk yet /// Update an array based on keyword like append or remove pub fn updateData(allocator: std.mem.Allocator, condition: ArrayCondition, input: *zid.Data, data: ?ConditionValue) !void { std.debug.print("HERE {any}\n", .{condition}); try switch (condition) { .append => append(allocator, input, data.?), .pop => pop(allocator, input), .clear => clear(allocator, input), .remove => remove(allocator, input, data.?), .removeat => removeat(allocator, input, data.?), }; } // This does not work, I think because I cant access the value at the pointer and so not update it. // Maybe if I return instead ? fn popInline(input: *zid.Data) void { inline for (comptime std.meta.fields(zid.Data)) |field| { if (comptime std.mem.endsWith(u8, field.name, "Array")) { if (@field(input, field.name).len > 8) { // If array is not empty, only 8 bytes mean that there is just the size of the array that's encode, meaning a u64 of 8 bytes @field(input.*, field.name) = @field(input, field.name)[0 .. @field(input, field.name).len - input.size()]; } } } } fn pop(allocator: std.mem.Allocator, input: *zid.Data) !void { var updated_array = std.ArrayList(u8).init(allocator); errdefer updated_array.deinit(); var new_len: ?u64 = null; if (input.size() > 8) switch (input.*) { .IntArray => |v| try updated_array.appendSlice(v[0 .. v.len - @sizeOf(i32)]), .FloatArray => |v| try updated_array.appendSlice(v[0 .. v.len - @sizeOf(f64)]), .UnixArray => |v| try updated_array.appendSlice(v[0 .. v.len - @sizeOf(u64)]), .UUIDArray => |v| try updated_array.appendSlice(v[0 .. v.len - @sizeOf([16]u8)]), .BoolArray => |v| try updated_array.appendSlice(v[0 .. v.len - @sizeOf(bool)]), .StrArray => |v| { var iter = try zid.ArrayIterator.init(input.*); var last_str: []const u8 = undefined; while (iter.next()) |item| last_str = item.Str; try updated_array.appendSlice(v[0 .. v.len - last_str.len - 8]); new_len = input.size() - 16 - last_str.len; }, else => unreachable, } else { new_len = 0; } new_len = new_len orelse updated_array.items.len - 8; @memcpy(updated_array.items[0..@sizeOf(u64)], std.mem.asBytes(&new_len.?)); switch (input.*) { .IntArray => input.*.IntArray = try updated_array.toOwnedSlice(), .FloatArray => input.*.FloatArray = try updated_array.toOwnedSlice(), .UnixArray => input.*.UnixArray = try updated_array.toOwnedSlice(), .UUIDArray => input.*.UUIDArray = try updated_array.toOwnedSlice(), .BoolArray => input.*.BoolArray = try updated_array.toOwnedSlice(), .StrArray => input.*.StrArray = try updated_array.toOwnedSlice(), else => unreachable, } } fn clear(allocator: std.mem.Allocator, input: *zid.Data) void { var updated_array = std.ArrayList(u8).init(allocator); errdefer updated_array.deinit(); switch (input.*) { .IntArray => input.*.IntArray = zid.allocEncodArray.Empty(), .FloatArray => input.*.FloatArray = zid.allocEncodArray.Empty(), .UnixArray => input.*.UnixArray = zid.allocEncodArray.Empty(), .UUIDArray => input.*.UUIDArray = zid.allocEncodArray.Empty(), .BoolArray => input.*.BoolArray = zid.allocEncodArray.Empty(), .StrArray => input.*.StrArray = zid.allocEncodArray.Empty(), else => unreachable, } } // I think I could use meta programming here by adding the type as argument fn append(allocator: std.mem.Allocator, input: *zid.Data, data: ConditionValue) !void { var updated_array = std.ArrayList(u8).init(allocator); errdefer updated_array.deinit(); switch (input.*) { .IntArray, .FloatArray, .UnixArray, .BoolArray, .StrArray, .UUIDArray, => |v| try updated_array.appendSlice(v), else => unreachable, } var new_len: usize = 0; switch (data) { .int => |v| { try updated_array.appendSlice(std.mem.asBytes(&v)); new_len = input.size() - 8 + @sizeOf(i32); }, .float => |v| { try updated_array.appendSlice(std.mem.asBytes(&v)); new_len = input.size() - 8 + @sizeOf(f64); }, .unix => |v| { try updated_array.appendSlice(std.mem.asBytes(&v)); new_len = input.size() - 8 + @sizeOf(u64); }, .bool_ => |v| { try updated_array.appendSlice(std.mem.asBytes(&v)); new_len = input.size() - 8 + @sizeOf(bool); }, .str => |v| { try updated_array.appendSlice(std.mem.asBytes(&v.len)); try updated_array.appendSlice(v); new_len = input.size() + v.len - 8; }, .int_array => |v| { const new_array = try zid.allocEncodArray.Int(allocator, v); defer allocator.free(new_array); try updated_array.appendSlice(new_array[8..]); new_len = input.size() + new_array.len - 16; }, .float_array => |v| { const new_array = try zid.allocEncodArray.Float(allocator, v); defer allocator.free(new_array); try updated_array.appendSlice(new_array[8..]); new_len = input.size() + new_array.len - 16; }, .bool_array => |v| { const new_array = try zid.allocEncodArray.Bool(allocator, v); defer allocator.free(new_array); try updated_array.appendSlice(new_array[8..]); new_len = input.size() + new_array.len - 16; }, .str_array => |v| { const new_array = try zid.allocEncodArray.Str(allocator, v); defer allocator.free(new_array); try updated_array.appendSlice(new_array[8..]); new_len = input.size() + new_array.len - 16; }, .unix_array => |v| { const new_array = try zid.allocEncodArray.Unix(allocator, v); defer allocator.free(new_array); try updated_array.appendSlice(new_array[8..]); new_len = input.size() + new_array.len - 16; }, else => unreachable, } @memcpy(updated_array.items[0..@sizeOf(u64)], std.mem.asBytes(&new_len)); switch (input.*) { .IntArray => input.*.IntArray = try updated_array.toOwnedSlice(), .FloatArray => input.*.FloatArray = try updated_array.toOwnedSlice(), .UnixArray => input.*.UnixArray = try updated_array.toOwnedSlice(), .UUIDArray => input.*.UUIDArray = try updated_array.toOwnedSlice(), .BoolArray => input.*.BoolArray = try updated_array.toOwnedSlice(), .StrArray => input.*.StrArray = try updated_array.toOwnedSlice(), else => unreachable, } } // TODO: Change the array for a map to speed up thing // And also I dont really need to realoc anything, only append need because here it can only go lower // So I could just memcopy the remaining of the bytes at the current position, so it overwrite the value to remove // Like if I want to re;ove 3 in [1 2 3 4 5], it would become [1 2 4 5 5]. Then I dont take the last value when I return. // But that mean I keep in memory useless data, so maybe not fn remove(allocator: std.mem.Allocator, input: *zid.Data, data: ConditionValue) !void { var iter = try zid.ArrayIterator.init(input.*); switch (input.*) { .IntArray => { var array = std.ArrayList(i32).init(allocator); defer array.deinit(); while (iter.next()) |v| if (!in(v, data)) try array.append(v.Int); input.*.IntArray = try zid.allocEncodArray.Int(allocator, array.items); }, .FloatArray => { var array = std.ArrayList(f64).init(allocator); defer array.deinit(); while (iter.next()) |v| if (!in(v, data)) try array.append(v.Float); input.*.FloatArray = try zid.allocEncodArray.Float(allocator, array.items); }, .UnixArray => { var array = std.ArrayList(u64).init(allocator); defer array.deinit(); while (iter.next()) |v| if (!in(v, data)) try array.append(v.Unix); input.*.UnixArray = try zid.allocEncodArray.Unix(allocator, array.items); }, .BoolArray => { var array = std.ArrayList(bool).init(allocator); defer array.deinit(); while (iter.next()) |v| if (!in(v, data)) try array.append(v.Bool); input.*.BoolArray = try zid.allocEncodArray.Bool(allocator, array.items); }, .StrArray => { var array = std.ArrayList([]const u8).init(allocator); defer array.deinit(); while (iter.next()) |v| if (!in(v, data)) try array.append(v.Str); input.*.StrArray = try zid.allocEncodArray.Str(allocator, array.items); }, .UUIDArray => { var array = std.ArrayList([16]u8).init(allocator); defer array.deinit(); while (iter.next()) |v| if (!in(v, data)) try array.append(v.UUID); input.*.UUIDArray = try zid.allocEncodArray.UUID(allocator, array.items); }, else => unreachable, } } fn removeat(allocator: std.mem.Allocator, input: *zid.Data, data: ConditionValue) !void { var iter = try zid.ArrayIterator.init(input.*); switch (input.*) { .IntArray => { var array = std.ArrayList(i32).init(allocator); defer array.deinit(); var i: i32 = 0; // Maybe use usize because here it limite the size of the array while (iter.next()) |v| { defer i += 1; if (!in(zid.Data{ .Int = i }, data)) try array.append(v.Int); } input.*.IntArray = try zid.allocEncodArray.Int(allocator, array.items); }, .FloatArray => { var array = std.ArrayList(f64).init(allocator); defer array.deinit(); var i: i32 = 0; // Maybe use usize because here it limite the size of the array while (iter.next()) |v| { defer i += 1; if (!in(zid.Data{ .Int = i }, data)) try array.append(v.Float); } input.*.FloatArray = try zid.allocEncodArray.Float(allocator, array.items); }, .UnixArray => { var array = std.ArrayList(u64).init(allocator); defer array.deinit(); var i: i32 = 0; // Maybe use usize because here it limite the size of the array while (iter.next()) |v| { defer i += 1; if (!in(zid.Data{ .Int = i }, data)) try array.append(v.Unix); } input.*.UnixArray = try zid.allocEncodArray.Unix(allocator, array.items); }, .BoolArray => { var array = std.ArrayList(bool).init(allocator); defer array.deinit(); var i: i32 = 0; // Maybe use usize because here it limite the size of the array while (iter.next()) |v| { defer i += 1; if (!in(zid.Data{ .Int = i }, data)) try array.append(v.Bool); } input.*.BoolArray = try zid.allocEncodArray.Bool(allocator, array.items); }, .StrArray => { var array = std.ArrayList([]const u8).init(allocator); defer array.deinit(); var i: i32 = 0; // Maybe use usize because here it limite the size of the array while (iter.next()) |v| { defer i += 1; if (!in(zid.Data{ .Int = i }, data)) try array.append(v.Str); } input.*.StrArray = try zid.allocEncodArray.Str(allocator, array.items); }, .UUIDArray => unreachable, // I cant do that for removeat because link don't really have order else => unreachable, } } // TODO: Use a map.contain for the ConditionValue // Specially because I end up iterate over the list for all entity, when I just need to make the map one time for all fn in(x: zid.Data, y: ConditionValue) bool { switch (x) { .Int => |v| for (y.int_array) |z| if (v == z) return true, .Float => |v| for (y.float_array) |z| if (v == z) return true, .Unix => |v| for (y.unix_array) |z| if (v == z) return true, .Bool => |v| for (y.bool_array) |z| if (v == z) return true, .Str => |v| for (y.str_array) |z| if (std.mem.eql(u8, z, v)) return true, .UUID => |v| if (y.link_array.contains(dtype.UUID{ .bytes = v })) return true, else => unreachable, } return false; }