| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | const debug = @import("./debug.zig");
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const math = @import("./math.zig");
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-29 16:04:27 +01:00
										 |  |  | const std = @import("std");
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | pub const AllocationError = error {
 | 
					
						
							|  |  |  | 	OutOfMemory,
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub const Allocator = struct {
 | 
					
						
							|  |  |  | 	context: *anyopaque,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions: *const struct {
 | 
					
						
							|  |  |  | 		deallocate: *const fn (context: *anyopaque, allocation: []Byte) void,
 | 
					
						
							|  |  |  | 		reallocate: *const fn (context: *anyopaque, return_address: usize, existing_allocation: ?[]Byte, size: usize) AllocationError![]Byte,
 | 
					
						
							|  |  |  | 	},
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pub fn Actions(comptime State: type) type {
 | 
					
						
							|  |  |  | 		return struct {
 | 
					
						
							|  |  |  | 			deallocate: fn (state: *State, allocation: []Byte) void,
 | 
					
						
							|  |  |  | 			reallocate: fn (state: *State, return_address: usize, existing_allocation: ?[]Byte, size: usize) AllocationError![]Byte,
 | 
					
						
							|  |  |  | 		};
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pub fn bind(comptime State: type, state: *State, comptime actions: Actions(State)) Allocator {
 | 
					
						
							|  |  |  | 		const is_zero_aligned = @alignOf(State) == 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 22:25:21 +01:00
										 |  |  | 		const ErasedActions = struct {
 | 
					
						
							|  |  |  | 			fn deallocate(context: *anyopaque, allocation: []Byte) void {
 | 
					
						
							|  |  |  | 				if (is_zero_aligned) {
 | 
					
						
							| 
									
										
										
										
											2023-07-30 14:33:41 +01:00
										 |  |  | 					return actions.deallocate(@ptrCast(context), allocation);
 | 
					
						
							| 
									
										
										
										
											2023-07-10 22:25:21 +01:00
										 |  |  | 				}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return actions.deallocate(@ptrCast(@alignCast(context)), allocation);
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			fn reallocate(context: *anyopaque, return_address: usize, existing_allocation: ?[]Byte, size: usize) AllocationError![]Byte {
 | 
					
						
							|  |  |  | 				if (is_zero_aligned) {
 | 
					
						
							| 
									
										
										
										
											2023-07-30 14:33:41 +01:00
										 |  |  | 					return actions.reallocate(@ptrCast(context), return_address, existing_allocation, size);
 | 
					
						
							| 
									
										
										
										
											2023-07-10 22:25:21 +01:00
										 |  |  | 				}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return actions.reallocate(@ptrCast(@alignCast(context)), return_address, existing_allocation, size);
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		};
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 		return .{
 | 
					
						
							|  |  |  | 			.context = if (is_zero_aligned) state else @ptrCast(state),
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			.actions = &.{
 | 
					
						
							| 
									
										
										
										
											2023-07-10 22:25:21 +01:00
										 |  |  | 				.deallocate = ErasedActions.deallocate,
 | 
					
						
							|  |  |  | 				.reallocate = ErasedActions.reallocate,
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 			}
 | 
					
						
							|  |  |  | 		};
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pub fn deallocate(self: Allocator, allocation: anytype) void {
 | 
					
						
							|  |  |  | 		switch (@typeInfo(@TypeOf(allocation))) {
 | 
					
						
							|  |  |  | 			.Pointer => |pointer| {
 | 
					
						
							|  |  |  | 				self.actions.deallocate(self.context, switch (pointer.size) {
 | 
					
						
							|  |  |  | 					.One => @as([*]Byte, @ptrCast(allocation))[0 .. @sizeOf(pointer.child)],
 | 
					
						
							|  |  |  | 					.Slice => @as([*]Byte, @ptrCast(allocation.ptr))[0 .. (@sizeOf(pointer.child) * allocation.len)],
 | 
					
						
							|  |  |  | 					.Many, .C => @compileError("length of allocation must be known to deallocate"),
 | 
					
						
							|  |  |  | 				});
 | 
					
						
							|  |  |  | 			},
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			else => @compileError("cannot deallocate " ++ allocation),
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pub fn reallocate(self: Allocator, allocation: ?[]Byte, allocation_size: usize) AllocationError![]Byte {
 | 
					
						
							|  |  |  | 		return self.actions.reallocate(self.context, @returnAddress(), allocation, allocation_size);
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub const Byte = u8;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub const FixedBuffer = struct {
 | 
					
						
							|  |  |  | 	bytes: []Byte,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pub fn as_writer(self: *FixedBuffer) Writer {
 | 
					
						
							|  |  |  | 		return Writer.bind(FixedBuffer, self, struct {
 | 
					
						
							|  |  |  | 			fn write(writable_memory: *FixedBuffer, data: []const Byte) ?usize {
 | 
					
						
							|  |  |  | 				return writable_memory.write(data);
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}.write);
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pub fn put(self: *FixedBuffer, byte: Byte) bool {
 | 
					
						
							|  |  |  | 		if (self.bytes.len == 0) {
 | 
					
						
							|  |  |  | 			return false;
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		self.bytes[0] = byte;
 | 
					
						
							|  |  |  | 		self.bytes = self.bytes[1 ..];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return true;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pub fn write(self: *FixedBuffer, bytes: []const Byte) usize {
 | 
					
						
							| 
									
										
										
										
											2023-07-22 13:57:39 +01:00
										 |  |  | 		const writable = @min(self.bytes.len, bytes.len);
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		copy(self.bytes, bytes);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		self.bytes = self.bytes[writable ..];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return writable;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub fn Functor(comptime Output: type, comptime Input: type) type {
 | 
					
						
							|  |  |  | 	return struct {
 | 
					
						
							|  |  |  | 		context: *const anyopaque,
 | 
					
						
							|  |  |  | 		invoker: *const fn (capture: *const anyopaque, input: Input) Output,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const Self = @This();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		pub fn bind(comptime State: type, state: *const State, comptime invoker: fn (capture: *const State, input: Input) Output) Self {
 | 
					
						
							|  |  |  | 			const is_zero_aligned = @alignOf(State) == 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 23:03:25 +01:00
										 |  |  | 			const Invoker = struct {
 | 
					
						
							|  |  |  | 				fn invoke(context: *const anyopaque, input: Input) Output {
 | 
					
						
							|  |  |  | 					if (is_zero_aligned) {
 | 
					
						
							|  |  |  | 						return invoker(@ptrCast(context), input);
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					return invoker(@ptrCast(@alignCast(context)), input);
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			};
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 			return .{
 | 
					
						
							|  |  |  | 				.context = if (is_zero_aligned) state else @ptrCast(state),
 | 
					
						
							| 
									
										
										
										
											2023-07-21 23:03:25 +01:00
										 |  |  | 				.invoker = Invoker.invoke,
 | 
					
						
							|  |  |  | 			};
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 23:03:25 +01:00
										 |  |  | 		pub fn from(comptime invoker: fn (input: Input) Output) Self {
 | 
					
						
							|  |  |  | 			const Invoker = struct {
 | 
					
						
							|  |  |  | 				fn invoke(_: *const anyopaque, input: Input) Output {
 | 
					
						
							|  |  |  | 					return invoker(input);
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			};
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-21 23:03:25 +01:00
										 |  |  | 			return .{
 | 
					
						
							|  |  |  | 				.context = &.{},
 | 
					
						
							|  |  |  | 				.invoker = Invoker.invoke,
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 			};
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		pub fn invoke(self: Self, input: Input) Output {
 | 
					
						
							|  |  |  | 			return self.invoker(self.context, input);
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	};
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub fn Generator(comptime Output: type, comptime Input: type) type {
 | 
					
						
							|  |  |  | 	return struct {
 | 
					
						
							|  |  |  | 		context: *anyopaque,
 | 
					
						
							|  |  |  | 		invoker: *const fn (capture: *anyopaque, input: Input) Output,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const Self = @This();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		pub fn bind(comptime State: type, state: *State, comptime invoker: fn (capture: *State, input: Input) Output) Self {
 | 
					
						
							|  |  |  | 			const is_zero_aligned = @alignOf(State) == 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return .{
 | 
					
						
							|  |  |  | 				.context = if (is_zero_aligned) state else @ptrCast(state),
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				.invoker = struct {
 | 
					
						
							|  |  |  | 					fn invoke(context: *anyopaque, input: Input) Output {
 | 
					
						
							|  |  |  | 						if (is_zero_aligned) {
 | 
					
						
							|  |  |  | 							return invoker(@ptrCast(context), input);
 | 
					
						
							|  |  |  | 						}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						return invoker(@ptrCast(@alignCast(context)), input);
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							|  |  |  | 				}.invoke,
 | 
					
						
							|  |  |  | 			};
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-16 00:34:28 +00:00
										 |  |  | 		pub fn from_fn(comptime invoker: fn (input: Input) Output) Self {
 | 
					
						
							| 
									
										
										
										
											2023-07-21 23:03:25 +01:00
										 |  |  | 			const Invoker = struct {
 | 
					
						
							|  |  |  | 				fn invoke(_: *const anyopaque, input: Input) Output {
 | 
					
						
							|  |  |  | 					return invoker(input);
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			};
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return .{
 | 
					
						
							|  |  |  | 				.context = &.{},
 | 
					
						
							|  |  |  | 				.invoker = Invoker.invoke,
 | 
					
						
							|  |  |  | 			};
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 		pub fn invoke(self: Self, input: Input) Output {
 | 
					
						
							|  |  |  | 			return self.invoker(self.context, input);
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	};
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub fn Tag(comptime Element: type) type {
 | 
					
						
							|  |  |  | 	return switch (@typeInfo(Element)) {
 | 
					
						
							|  |  |  | 		.Enum => |info| info.tag_type,
 | 
					
						
							|  |  |  | 		.Union => |info| info.tag_type orelse @compileError(@typeName(Element) ++ " has no tag type"),
 | 
					
						
							|  |  |  | 		else => @compileError("expected enum or union type, found '" ++ @typeName(Element) ++ "'"),
 | 
					
						
							|  |  |  | 	};
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub const Writer = Generator(?usize, []const Byte);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-13 13:54:31 +01:00
										 |  |  | pub fn all_equals(target: []const Byte, match: Byte) bool {
 | 
					
						
							|  |  |  | 	for (0 .. target.len) |index| {
 | 
					
						
							|  |  |  | 		if (target[index] != match) {
 | 
					
						
							|  |  |  | 			return false;
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-29 21:48:21 +00:00
										 |  |  | pub fn allocate_copy(comptime Element: type, allocator: Allocator, source: []const Element) AllocationError![]Element {
 | 
					
						
							|  |  |  | 	const allocation = try allocator.actions.reallocate(allocator.context, @returnAddress(), null, @sizeOf(Element) * source.len);
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-29 21:48:21 +00:00
										 |  |  | 	copy(allocation, bytes_of(source));
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-29 21:48:21 +00:00
										 |  |  | 	return @as([*]Element, @ptrCast(@alignCast(allocation.ptr)))[0 .. source.len];
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-29 16:04:27 +01:00
										 |  |  | pub fn allocate_many(allocator: Allocator, count: usize, value: anytype) AllocationError![]@TypeOf(value) {
 | 
					
						
							|  |  |  | 	const Type = @TypeOf(value);
 | 
					
						
							|  |  |  | 	const typeSize = @sizeOf(Type);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (typeSize == 0) {
 | 
					
						
							|  |  |  | 		@compileError("Cannot allocate memory for 0-byte sized type " ++ @typeName(Type));
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const allocations = @as([*]Type, @ptrCast(@alignCast(try allocator.actions.reallocate(
 | 
					
						
							|  |  |  | 		allocator.context,
 | 
					
						
							|  |  |  | 		@returnAddress(),
 | 
					
						
							|  |  |  | 		null,
 | 
					
						
							|  |  |  | 		typeSize * count))))[0 .. count];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (allocations) |*allocation| {
 | 
					
						
							|  |  |  | 		allocation.* = value;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return allocations;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | pub fn allocate_one(allocator: Allocator, value: anytype) AllocationError!*@TypeOf(value) {
 | 
					
						
							|  |  |  | 	const Type = @TypeOf(value);
 | 
					
						
							|  |  |  | 	const typeSize = @sizeOf(Type);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (typeSize == 0) {
 | 
					
						
							|  |  |  | 		@compileError("Cannot allocate memory for 0-byte sized type " ++ @typeName(Type));
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const allocation = @as(*Type, @ptrCast(@alignCast(try allocator.actions.reallocate(
 | 
					
						
							|  |  |  | 		allocator.context,
 | 
					
						
							|  |  |  | 		@returnAddress(),
 | 
					
						
							|  |  |  | 		null,
 | 
					
						
							|  |  |  | 		typeSize))));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	allocation.* = value;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return allocation;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-12 12:57:50 +01:00
										 |  |  | pub fn allocate_string(allocator: Allocator, source: []const Byte) AllocationError![:0]Byte {
 | 
					
						
							|  |  |  | 	const allocation = try allocator.actions.reallocate(allocator.context, @returnAddress(), null, source.len + 1);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	copy(allocation[0 .. source.len], source);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	allocation[source.len] = 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return @ptrCast(allocation);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-13 13:54:31 +01:00
										 |  |  | pub fn are_equal(target: []const Byte, match: []const Byte) bool {
 | 
					
						
							|  |  |  | 	if (target.len != match.len) {
 | 
					
						
							|  |  |  | 		return false;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (0 .. target.len) |index| {
 | 
					
						
							|  |  |  | 		if (target[index] != match[index]) {
 | 
					
						
							|  |  |  | 			return false;
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | pub fn bytes_of(value: anytype) []const Byte {
 | 
					
						
							|  |  |  | 	const pointer_info = @typeInfo(@TypeOf(value)).Pointer;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return switch (pointer_info.size) {
 | 
					
						
							|  |  |  | 		.One => @as([*]const Byte, @ptrCast(value))[0 .. @sizeOf(pointer_info.child)],
 | 
					
						
							|  |  |  | 		.Slice => @as([*]const Byte, @ptrCast(value.ptr))[0 .. @sizeOf(pointer_info.child) * value.len],
 | 
					
						
							|  |  |  | 		else => @compileError("`value` must be single-element pointer or slice type"),
 | 
					
						
							|  |  |  | 	};
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub fn copy(target: []Byte, source: []const Byte) void {
 | 
					
						
							|  |  |  | 	var index: usize = 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (index < source.len) : (index += 1) {
 | 
					
						
							|  |  |  | 		target[index] = source[index];
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-18 23:52:56 +01:00
										 |  |  | pub fn compare(this: []const Byte, that: []const Byte) isize {
 | 
					
						
							| 
									
										
										
										
											2023-07-22 13:57:39 +01:00
										 |  |  | 	const range = @min(this.len, that.len);
 | 
					
						
							| 
									
										
										
										
											2023-07-18 23:52:56 +01:00
										 |  |  | 	var index: usize = 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (index < range) : (index += 1) {
 | 
					
						
							|  |  |  | 		const difference = @as(isize, @intCast(this[index])) - @as(isize, @intCast(that[index]));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (difference != 0) {
 | 
					
						
							|  |  |  | 			return difference;
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return @as(isize, @intCast(this.len)) - @as(isize, @intCast(that.len));
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-29 16:04:27 +01:00
										 |  |  | pub fn djb2_hash(comptime int: std.builtin.Type.Int, target: []const Byte) math.Int(int) {
 | 
					
						
							|  |  |  | 	var hash_code = @as(math.Int(int), 5381);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (target) |byte| {
 | 
					
						
							|  |  |  | 		hash_code = ((hash_code << 5) +% hash_code) +% byte;
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return hash_code;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-12 12:57:50 +01:00
										 |  |  | pub fn find_first(haystack: []const Byte, needle: Byte) ?usize {
 | 
					
						
							|  |  |  | 	for (0 .. haystack.len) |i| {
 | 
					
						
							|  |  |  | 		if (haystack[i] == needle) {
 | 
					
						
							|  |  |  | 			return i;
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return null;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-13 02:03:43 +01:00
										 |  |  | pub fn jenkins_hash(comptime int: std.builtin.Type.Int, bytes: []const Byte) math.Int(int) {
 | 
					
						
							|  |  |  |     var hash = @as(math.Int(int), 0);
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-13 02:03:43 +01:00
										 |  |  |     for (bytes) |byte| {
 | 
					
						
							|  |  |  |         hash +%= byte;
 | 
					
						
							|  |  |  |         hash +%= (hash << 10);
 | 
					
						
							|  |  |  |         hash ^= (hash >> 6);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-13 02:03:43 +01:00
										 |  |  |     hash +%= (hash << 3);
 | 
					
						
							|  |  |  |     hash ^= (hash >> 11);
 | 
					
						
							|  |  |  |     hash +%= (hash << 15);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return hash;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-16 00:34:28 +00:00
										 |  |  | pub const null_writer = Writer.from_fn(write_null);
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | pub fn slice_sentineled(comptime sen: anytype, ptr: [*:sen]const @TypeOf(sen)) [:sen]const @TypeOf(sen) {
 | 
					
						
							|  |  |  |     var len = @as(usize, 0);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (ptr[len] != sen) {
 | 
					
						
							|  |  |  |         len += 1;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ptr[0 .. len:sen];
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub fn tag_of(comptime value: anytype) Tag(@TypeOf(value)) {
 | 
					
						
							|  |  |  | 	return @as(Tag(@TypeOf(value)), value);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-05 22:46:24 +00:00
										 |  |  | fn write_null(buffer: []const u8) ?usize {
 | 
					
						
							| 
									
										
										
										
											2023-08-13 02:03:43 +01:00
										 |  |  | 	return buffer.len;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 01:10:56 +01:00
										 |  |  | pub fn zero(target: []Byte) void {
 | 
					
						
							|  |  |  | 	for (target) |*t| t.* = 0;
 | 
					
						
							|  |  |  | }
 |