| author | |
| committer | |
| log | 21df0010012b9a428f678a11586a50f24e54cf6f |
| tree | 7324b6cbf6f37ababd26392621f3ed70eb7ebb75 |
| parent | 3650cd3e8efd730fb6305bdefbbf8053c352bb0c |
bad API7 files changed, 595 insertions(+), 596 deletions(-)
CMakeLists.txt-1| ... | ... | @@ -434,7 +434,6 @@ set(ZIG_STAGE2_SOURCES |
| 434 | 434 | lib/std/dwarf/OP.zig |
| 435 | 435 | lib/std/dwarf/TAG.zig |
| 436 | 436 | lib/std/elf.zig |
| 437 | lib/std/fifo.zig | |
| 438 | 437 | lib/std/fmt.zig |
| 439 | 438 | lib/std/fmt/parse_float.zig |
| 440 | 439 | lib/std/fs.zig |
lib/compiler/resinator/compile.zig+1-3| ... | ... | @@ -1269,9 +1269,7 @@ pub const Compiler = struct { |
| 1269 | 1269 | pub fn writeResourceDataNoPadding(writer: anytype, data_reader: anytype, data_size: u32) !void { |
| 1270 | 1270 | var limited_reader = std.io.limitedReader(data_reader, data_size); |
| 1271 | 1271 | |
| 1272 | const FifoBuffer = std.fifo.LinearFifo(u8, .{ .Static = 4096 }); | |
| 1273 | var fifo = FifoBuffer.init(); | |
| 1274 | try fifo.pump(limited_reader.reader(), writer); | |
| 1272 | try limited_reader.reader().readRemaining(writer); | |
| 1275 | 1273 | } |
| 1276 | 1274 | |
| 1277 | 1275 | pub fn writeResourceData(writer: anytype, data_reader: anytype, data_size: u32) !void { |
lib/std/fifo.zig deleted-587| ... | ... | @@ -1,587 +0,0 @@ |
| 1 | // FIFO of fixed size items | |
| 2 | // Usually used for e.g. byte buffers | |
| 3 | ||
| 4 | const std = @import("std"); | |
| 5 | const math = std.math; | |
| 6 | const mem = std.mem; | |
| 7 | const Allocator = mem.Allocator; | |
| 8 | const assert = std.debug.assert; | |
| 9 | const testing = std.testing; | |
| 10 | ||
| 11 | pub const LinearFifoBufferType = union(enum) { | |
| 12 | /// The buffer is internal to the fifo; it is of the specified size. | |
| 13 | Static: usize, | |
| 14 | ||
| 15 | /// The buffer is passed as a slice to the initialiser. | |
| 16 | Slice, | |
| 17 | ||
| 18 | /// The buffer is managed dynamically using a `mem.Allocator`. | |
| 19 | Dynamic, | |
| 20 | }; | |
| 21 | ||
| 22 | pub fn LinearFifo( | |
| 23 | comptime T: type, | |
| 24 | comptime buffer_type: LinearFifoBufferType, | |
| 25 | ) type { | |
| 26 | const autoalign = false; | |
| 27 | ||
| 28 | const powers_of_two = switch (buffer_type) { | |
| 29 | .Static => std.math.isPowerOfTwo(buffer_type.Static), | |
| 30 | .Slice => false, // Any size slice could be passed in | |
| 31 | .Dynamic => true, // This could be configurable in future | |
| 32 | }; | |
| 33 | ||
| 34 | return struct { | |
| 35 | allocator: if (buffer_type == .Dynamic) Allocator else void, | |
| 36 | buf: if (buffer_type == .Static) [buffer_type.Static]T else []T, | |
| 37 | head: usize, | |
| 38 | count: usize, | |
| 39 | ||
| 40 | const Self = @This(); | |
| 41 | ||
| 42 | // Type of Self argument for slice operations. | |
| 43 | // If buffer is inline (Static) then we need to ensure we haven't | |
| 44 | // returned a slice into a copy on the stack | |
| 45 | const SliceSelfArg = if (buffer_type == .Static) *Self else Self; | |
| 46 | ||
| 47 | pub const init = switch (buffer_type) { | |
| 48 | .Static => initStatic, | |
| 49 | .Slice => initSlice, | |
| 50 | .Dynamic => initDynamic, | |
| 51 | }; | |
| 52 | ||
| 53 | fn initStatic() Self { | |
| 54 | comptime assert(buffer_type == .Static); | |
| 55 | return .{ | |
| 56 | .allocator = {}, | |
| 57 | .buf = undefined, | |
| 58 | .head = 0, | |
| 59 | .count = 0, | |
| 60 | }; | |
| 61 | } | |
| 62 | ||
| 63 | fn initSlice(buf: []T) Self { | |
| 64 | comptime assert(buffer_type == .Slice); | |
| 65 | return .{ | |
| 66 | .allocator = {}, | |
| 67 | .buf = buf, | |
| 68 | .head = 0, | |
| 69 | .count = 0, | |
| 70 | }; | |
| 71 | } | |
| 72 | ||
| 73 | fn initDynamic(allocator: Allocator) Self { | |
| 74 | comptime assert(buffer_type == .Dynamic); | |
| 75 | return .{ | |
| 76 | .allocator = allocator, | |
| 77 | .buf = &.{}, | |
| 78 | .head = 0, | |
| 79 | .count = 0, | |
| 80 | }; | |
| 81 | } | |
| 82 | ||
| 83 | pub fn deinit(self: Self) void { | |
| 84 | if (buffer_type == .Dynamic) self.allocator.free(self.buf); | |
| 85 | } | |
| 86 | ||
| 87 | pub fn realign(self: *Self) void { | |
| 88 | if (self.buf.len - self.head >= self.count) { | |
| 89 | mem.copyForwards(T, self.buf[0..self.count], self.buf[self.head..][0..self.count]); | |
| 90 | self.head = 0; | |
| 91 | } else { | |
| 92 | var tmp: [4096 / 2 / @sizeOf(T)]T = undefined; | |
| 93 | ||
| 94 | while (self.head != 0) { | |
| 95 | const n = @min(self.head, tmp.len); | |
| 96 | const m = self.buf.len - n; | |
| 97 | @memcpy(tmp[0..n], self.buf[0..n]); | |
| 98 | mem.copyForwards(T, self.buf[0..m], self.buf[n..][0..m]); | |
| 99 | @memcpy(self.buf[m..][0..n], tmp[0..n]); | |
| 100 | self.head -= n; | |
| 101 | } | |
| 102 | } | |
| 103 | { // set unused area to undefined | |
| 104 | const unused = mem.sliceAsBytes(self.buf[self.count..]); | |
| 105 | @memset(unused, undefined); | |
| 106 | } | |
| 107 | } | |
| 108 | ||
| 109 | /// Reduce allocated capacity to `size`. | |
| 110 | pub fn shrink(self: *Self, size: usize) void { | |
| 111 | assert(size >= self.count); | |
| 112 | if (buffer_type == .Dynamic) { | |
| 113 | self.realign(); | |
| 114 | self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) { | |
| 115 | error.OutOfMemory => return, // no problem, capacity is still correct then. | |
| 116 | }; | |
| 117 | } | |
| 118 | } | |
| 119 | ||
| 120 | /// Ensure that the buffer can fit at least `size` items | |
| 121 | pub fn ensureTotalCapacity(self: *Self, size: usize) !void { | |
| 122 | if (self.buf.len >= size) return; | |
| 123 | if (buffer_type == .Dynamic) { | |
| 124 | self.realign(); | |
| 125 | const new_size = if (powers_of_two) math.ceilPowerOfTwo(usize, size) catch return error.OutOfMemory else size; | |
| 126 | self.buf = try self.allocator.realloc(self.buf, new_size); | |
| 127 | } else { | |
| 128 | return error.OutOfMemory; | |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 132 | /// Makes sure at least `size` items are unused | |
| 133 | pub fn ensureUnusedCapacity(self: *Self, size: usize) error{OutOfMemory}!void { | |
| 134 | if (self.writableLength() >= size) return; | |
| 135 | ||
| 136 | return try self.ensureTotalCapacity(math.add(usize, self.count, size) catch return error.OutOfMemory); | |
| 137 | } | |
| 138 | ||
| 139 | /// Returns number of items currently in fifo | |
| 140 | pub fn readableLength(self: Self) usize { | |
| 141 | return self.count; | |
| 142 | } | |
| 143 | ||
| 144 | /// Returns a writable slice from the 'read' end of the fifo | |
| 145 | fn readableSliceMut(self: SliceSelfArg, offset: usize) []T { | |
| 146 | if (offset > self.count) return &[_]T{}; | |
| 147 | ||
| 148 | var start = self.head + offset; | |
| 149 | if (start >= self.buf.len) { | |
| 150 | start -= self.buf.len; | |
| 151 | return self.buf[start .. start + (self.count - offset)]; | |
| 152 | } else { | |
| 153 | const end = @min(self.head + self.count, self.buf.len); | |
| 154 | return self.buf[start..end]; | |
| 155 | } | |
| 156 | } | |
| 157 | ||
| 158 | /// Returns a readable slice from `offset` | |
| 159 | pub fn readableSlice(self: SliceSelfArg, offset: usize) []const T { | |
| 160 | return self.readableSliceMut(offset); | |
| 161 | } | |
| 162 | ||
| 163 | pub fn readableSliceOfLen(self: *Self, len: usize) []const T { | |
| 164 | assert(len <= self.count); | |
| 165 | const buf = self.readableSlice(0); | |
| 166 | if (buf.len >= len) { | |
| 167 | return buf[0..len]; | |
| 168 | } else { | |
| 169 | self.realign(); | |
| 170 | return self.readableSlice(0)[0..len]; | |
| 171 | } | |
| 172 | } | |
| 173 | ||
| 174 | /// Discard first `count` items in the fifo | |
| 175 | pub fn discard(self: *Self, count: usize) void { | |
| 176 | assert(count <= self.count); | |
| 177 | { // set old range to undefined. Note: may be wrapped around | |
| 178 | const slice = self.readableSliceMut(0); | |
| 179 | if (slice.len >= count) { | |
| 180 | const unused = mem.sliceAsBytes(slice[0..count]); | |
| 181 | @memset(unused, undefined); | |
| 182 | } else { | |
| 183 | const unused = mem.sliceAsBytes(slice[0..]); | |
| 184 | @memset(unused, undefined); | |
| 185 | const unused2 = mem.sliceAsBytes(self.readableSliceMut(slice.len)[0 .. count - slice.len]); | |
| 186 | @memset(unused2, undefined); | |
| 187 | } | |
| 188 | } | |
| 189 | if (autoalign and self.count == count) { | |
| 190 | self.head = 0; | |
| 191 | self.count = 0; | |
| 192 | } else { | |
| 193 | var head = self.head + count; | |
| 194 | if (powers_of_two) { | |
| 195 | // Note it is safe to do a wrapping subtract as | |
| 196 | // bitwise & with all 1s is a noop | |
| 197 | head &= self.buf.len -% 1; | |
| 198 | } else { | |
| 199 | head %= self.buf.len; | |
| 200 | } | |
| 201 | self.head = head; | |
| 202 | self.count -= count; | |
| 203 | } | |
| 204 | } | |
| 205 | ||
| 206 | /// Read the next item from the fifo | |
| 207 | pub fn readItem(self: *Self) ?T { | |
| 208 | if (self.count == 0) return null; | |
| 209 | ||
| 210 | const c = self.buf[self.head]; | |
| 211 | self.discard(1); | |
| 212 | return c; | |
| 213 | } | |
| 214 | ||
| 215 | /// Read data from the fifo into `dst`, returns number of items copied. | |
| 216 | pub fn read(self: *Self, dst: []T) usize { | |
| 217 | var dst_left = dst; | |
| 218 | ||
| 219 | while (dst_left.len > 0) { | |
| 220 | const slice = self.readableSlice(0); | |
| 221 | if (slice.len == 0) break; | |
| 222 | const n = @min(slice.len, dst_left.len); | |
| 223 | @memcpy(dst_left[0..n], slice[0..n]); | |
| 224 | self.discard(n); | |
| 225 | dst_left = dst_left[n..]; | |
| 226 | } | |
| 227 | ||
| 228 | return dst.len - dst_left.len; | |
| 229 | } | |
| 230 | ||
| 231 | /// Same as `read` except it returns an error union | |
| 232 | /// The purpose of this function existing is to match `std.io.Reader` API. | |
| 233 | fn readFn(self: *Self, dest: []u8) error{}!usize { | |
| 234 | return self.read(dest); | |
| 235 | } | |
| 236 | ||
| 237 | pub fn reader(self: *Self) std.io.Reader { | |
| 238 | return .{ | |
| 239 | .context = self, | |
| 240 | .vtable = &.{ | |
| 241 | .read = &readerRead, | |
| 242 | .readVec = &readerReadVec, | |
| 243 | .discard = &readerDiscard, | |
| 244 | }, | |
| 245 | }; | |
| 246 | } | |
| 247 | fn readerRead( | |
| 248 | ctx: ?*anyopaque, | |
| 249 | bw: *std.io.BufferedWriter, | |
| 250 | limit: std.io.Limit, | |
| 251 | ) std.io.Reader.RwError!usize { | |
| 252 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 253 | _ = fifo; | |
| 254 | _ = bw; | |
| 255 | _ = limit; | |
| 256 | @panic("TODO"); | |
| 257 | } | |
| 258 | fn readerReadVec(ctx: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { | |
| 259 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 260 | _ = fifo; | |
| 261 | _ = data; | |
| 262 | @panic("TODO"); | |
| 263 | } | |
| 264 | fn readerDiscard(ctx: ?*anyopaque, limit: std.io.Limit) std.io.Reader.Error!usize { | |
| 265 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 266 | _ = fifo; | |
| 267 | _ = limit; | |
| 268 | @panic("TODO"); | |
| 269 | } | |
| 270 | ||
| 271 | /// Returns number of items available in fifo | |
| 272 | pub fn writableLength(self: Self) usize { | |
| 273 | return self.buf.len - self.count; | |
| 274 | } | |
| 275 | ||
| 276 | /// Returns the first section of writable buffer. | |
| 277 | /// Note that this may be of length 0 | |
| 278 | pub fn writableSlice(self: SliceSelfArg, offset: usize) []T { | |
| 279 | if (offset > self.buf.len) return &[_]T{}; | |
| 280 | ||
| 281 | const tail = self.head + offset + self.count; | |
| 282 | if (tail < self.buf.len) { | |
| 283 | return self.buf[tail..]; | |
| 284 | } else { | |
| 285 | return self.buf[tail - self.buf.len ..][0 .. self.writableLength() - offset]; | |
| 286 | } | |
| 287 | } | |
| 288 | ||
| 289 | /// Returns a writable buffer of at least `size` items, allocating memory as needed. | |
| 290 | /// Use `fifo.update` once you've written data to it. | |
| 291 | pub fn writableWithSize(self: *Self, size: usize) ![]T { | |
| 292 | try self.ensureUnusedCapacity(size); | |
| 293 | ||
| 294 | // try to avoid realigning buffer | |
| 295 | var slice = self.writableSlice(0); | |
| 296 | if (slice.len < size) { | |
| 297 | self.realign(); | |
| 298 | slice = self.writableSlice(0); | |
| 299 | } | |
| 300 | return slice; | |
| 301 | } | |
| 302 | ||
| 303 | /// Update the tail location of the buffer (usually follows use of writable/writableWithSize) | |
| 304 | pub fn update(self: *Self, count: usize) void { | |
| 305 | assert(self.count + count <= self.buf.len); | |
| 306 | self.count += count; | |
| 307 | } | |
| 308 | ||
| 309 | /// Appends the data in `src` to the fifo. | |
| 310 | /// You must have ensured there is enough space. | |
| 311 | pub fn writeAssumeCapacity(self: *Self, src: []const T) void { | |
| 312 | assert(self.writableLength() >= src.len); | |
| 313 | ||
| 314 | var src_left = src; | |
| 315 | while (src_left.len > 0) { | |
| 316 | const writable_slice = self.writableSlice(0); | |
| 317 | assert(writable_slice.len != 0); | |
| 318 | const n = @min(writable_slice.len, src_left.len); | |
| 319 | @memcpy(writable_slice[0..n], src_left[0..n]); | |
| 320 | self.update(n); | |
| 321 | src_left = src_left[n..]; | |
| 322 | } | |
| 323 | } | |
| 324 | ||
| 325 | /// Write a single item to the fifo | |
| 326 | pub fn writeItem(self: *Self, item: T) !void { | |
| 327 | try self.ensureUnusedCapacity(1); | |
| 328 | return self.writeItemAssumeCapacity(item); | |
| 329 | } | |
| 330 | ||
| 331 | pub fn writeItemAssumeCapacity(self: *Self, item: T) void { | |
| 332 | var tail = self.head + self.count; | |
| 333 | if (powers_of_two) { | |
| 334 | tail &= self.buf.len - 1; | |
| 335 | } else { | |
| 336 | tail %= self.buf.len; | |
| 337 | } | |
| 338 | self.buf[tail] = item; | |
| 339 | self.update(1); | |
| 340 | } | |
| 341 | ||
| 342 | /// Appends the data in `src` to the fifo. | |
| 343 | /// Allocates more memory as necessary | |
| 344 | pub fn write(self: *Self, src: []const T) !void { | |
| 345 | try self.ensureUnusedCapacity(src.len); | |
| 346 | ||
| 347 | return self.writeAssumeCapacity(src); | |
| 348 | } | |
| 349 | ||
| 350 | /// Same as `write` except it returns the number of bytes written, which is always the same | |
| 351 | /// as `bytes.len`. The purpose of this function existing is to match `std.io.Writer` API. | |
| 352 | fn appendWrite(self: *Self, bytes: []const u8) error{OutOfMemory}!usize { | |
| 353 | try self.write(bytes); | |
| 354 | return bytes.len; | |
| 355 | } | |
| 356 | ||
| 357 | pub fn writer(fifo: *Self) std.io.Writer { | |
| 358 | return .{ | |
| 359 | .context = fifo, | |
| 360 | .vtable = &.{ | |
| 361 | .writeSplat = writerWriteSplat, | |
| 362 | .writeFile = writerWriteFile, | |
| 363 | }, | |
| 364 | }; | |
| 365 | } | |
| 366 | fn writerWriteSplat(ctx: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { | |
| 367 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 368 | _ = fifo; | |
| 369 | _ = data; | |
| 370 | _ = splat; | |
| 371 | @panic("TODO"); | |
| 372 | } | |
| 373 | fn writerWriteFile( | |
| 374 | ctx: ?*anyopaque, | |
| 375 | file: std.fs.File, | |
| 376 | offset: std.io.Writer.Offset, | |
| 377 | limit: std.io.Writer.Limit, | |
| 378 | headers_and_trailers: []const []const u8, | |
| 379 | headers_len: usize, | |
| 380 | ) std.io.Writer.Error!usize { | |
| 381 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 382 | _ = fifo; | |
| 383 | _ = file; | |
| 384 | _ = offset; | |
| 385 | _ = limit; | |
| 386 | _ = headers_and_trailers; | |
| 387 | _ = headers_len; | |
| 388 | @panic("TODO"); | |
| 389 | } | |
| 390 | ||
| 391 | /// Make `count` items available before the current read location | |
| 392 | fn rewind(self: *Self, count: usize) void { | |
| 393 | assert(self.writableLength() >= count); | |
| 394 | ||
| 395 | var head = self.head + (self.buf.len - count); | |
| 396 | if (powers_of_two) { | |
| 397 | head &= self.buf.len - 1; | |
| 398 | } else { | |
| 399 | head %= self.buf.len; | |
| 400 | } | |
| 401 | self.head = head; | |
| 402 | self.count += count; | |
| 403 | } | |
| 404 | ||
| 405 | /// Place data back into the read stream | |
| 406 | pub fn unget(self: *Self, src: []const T) !void { | |
| 407 | try self.ensureUnusedCapacity(src.len); | |
| 408 | ||
| 409 | self.rewind(src.len); | |
| 410 | ||
| 411 | const slice = self.readableSliceMut(0); | |
| 412 | if (src.len < slice.len) { | |
| 413 | @memcpy(slice[0..src.len], src); | |
| 414 | } else { | |
| 415 | @memcpy(slice, src[0..slice.len]); | |
| 416 | const slice2 = self.readableSliceMut(slice.len); | |
| 417 | @memcpy(slice2[0 .. src.len - slice.len], src[slice.len..]); | |
| 418 | } | |
| 419 | } | |
| 420 | ||
| 421 | /// Returns the item at `offset`. | |
| 422 | /// Asserts offset is within bounds. | |
| 423 | pub fn peekItem(self: Self, offset: usize) T { | |
| 424 | assert(offset < self.count); | |
| 425 | ||
| 426 | var index = self.head + offset; | |
| 427 | if (powers_of_two) { | |
| 428 | index &= self.buf.len - 1; | |
| 429 | } else { | |
| 430 | index %= self.buf.len; | |
| 431 | } | |
| 432 | return self.buf[index]; | |
| 433 | } | |
| 434 | ||
| 435 | pub fn toOwnedSlice(self: *Self) Allocator.Error![]T { | |
| 436 | if (self.head != 0) self.realign(); | |
| 437 | assert(self.head == 0); | |
| 438 | assert(self.count <= self.buf.len); | |
| 439 | const allocator = self.allocator; | |
| 440 | if (allocator.resize(self.buf, self.count)) { | |
| 441 | const result = self.buf[0..self.count]; | |
| 442 | self.* = Self.init(allocator); | |
| 443 | return result; | |
| 444 | } | |
| 445 | const new_memory = try allocator.dupe(T, self.buf[0..self.count]); | |
| 446 | allocator.free(self.buf); | |
| 447 | self.* = Self.init(allocator); | |
| 448 | return new_memory; | |
| 449 | } | |
| 450 | }; | |
| 451 | } | |
| 452 | ||
| 453 | test "LinearFifo(u8, .Dynamic) discard(0) from empty buffer should not error on overflow" { | |
| 454 | var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator); | |
| 455 | defer fifo.deinit(); | |
| 456 | ||
| 457 | // If overflow is not explicitly allowed this will crash in debug / safe mode | |
| 458 | fifo.discard(0); | |
| 459 | } | |
| 460 | ||
| 461 | test "LinearFifo(u8, .Dynamic)" { | |
| 462 | var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator); | |
| 463 | defer fifo.deinit(); | |
| 464 | ||
| 465 | try fifo.write("HELLO"); | |
| 466 | try testing.expectEqual(@as(usize, 5), fifo.readableLength()); | |
| 467 | try testing.expectEqualSlices(u8, "HELLO", fifo.readableSlice(0)); | |
| 468 | ||
| 469 | { | |
| 470 | var i: usize = 0; | |
| 471 | while (i < 5) : (i += 1) { | |
| 472 | try fifo.write(&[_]u8{fifo.peekItem(i)}); | |
| 473 | } | |
| 474 | try testing.expectEqual(@as(usize, 10), fifo.readableLength()); | |
| 475 | try testing.expectEqualSlices(u8, "HELLOHELLO", fifo.readableSlice(0)); | |
| 476 | } | |
| 477 | ||
| 478 | { | |
| 479 | try testing.expectEqual(@as(u8, 'H'), fifo.readItem().?); | |
| 480 | try testing.expectEqual(@as(u8, 'E'), fifo.readItem().?); | |
| 481 | try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?); | |
| 482 | try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?); | |
| 483 | try testing.expectEqual(@as(u8, 'O'), fifo.readItem().?); | |
| 484 | } | |
| 485 | try testing.expectEqual(@as(usize, 5), fifo.readableLength()); | |
| 486 | ||
| 487 | { // Writes that wrap around | |
| 488 | try testing.expectEqual(@as(usize, 11), fifo.writableLength()); | |
| 489 | try testing.expectEqual(@as(usize, 6), fifo.writableSlice(0).len); | |
| 490 | fifo.writeAssumeCapacity("6<chars<11"); | |
| 491 | try testing.expectEqualSlices(u8, "HELLO6<char", fifo.readableSlice(0)); | |
| 492 | try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(11)); | |
| 493 | try testing.expectEqualSlices(u8, "11", fifo.readableSlice(13)); | |
| 494 | try testing.expectEqualSlices(u8, "", fifo.readableSlice(15)); | |
| 495 | fifo.discard(11); | |
| 496 | try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(0)); | |
| 497 | fifo.discard(4); | |
| 498 | try testing.expectEqual(@as(usize, 0), fifo.readableLength()); | |
| 499 | } | |
| 500 | ||
| 501 | { | |
| 502 | const buf = try fifo.writableWithSize(12); | |
| 503 | try testing.expectEqual(@as(usize, 12), buf.len); | |
| 504 | var i: u8 = 0; | |
| 505 | while (i < 10) : (i += 1) { | |
| 506 | buf[i] = i + 'a'; | |
| 507 | } | |
| 508 | fifo.update(10); | |
| 509 | try testing.expectEqualSlices(u8, "abcdefghij", fifo.readableSlice(0)); | |
| 510 | } | |
| 511 | ||
| 512 | { | |
| 513 | try fifo.unget("prependedstring"); | |
| 514 | var result: [30]u8 = undefined; | |
| 515 | try testing.expectEqualSlices(u8, "prependedstringabcdefghij", result[0..fifo.read(&result)]); | |
| 516 | try fifo.unget("b"); | |
| 517 | try fifo.unget("a"); | |
| 518 | try testing.expectEqualSlices(u8, "ab", result[0..fifo.read(&result)]); | |
| 519 | } | |
| 520 | ||
| 521 | fifo.shrink(0); | |
| 522 | ||
| 523 | { | |
| 524 | try fifo.writer().print("{s}, {s}!", .{ "Hello", "World" }); | |
| 525 | var result: [30]u8 = undefined; | |
| 526 | try testing.expectEqualSlices(u8, "Hello, World!", result[0..fifo.read(&result)]); | |
| 527 | try testing.expectEqual(@as(usize, 0), fifo.readableLength()); | |
| 528 | } | |
| 529 | ||
| 530 | { | |
| 531 | try fifo.writer().writeAll("This is a test"); | |
| 532 | var result: [30]u8 = undefined; | |
| 533 | try testing.expectEqualSlices(u8, "This", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?); | |
| 534 | try testing.expectEqualSlices(u8, "is", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?); | |
| 535 | try testing.expectEqualSlices(u8, "a", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?); | |
| 536 | try testing.expectEqualSlices(u8, "test", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?); | |
| 537 | } | |
| 538 | ||
| 539 | { | |
| 540 | try fifo.ensureTotalCapacity(1); | |
| 541 | var in_fbs = std.io.fixedBufferStream("pump test"); | |
| 542 | var out_buf: [50]u8 = undefined; | |
| 543 | var out_fbs = std.io.fixedBufferStream(&out_buf); | |
| 544 | try fifo.pump(in_fbs.reader(), out_fbs.writer()); | |
| 545 | try testing.expectEqualSlices(u8, in_fbs.buffer, out_fbs.getWritten()); | |
| 546 | } | |
| 547 | } | |
| 548 | ||
| 549 | test LinearFifo { | |
| 550 | inline for ([_]type{ u1, u8, u16, u64 }) |T| { | |
| 551 | inline for ([_]LinearFifoBufferType{ LinearFifoBufferType{ .Static = 32 }, .Slice, .Dynamic }) |bt| { | |
| 552 | const FifoType = LinearFifo(T, bt); | |
| 553 | var buf: if (bt == .Slice) [32]T else void = undefined; | |
| 554 | var fifo = switch (bt) { | |
| 555 | .Static => FifoType.init(), | |
| 556 | .Slice => FifoType.init(buf[0..]), | |
| 557 | .Dynamic => FifoType.init(testing.allocator), | |
| 558 | }; | |
| 559 | defer fifo.deinit(); | |
| 560 | ||
| 561 | try fifo.write(&[_]T{ 0, 1, 1, 0, 1 }); | |
| 562 | try testing.expectEqual(@as(usize, 5), fifo.readableLength()); | |
| 563 | ||
| 564 | { | |
| 565 | try testing.expectEqual(@as(T, 0), fifo.readItem().?); | |
| 566 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); | |
| 567 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); | |
| 568 | try testing.expectEqual(@as(T, 0), fifo.readItem().?); | |
| 569 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); | |
| 570 | try testing.expectEqual(@as(usize, 0), fifo.readableLength()); | |
| 571 | } | |
| 572 | ||
| 573 | { | |
| 574 | try fifo.writeItem(1); | |
| 575 | try fifo.writeItem(1); | |
| 576 | try fifo.writeItem(1); | |
| 577 | try testing.expectEqual(@as(usize, 3), fifo.readableLength()); | |
| 578 | } | |
| 579 | ||
| 580 | { | |
| 581 | var readBuf: [3]T = undefined; | |
| 582 | const n = fifo.read(&readBuf); | |
| 583 | try testing.expectEqual(@as(usize, 3), n); // NOTE: It should be the number of items. | |
| 584 | } | |
| 585 | } | |
| 586 | } | |
| 587 | } |
lib/std/std.zig-1| ... | ... | @@ -58,7 +58,6 @@ pub const debug = @import("debug.zig"); |
| 58 | 58 | pub const dwarf = @import("dwarf.zig"); |
| 59 | 59 | pub const elf = @import("elf.zig"); |
| 60 | 60 | pub const enums = @import("enums.zig"); |
| 61 | pub const fifo = @import("fifo.zig"); | |
| 62 | 61 | pub const fmt = @import("fmt.zig"); |
| 63 | 62 | pub const fs = @import("fs.zig"); |
| 64 | 63 | pub const gpu = @import("gpu.zig"); |
src/Compilation.zig+5-3| ... | ... | @@ -44,6 +44,8 @@ const Builtin = @import("Builtin.zig"); |
| 44 | 44 | const LlvmObject = @import("codegen/llvm.zig").Object; |
| 45 | 45 | const dev = @import("dev.zig"); |
| 46 | 46 | |
| 47 | const DeprecatedLinearFifo = @import("deprecated.zig").LinearFifo; | |
| 48 | ||
| 47 | 49 | pub const Config = @import("Compilation/Config.zig"); |
| 48 | 50 | |
| 49 | 51 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| ... | ... | @@ -121,15 +123,15 @@ work_queues: [ |
| 121 | 123 | } |
| 122 | 124 | break :len len; |
| 123 | 125 | } |
| 124 | ]std.fifo.LinearFifo(Job, .Dynamic), | |
| 126 | ]DeprecatedLinearFifo(Job), | |
| 125 | 127 | |
| 126 | 128 | /// These jobs are to invoke the Clang compiler to create an object file, which |
| 127 | 129 | /// gets linked with the Compilation. |
| 128 | c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic), | |
| 130 | c_object_work_queue: DeprecatedLinearFifo(*CObject), | |
| 129 | 131 | |
| 130 | 132 | /// These jobs are to invoke the RC compiler to create a compiled resource file (.res), which |
| 131 | 133 | /// gets linked with the Compilation. |
| 132 | win32_resource_work_queue: if (dev.env.supports(.win32_resource)) std.fifo.LinearFifo(*Win32Resource, .Dynamic) else struct { | |
| 134 | win32_resource_work_queue: if (dev.env.supports(.win32_resource)) DeprecatedLinearFifo(*Win32Resource) else struct { | |
| 133 | 135 | pub fn ensureUnusedCapacity(_: @This(), _: u0) error{}!void {} |
| 134 | 136 | pub fn readItem(_: @This()) ?noreturn { |
| 135 | 137 | return null; |
src/deprecated.zig created+587| ... | ... | @@ -0,0 +1,587 @@ |
| 1 | // FIFO of fixed size items | |
| 2 | // Usually used for e.g. byte buffers | |
| 3 | ||
| 4 | const std = @import("std"); | |
| 5 | const math = std.math; | |
| 6 | const mem = std.mem; | |
| 7 | const Allocator = mem.Allocator; | |
| 8 | const assert = std.debug.assert; | |
| 9 | const testing = std.testing; | |
| 10 | ||
| 11 | pub const LinearFifoBufferType = union(enum) { | |
| 12 | /// The buffer is internal to the fifo; it is of the specified size. | |
| 13 | Static: usize, | |
| 14 | ||
| 15 | /// The buffer is passed as a slice to the initialiser. | |
| 16 | Slice, | |
| 17 | ||
| 18 | /// The buffer is managed dynamically using a `mem.Allocator`. | |
| 19 | Dynamic, | |
| 20 | }; | |
| 21 | ||
| 22 | pub fn LinearFifo( | |
| 23 | comptime T: type, | |
| 24 | comptime buffer_type: LinearFifoBufferType, | |
| 25 | ) type { | |
| 26 | const autoalign = false; | |
| 27 | ||
| 28 | const powers_of_two = switch (buffer_type) { | |
| 29 | .Static => std.math.isPowerOfTwo(buffer_type.Static), | |
| 30 | .Slice => false, // Any size slice could be passed in | |
| 31 | .Dynamic => true, // This could be configurable in future | |
| 32 | }; | |
| 33 | ||
| 34 | return struct { | |
| 35 | allocator: if (buffer_type == .Dynamic) Allocator else void, | |
| 36 | buf: if (buffer_type == .Static) [buffer_type.Static]T else []T, | |
| 37 | head: usize, | |
| 38 | count: usize, | |
| 39 | ||
| 40 | const Self = @This(); | |
| 41 | ||
| 42 | // Type of Self argument for slice operations. | |
| 43 | // If buffer is inline (Static) then we need to ensure we haven't | |
| 44 | // returned a slice into a copy on the stack | |
| 45 | const SliceSelfArg = if (buffer_type == .Static) *Self else Self; | |
| 46 | ||
| 47 | pub const init = switch (buffer_type) { | |
| 48 | .Static => initStatic, | |
| 49 | .Slice => initSlice, | |
| 50 | .Dynamic => initDynamic, | |
| 51 | }; | |
| 52 | ||
| 53 | fn initStatic() Self { | |
| 54 | comptime assert(buffer_type == .Static); | |
| 55 | return .{ | |
| 56 | .allocator = {}, | |
| 57 | .buf = undefined, | |
| 58 | .head = 0, | |
| 59 | .count = 0, | |
| 60 | }; | |
| 61 | } | |
| 62 | ||
| 63 | fn initSlice(buf: []T) Self { | |
| 64 | comptime assert(buffer_type == .Slice); | |
| 65 | return .{ | |
| 66 | .allocator = {}, | |
| 67 | .buf = buf, | |
| 68 | .head = 0, | |
| 69 | .count = 0, | |
| 70 | }; | |
| 71 | } | |
| 72 | ||
| 73 | fn initDynamic(allocator: Allocator) Self { | |
| 74 | comptime assert(buffer_type == .Dynamic); | |
| 75 | return .{ | |
| 76 | .allocator = allocator, | |
| 77 | .buf = &.{}, | |
| 78 | .head = 0, | |
| 79 | .count = 0, | |
| 80 | }; | |
| 81 | } | |
| 82 | ||
| 83 | pub fn deinit(self: Self) void { | |
| 84 | if (buffer_type == .Dynamic) self.allocator.free(self.buf); | |
| 85 | } | |
| 86 | ||
| 87 | pub fn realign(self: *Self) void { | |
| 88 | if (self.buf.len - self.head >= self.count) { | |
| 89 | mem.copyForwards(T, self.buf[0..self.count], self.buf[self.head..][0..self.count]); | |
| 90 | self.head = 0; | |
| 91 | } else { | |
| 92 | var tmp: [4096 / 2 / @sizeOf(T)]T = undefined; | |
| 93 | ||
| 94 | while (self.head != 0) { | |
| 95 | const n = @min(self.head, tmp.len); | |
| 96 | const m = self.buf.len - n; | |
| 97 | @memcpy(tmp[0..n], self.buf[0..n]); | |
| 98 | mem.copyForwards(T, self.buf[0..m], self.buf[n..][0..m]); | |
| 99 | @memcpy(self.buf[m..][0..n], tmp[0..n]); | |
| 100 | self.head -= n; | |
| 101 | } | |
| 102 | } | |
| 103 | { // set unused area to undefined | |
| 104 | const unused = mem.sliceAsBytes(self.buf[self.count..]); | |
| 105 | @memset(unused, undefined); | |
| 106 | } | |
| 107 | } | |
| 108 | ||
| 109 | /// Reduce allocated capacity to `size`. | |
| 110 | pub fn shrink(self: *Self, size: usize) void { | |
| 111 | assert(size >= self.count); | |
| 112 | if (buffer_type == .Dynamic) { | |
| 113 | self.realign(); | |
| 114 | self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) { | |
| 115 | error.OutOfMemory => return, // no problem, capacity is still correct then. | |
| 116 | }; | |
| 117 | } | |
| 118 | } | |
| 119 | ||
| 120 | /// Ensure that the buffer can fit at least `size` items | |
| 121 | pub fn ensureTotalCapacity(self: *Self, size: usize) !void { | |
| 122 | if (self.buf.len >= size) return; | |
| 123 | if (buffer_type == .Dynamic) { | |
| 124 | self.realign(); | |
| 125 | const new_size = if (powers_of_two) math.ceilPowerOfTwo(usize, size) catch return error.OutOfMemory else size; | |
| 126 | self.buf = try self.allocator.realloc(self.buf, new_size); | |
| 127 | } else { | |
| 128 | return error.OutOfMemory; | |
| 129 | } | |
| 130 | } | |
| 131 | ||
| 132 | /// Makes sure at least `size` items are unused | |
| 133 | pub fn ensureUnusedCapacity(self: *Self, size: usize) error{OutOfMemory}!void { | |
| 134 | if (self.writableLength() >= size) return; | |
| 135 | ||
| 136 | return try self.ensureTotalCapacity(math.add(usize, self.count, size) catch return error.OutOfMemory); | |
| 137 | } | |
| 138 | ||
| 139 | /// Returns number of items currently in fifo | |
| 140 | pub fn readableLength(self: Self) usize { | |
| 141 | return self.count; | |
| 142 | } | |
| 143 | ||
| 144 | /// Returns a writable slice from the 'read' end of the fifo | |
| 145 | fn readableSliceMut(self: SliceSelfArg, offset: usize) []T { | |
| 146 | if (offset > self.count) return &[_]T{}; | |
| 147 | ||
| 148 | var start = self.head + offset; | |
| 149 | if (start >= self.buf.len) { | |
| 150 | start -= self.buf.len; | |
| 151 | return self.buf[start .. start + (self.count - offset)]; | |
| 152 | } else { | |
| 153 | const end = @min(self.head + self.count, self.buf.len); | |
| 154 | return self.buf[start..end]; | |
| 155 | } | |
| 156 | } | |
| 157 | ||
| 158 | /// Returns a readable slice from `offset` | |
| 159 | pub fn readableSlice(self: SliceSelfArg, offset: usize) []const T { | |
| 160 | return self.readableSliceMut(offset); | |
| 161 | } | |
| 162 | ||
| 163 | pub fn readableSliceOfLen(self: *Self, len: usize) []const T { | |
| 164 | assert(len <= self.count); | |
| 165 | const buf = self.readableSlice(0); | |
| 166 | if (buf.len >= len) { | |
| 167 | return buf[0..len]; | |
| 168 | } else { | |
| 169 | self.realign(); | |
| 170 | return self.readableSlice(0)[0..len]; | |
| 171 | } | |
| 172 | } | |
| 173 | ||
| 174 | /// Discard first `count` items in the fifo | |
| 175 | pub fn discard(self: *Self, count: usize) void { | |
| 176 | assert(count <= self.count); | |
| 177 | { // set old range to undefined. Note: may be wrapped around | |
| 178 | const slice = self.readableSliceMut(0); | |
| 179 | if (slice.len >= count) { | |
| 180 | const unused = mem.sliceAsBytes(slice[0..count]); | |
| 181 | @memset(unused, undefined); | |
| 182 | } else { | |
| 183 | const unused = mem.sliceAsBytes(slice[0..]); | |
| 184 | @memset(unused, undefined); | |
| 185 | const unused2 = mem.sliceAsBytes(self.readableSliceMut(slice.len)[0 .. count - slice.len]); | |
| 186 | @memset(unused2, undefined); | |
| 187 | } | |
| 188 | } | |
| 189 | if (autoalign and self.count == count) { | |
| 190 | self.head = 0; | |
| 191 | self.count = 0; | |
| 192 | } else { | |
| 193 | var head = self.head + count; | |
| 194 | if (powers_of_two) { | |
| 195 | // Note it is safe to do a wrapping subtract as | |
| 196 | // bitwise & with all 1s is a noop | |
| 197 | head &= self.buf.len -% 1; | |
| 198 | } else { | |
| 199 | head %= self.buf.len; | |
| 200 | } | |
| 201 | self.head = head; | |
| 202 | self.count -= count; | |
| 203 | } | |
| 204 | } | |
| 205 | ||
| 206 | /// Read the next item from the fifo | |
| 207 | pub fn readItem(self: *Self) ?T { | |
| 208 | if (self.count == 0) return null; | |
| 209 | ||
| 210 | const c = self.buf[self.head]; | |
| 211 | self.discard(1); | |
| 212 | return c; | |
| 213 | } | |
| 214 | ||
| 215 | /// Read data from the fifo into `dst`, returns number of items copied. | |
| 216 | pub fn read(self: *Self, dst: []T) usize { | |
| 217 | var dst_left = dst; | |
| 218 | ||
| 219 | while (dst_left.len > 0) { | |
| 220 | const slice = self.readableSlice(0); | |
| 221 | if (slice.len == 0) break; | |
| 222 | const n = @min(slice.len, dst_left.len); | |
| 223 | @memcpy(dst_left[0..n], slice[0..n]); | |
| 224 | self.discard(n); | |
| 225 | dst_left = dst_left[n..]; | |
| 226 | } | |
| 227 | ||
| 228 | return dst.len - dst_left.len; | |
| 229 | } | |
| 230 | ||
| 231 | /// Same as `read` except it returns an error union | |
| 232 | /// The purpose of this function existing is to match `std.io.Reader` API. | |
| 233 | fn readFn(self: *Self, dest: []u8) error{}!usize { | |
| 234 | return self.read(dest); | |
| 235 | } | |
| 236 | ||
| 237 | pub fn reader(self: *Self) std.io.Reader { | |
| 238 | return .{ | |
| 239 | .context = self, | |
| 240 | .vtable = &.{ | |
| 241 | .read = &readerRead, | |
| 242 | .readVec = &readerReadVec, | |
| 243 | .discard = &readerDiscard, | |
| 244 | }, | |
| 245 | }; | |
| 246 | } | |
| 247 | fn readerRead( | |
| 248 | ctx: ?*anyopaque, | |
| 249 | bw: *std.io.BufferedWriter, | |
| 250 | limit: std.io.Limit, | |
| 251 | ) std.io.Reader.RwError!usize { | |
| 252 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 253 | _ = fifo; | |
| 254 | _ = bw; | |
| 255 | _ = limit; | |
| 256 | @panic("TODO"); | |
| 257 | } | |
| 258 | fn readerReadVec(ctx: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { | |
| 259 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 260 | _ = fifo; | |
| 261 | _ = data; | |
| 262 | @panic("TODO"); | |
| 263 | } | |
| 264 | fn readerDiscard(ctx: ?*anyopaque, limit: std.io.Limit) std.io.Reader.Error!usize { | |
| 265 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 266 | _ = fifo; | |
| 267 | _ = limit; | |
| 268 | @panic("TODO"); | |
| 269 | } | |
| 270 | ||
| 271 | /// Returns number of items available in fifo | |
| 272 | pub fn writableLength(self: Self) usize { | |
| 273 | return self.buf.len - self.count; | |
| 274 | } | |
| 275 | ||
| 276 | /// Returns the first section of writable buffer. | |
| 277 | /// Note that this may be of length 0 | |
| 278 | pub fn writableSlice(self: SliceSelfArg, offset: usize) []T { | |
| 279 | if (offset > self.buf.len) return &[_]T{}; | |
| 280 | ||
| 281 | const tail = self.head + offset + self.count; | |
| 282 | if (tail < self.buf.len) { | |
| 283 | return self.buf[tail..]; | |
| 284 | } else { | |
| 285 | return self.buf[tail - self.buf.len ..][0 .. self.writableLength() - offset]; | |
| 286 | } | |
| 287 | } | |
| 288 | ||
| 289 | /// Returns a writable buffer of at least `size` items, allocating memory as needed. | |
| 290 | /// Use `fifo.update` once you've written data to it. | |
| 291 | pub fn writableWithSize(self: *Self, size: usize) ![]T { | |
| 292 | try self.ensureUnusedCapacity(size); | |
| 293 | ||
| 294 | // try to avoid realigning buffer | |
| 295 | var slice = self.writableSlice(0); | |
| 296 | if (slice.len < size) { | |
| 297 | self.realign(); | |
| 298 | slice = self.writableSlice(0); | |
| 299 | } | |
| 300 | return slice; | |
| 301 | } | |
| 302 | ||
| 303 | /// Update the tail location of the buffer (usually follows use of writable/writableWithSize) | |
| 304 | pub fn update(self: *Self, count: usize) void { | |
| 305 | assert(self.count + count <= self.buf.len); | |
| 306 | self.count += count; | |
| 307 | } | |
| 308 | ||
| 309 | /// Appends the data in `src` to the fifo. | |
| 310 | /// You must have ensured there is enough space. | |
| 311 | pub fn writeAssumeCapacity(self: *Self, src: []const T) void { | |
| 312 | assert(self.writableLength() >= src.len); | |
| 313 | ||
| 314 | var src_left = src; | |
| 315 | while (src_left.len > 0) { | |
| 316 | const writable_slice = self.writableSlice(0); | |
| 317 | assert(writable_slice.len != 0); | |
| 318 | const n = @min(writable_slice.len, src_left.len); | |
| 319 | @memcpy(writable_slice[0..n], src_left[0..n]); | |
| 320 | self.update(n); | |
| 321 | src_left = src_left[n..]; | |
| 322 | } | |
| 323 | } | |
| 324 | ||
| 325 | /// Write a single item to the fifo | |
| 326 | pub fn writeItem(self: *Self, item: T) !void { | |
| 327 | try self.ensureUnusedCapacity(1); | |
| 328 | return self.writeItemAssumeCapacity(item); | |
| 329 | } | |
| 330 | ||
| 331 | pub fn writeItemAssumeCapacity(self: *Self, item: T) void { | |
| 332 | var tail = self.head + self.count; | |
| 333 | if (powers_of_two) { | |
| 334 | tail &= self.buf.len - 1; | |
| 335 | } else { | |
| 336 | tail %= self.buf.len; | |
| 337 | } | |
| 338 | self.buf[tail] = item; | |
| 339 | self.update(1); | |
| 340 | } | |
| 341 | ||
| 342 | /// Appends the data in `src` to the fifo. | |
| 343 | /// Allocates more memory as necessary | |
| 344 | pub fn write(self: *Self, src: []const T) !void { | |
| 345 | try self.ensureUnusedCapacity(src.len); | |
| 346 | ||
| 347 | return self.writeAssumeCapacity(src); | |
| 348 | } | |
| 349 | ||
| 350 | /// Same as `write` except it returns the number of bytes written, which is always the same | |
| 351 | /// as `bytes.len`. The purpose of this function existing is to match `std.io.Writer` API. | |
| 352 | fn appendWrite(self: *Self, bytes: []const u8) error{OutOfMemory}!usize { | |
| 353 | try self.write(bytes); | |
| 354 | return bytes.len; | |
| 355 | } | |
| 356 | ||
| 357 | pub fn writer(fifo: *Self) std.io.Writer { | |
| 358 | return .{ | |
| 359 | .context = fifo, | |
| 360 | .vtable = &.{ | |
| 361 | .writeSplat = writerWriteSplat, | |
| 362 | .writeFile = writerWriteFile, | |
| 363 | }, | |
| 364 | }; | |
| 365 | } | |
| 366 | fn writerWriteSplat(ctx: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { | |
| 367 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 368 | _ = fifo; | |
| 369 | _ = data; | |
| 370 | _ = splat; | |
| 371 | @panic("TODO"); | |
| 372 | } | |
| 373 | fn writerWriteFile( | |
| 374 | ctx: ?*anyopaque, | |
| 375 | file: std.fs.File, | |
| 376 | offset: std.io.Writer.Offset, | |
| 377 | limit: std.io.Writer.Limit, | |
| 378 | headers_and_trailers: []const []const u8, | |
| 379 | headers_len: usize, | |
| 380 | ) std.io.Writer.Error!usize { | |
| 381 | const fifo: *Self = @alignCast(@ptrCast(ctx)); | |
| 382 | _ = fifo; | |
| 383 | _ = file; | |
| 384 | _ = offset; | |
| 385 | _ = limit; | |
| 386 | _ = headers_and_trailers; | |
| 387 | _ = headers_len; | |
| 388 | @panic("TODO"); | |
| 389 | } | |
| 390 | ||
| 391 | /// Make `count` items available before the current read location | |
| 392 | fn rewind(self: *Self, count: usize) void { | |
| 393 | assert(self.writableLength() >= count); | |
| 394 | ||
| 395 | var head = self.head + (self.buf.len - count); | |
| 396 | if (powers_of_two) { | |
| 397 | head &= self.buf.len - 1; | |
| 398 | } else { | |
| 399 | head %= self.buf.len; | |
| 400 | } | |
| 401 | self.head = head; | |
| 402 | self.count += count; | |
| 403 | } | |
| 404 | ||
| 405 | /// Place data back into the read stream | |
| 406 | pub fn unget(self: *Self, src: []const T) !void { | |
| 407 | try self.ensureUnusedCapacity(src.len); | |
| 408 | ||
| 409 | self.rewind(src.len); | |
| 410 | ||
| 411 | const slice = self.readableSliceMut(0); | |
| 412 | if (src.len < slice.len) { | |
| 413 | @memcpy(slice[0..src.len], src); | |
| 414 | } else { | |
| 415 | @memcpy(slice, src[0..slice.len]); | |
| 416 | const slice2 = self.readableSliceMut(slice.len); | |
| 417 | @memcpy(slice2[0 .. src.len - slice.len], src[slice.len..]); | |
| 418 | } | |
| 419 | } | |
| 420 | ||
| 421 | /// Returns the item at `offset`. | |
| 422 | /// Asserts offset is within bounds. | |
| 423 | pub fn peekItem(self: Self, offset: usize) T { | |
| 424 | assert(offset < self.count); | |
| 425 | ||
| 426 | var index = self.head + offset; | |
| 427 | if (powers_of_two) { | |
| 428 | index &= self.buf.len - 1; | |
| 429 | } else { | |
| 430 | index %= self.buf.len; | |
| 431 | } | |
| 432 | return self.buf[index]; | |
| 433 | } | |
| 434 | ||
| 435 | pub fn toOwnedSlice(self: *Self) Allocator.Error![]T { | |
| 436 | if (self.head != 0) self.realign(); | |
| 437 | assert(self.head == 0); | |
| 438 | assert(self.count <= self.buf.len); | |
| 439 | const allocator = self.allocator; | |
| 440 | if (allocator.resize(self.buf, self.count)) { | |
| 441 | const result = self.buf[0..self.count]; | |
| 442 | self.* = Self.init(allocator); | |
| 443 | return result; | |
| 444 | } | |
| 445 | const new_memory = try allocator.dupe(T, self.buf[0..self.count]); | |
| 446 | allocator.free(self.buf); | |
| 447 | self.* = Self.init(allocator); | |
| 448 | return new_memory; | |
| 449 | } | |
| 450 | }; | |
| 451 | } | |
| 452 | ||
| 453 | test "LinearFifo(u8, .Dynamic) discard(0) from empty buffer should not error on overflow" { | |
| 454 | var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator); | |
| 455 | defer fifo.deinit(); | |
| 456 | ||
| 457 | // If overflow is not explicitly allowed this will crash in debug / safe mode | |
| 458 | fifo.discard(0); | |
| 459 | } | |
| 460 | ||
| 461 | test "LinearFifo(u8, .Dynamic)" { | |
| 462 | var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator); | |
| 463 | defer fifo.deinit(); | |
| 464 | ||
| 465 | try fifo.write("HELLO"); | |
| 466 | try testing.expectEqual(@as(usize, 5), fifo.readableLength()); | |
| 467 | try testing.expectEqualSlices(u8, "HELLO", fifo.readableSlice(0)); | |
| 468 | ||
| 469 | { | |
| 470 | var i: usize = 0; | |
| 471 | while (i < 5) : (i += 1) { | |
| 472 | try fifo.write(&[_]u8{fifo.peekItem(i)}); | |
| 473 | } | |
| 474 | try testing.expectEqual(@as(usize, 10), fifo.readableLength()); | |
| 475 | try testing.expectEqualSlices(u8, "HELLOHELLO", fifo.readableSlice(0)); | |
| 476 | } | |
| 477 | ||
| 478 | { | |
| 479 | try testing.expectEqual(@as(u8, 'H'), fifo.readItem().?); | |
| 480 | try testing.expectEqual(@as(u8, 'E'), fifo.readItem().?); | |
| 481 | try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?); | |
| 482 | try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?); | |
| 483 | try testing.expectEqual(@as(u8, 'O'), fifo.readItem().?); | |
| 484 | } | |
| 485 | try testing.expectEqual(@as(usize, 5), fifo.readableLength()); | |
| 486 | ||
| 487 | { // Writes that wrap around | |
| 488 | try testing.expectEqual(@as(usize, 11), fifo.writableLength()); | |
| 489 | try testing.expectEqual(@as(usize, 6), fifo.writableSlice(0).len); | |
| 490 | fifo.writeAssumeCapacity("6<chars<11"); | |
| 491 | try testing.expectEqualSlices(u8, "HELLO6<char", fifo.readableSlice(0)); | |
| 492 | try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(11)); | |
| 493 | try testing.expectEqualSlices(u8, "11", fifo.readableSlice(13)); | |
| 494 | try testing.expectEqualSlices(u8, "", fifo.readableSlice(15)); | |
| 495 | fifo.discard(11); | |
| 496 | try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(0)); | |
| 497 | fifo.discard(4); | |
| 498 | try testing.expectEqual(@as(usize, 0), fifo.readableLength()); | |
| 499 | } | |
| 500 | ||
| 501 | { | |
| 502 | const buf = try fifo.writableWithSize(12); | |
| 503 | try testing.expectEqual(@as(usize, 12), buf.len); | |
| 504 | var i: u8 = 0; | |
| 505 | while (i < 10) : (i += 1) { | |
| 506 | buf[i] = i + 'a'; | |
| 507 | } | |
| 508 | fifo.update(10); | |
| 509 | try testing.expectEqualSlices(u8, "abcdefghij", fifo.readableSlice(0)); | |
| 510 | } | |
| 511 | ||
| 512 | { | |
| 513 | try fifo.unget("prependedstring"); | |
| 514 | var result: [30]u8 = undefined; | |
| 515 | try testing.expectEqualSlices(u8, "prependedstringabcdefghij", result[0..fifo.read(&result)]); | |
| 516 | try fifo.unget("b"); | |
| 517 | try fifo.unget("a"); | |
| 518 | try testing.expectEqualSlices(u8, "ab", result[0..fifo.read(&result)]); | |
| 519 | } | |
| 520 | ||
| 521 | fifo.shrink(0); | |
| 522 | ||
| 523 | { | |
| 524 | try fifo.writer().print("{s}, {s}!", .{ "Hello", "World" }); | |
| 525 | var result: [30]u8 = undefined; | |
| 526 | try testing.expectEqualSlices(u8, "Hello, World!", result[0..fifo.read(&result)]); | |
| 527 | try testing.expectEqual(@as(usize, 0), fifo.readableLength()); | |
| 528 | } | |
| 529 | ||
| 530 | { | |
| 531 | try fifo.writer().writeAll("This is a test"); | |
| 532 | var result: [30]u8 = undefined; | |
| 533 | try testing.expectEqualSlices(u8, "This", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?); | |
| 534 | try testing.expectEqualSlices(u8, "is", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?); | |
| 535 | try testing.expectEqualSlices(u8, "a", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?); | |
| 536 | try testing.expectEqualSlices(u8, "test", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?); | |
| 537 | } | |
| 538 | ||
| 539 | { | |
| 540 | try fifo.ensureTotalCapacity(1); | |
| 541 | var in_fbs = std.io.fixedBufferStream("pump test"); | |
| 542 | var out_buf: [50]u8 = undefined; | |
| 543 | var out_fbs = std.io.fixedBufferStream(&out_buf); | |
| 544 | try fifo.pump(in_fbs.reader(), out_fbs.writer()); | |
| 545 | try testing.expectEqualSlices(u8, in_fbs.buffer, out_fbs.getWritten()); | |
| 546 | } | |
| 547 | } | |
| 548 | ||
| 549 | test LinearFifo { | |
| 550 | inline for ([_]type{ u1, u8, u16, u64 }) |T| { | |
| 551 | inline for ([_]LinearFifoBufferType{ LinearFifoBufferType{ .Static = 32 }, .Slice, .Dynamic }) |bt| { | |
| 552 | const FifoType = LinearFifo(T, bt); | |
| 553 | var buf: if (bt == .Slice) [32]T else void = undefined; | |
| 554 | var fifo = switch (bt) { | |
| 555 | .Static => FifoType.init(), | |
| 556 | .Slice => FifoType.init(buf[0..]), | |
| 557 | .Dynamic => FifoType.init(testing.allocator), | |
| 558 | }; | |
| 559 | defer fifo.deinit(); | |
| 560 | ||
| 561 | try fifo.write(&[_]T{ 0, 1, 1, 0, 1 }); | |
| 562 | try testing.expectEqual(@as(usize, 5), fifo.readableLength()); | |
| 563 | ||
| 564 | { | |
| 565 | try testing.expectEqual(@as(T, 0), fifo.readItem().?); | |
| 566 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); | |
| 567 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); | |
| 568 | try testing.expectEqual(@as(T, 0), fifo.readItem().?); | |
| 569 | try testing.expectEqual(@as(T, 1), fifo.readItem().?); | |
| 570 | try testing.expectEqual(@as(usize, 0), fifo.readableLength()); | |
| 571 | } | |
| 572 | ||
| 573 | { | |
| 574 | try fifo.writeItem(1); | |
| 575 | try fifo.writeItem(1); | |
| 576 | try fifo.writeItem(1); | |
| 577 | try testing.expectEqual(@as(usize, 3), fifo.readableLength()); | |
| 578 | } | |
| 579 | ||
| 580 | { | |
| 581 | var readBuf: [3]T = undefined; | |
| 582 | const n = fifo.read(&readBuf); | |
| 583 | try testing.expectEqual(@as(usize, 3), n); // NOTE: It should be the number of items. | |
| 584 | } | |
| 585 | } | |
| 586 | } | |
| 587 | } |
src/link/MachO/dyld_info/Trie.zig+2-1| ... | ... | @@ -138,7 +138,7 @@ fn finalize(self: *Trie, allocator: Allocator) !void { |
| 138 | 138 | defer ordered_nodes.deinit(); |
| 139 | 139 | try ordered_nodes.ensureTotalCapacityPrecise(self.nodes.items(.is_terminal).len); |
| 140 | 140 | |
| 141 | var fifo = std.fifo.LinearFifo(Node.Index, .Dynamic).init(allocator); | |
| 141 | var fifo = DeprecatedLinearFifo(Node.Index).init(allocator); | |
| 142 | 142 | defer fifo.deinit(); |
| 143 | 143 | |
| 144 | 144 | try fifo.writeItem(self.root.?); |
| ... | ... | @@ -409,6 +409,7 @@ const mem = std.mem; |
| 409 | 409 | const std = @import("std"); |
| 410 | 410 | const testing = std.testing; |
| 411 | 411 | const trace = @import("../../../tracy.zig").trace; |
| 412 | const DeprecatedLinearFifo = @import("../../../deprecated.zig").LinearFifo; | |
| 412 | 413 | |
| 413 | 414 | const Allocator = mem.Allocator; |
| 414 | 415 | const MachO = @import("../../MachO.zig"); |