| ... | ... | @@ -28,18 +28,23 @@ pub const Streams = extern struct { |
| 28 | 28 | len: u32, |
| 29 | 29 | |
| 30 | 30 | pub fn contexts(s: *Streams) []Context { |
| 31 | | _ = s; |
| 32 | | @panic("TODO"); |
| 31 | const base: usize = @intFromPtr(s); |
| 32 | const ptr: [*]Context = @ptrFromInt(std.mem.alignForward(usize, base + @sizeOf(Streams), @alignOf(Context))); |
| 33 | return ptr[0..s.len]; |
| 33 | 34 | } |
| 34 | 35 | |
| 35 | 36 | pub fn ring(s: *Streams) []u32 { |
| 36 | | _ = s; |
| 37 | | @panic("TODO"); |
| 37 | const prev = contexts(s); |
| 38 | const end = prev.ptr + prev.len; |
| 39 | const ptr: [*]u32 = @ptrFromInt(std.mem.alignForward(usize, @intFromPtr(end), @alignOf(u32))); |
| 40 | return ptr[0..s.len]; |
| 38 | 41 | } |
| 39 | 42 | |
| 40 | 43 | pub fn operations(s: *Streams) []Io.Operation { |
| 41 | | _ = s; |
| 42 | | @panic("TODO"); |
| 44 | const prev = ring(s); |
| 45 | const end = prev.ptr + prev.len; |
| 46 | const ptr: [*]Io.Operation = @ptrFromInt(std.mem.alignForward(usize, @intFromPtr(end), @alignOf(Io.Operation))); |
| 47 | return ptr[0..s.len]; |
| 43 | 48 | } |
| 44 | 49 | }; |
| 45 | 50 | |
| ... | ... | @@ -51,6 +56,7 @@ pub fn Buffer(comptime n: usize) type { |
| 51 | 56 | operations: [n][@sizeOf(Io.Operation)]u8 align(@alignOf(Io.Operation)), |
| 52 | 57 | |
| 53 | 58 | pub fn toStreams(b: *@This()) *Streams { |
| 59 | b.len = n; |
| 54 | 60 | return @ptrCast(b); |
| 55 | 61 | } |
| 56 | 62 | }; |
| ... | ... | @@ -157,61 +163,43 @@ fn stream(r: *Io.Reader, w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!u |
| 157 | 163 | _ = w; |
| 158 | 164 | const fr: *File.Reader = @alignCast(@fieldParentPtr("interface", r)); |
| 159 | 165 | const context: *Context = @fieldParentPtr("fr", fr); |
| 160 | | const mr = context.mr; |
| 161 | | return fillUntimed(mr, context); |
| 166 | try fillUntimed(context, 1); |
| 167 | return 0; |
| 162 | 168 | } |
| 163 | 169 | |
| 164 | 170 | fn discard(r: *Io.Reader, limit: Io.Limit) Io.Reader.Error!usize { |
| 165 | 171 | _ = limit; |
| 166 | 172 | const fr: *File.Reader = @alignCast(@fieldParentPtr("interface", r)); |
| 167 | 173 | const context: *Context = @fieldParentPtr("fr", fr); |
| 168 | | const mr = context.mr; |
| 169 | | return fillUntimed(mr, context); |
| 174 | try fillUntimed(context, 1); |
| 175 | return 0; |
| 170 | 176 | } |
| 171 | 177 | |
| 172 | 178 | fn readVec(r: *Io.Reader, data: [][]u8) Io.Reader.Error!usize { |
| 173 | 179 | _ = data; |
| 174 | 180 | const fr: *File.Reader = @alignCast(@fieldParentPtr("interface", r)); |
| 175 | 181 | const context: *Context = @fieldParentPtr("fr", fr); |
| 176 | | const mr = context.mr; |
| 177 | | return fillUntimed(mr, context); |
| 182 | try fillUntimed(context, 1); |
| 183 | return 0; |
| 178 | 184 | } |
| 179 | 185 | |
| 180 | 186 | fn rebase(r: *Io.Reader, capacity: usize) Io.Reader.RebaseError!void { |
| 181 | 187 | const fr: *File.Reader = @alignCast(@fieldParentPtr("interface", r)); |
| 182 | 188 | const context: *Context = @fieldParentPtr("fr", fr); |
| 183 | | const mr = context.mr; |
| 184 | | |
| 185 | | return rebaseGrowing(mr, context, capacity) catch |err| { |
| 186 | | context.err = err; |
| 187 | | return error.ReadFailed; |
| 188 | | }; |
| 189 | try fillUntimed(context, capacity); |
| 189 | 190 | } |
| 190 | 191 | |
| 191 | | fn rebaseGrowing(mr: *MultiReader, context: *Context, capacity: usize) Allocator.Error!void { |
| 192 | | const gpa = mr.gpa; |
| 193 | | const r = &context.fr.interface; |
| 194 | | if (r.buffer.len >= capacity) { |
| 195 | | const data = r.buffer[r.seek..r.end]; |
| 196 | | @memmove(r.buffer[0..data.len], data); |
| 197 | | r.seek = 0; |
| 198 | | r.end = data.len; |
| 199 | | } else { |
| 200 | | const adjusted_capacity = std.ArrayList(u8).growCapacity(capacity); |
| 201 | | |
| 202 | | if (r.seek == 0) { |
| 203 | | if (gpa.remap(r.buffer, adjusted_capacity)) |new_memory| { |
| 204 | | r.buffer = new_memory; |
| 205 | | return; |
| 206 | | } |
| 207 | | } |
| 208 | | |
| 209 | | const data = r.buffer[r.seek..r.end]; |
| 210 | | const new = try gpa.alloc(u8, adjusted_capacity); |
| 211 | | @memcpy(new[0..data.len], data); |
| 212 | | r.seek = 0; |
| 213 | | r.end = data.len; |
| 214 | | } |
| 192 | fn fillUntimed(context: *Context, capacity: usize) Io.Reader.Error!void { |
| 193 | fill(context.mr, capacity, .none) catch |err| switch (err) { |
| 194 | error.Timeout, error.UnsupportedClock => unreachable, |
| 195 | error.Canceled, error.ConcurrencyUnavailable => |e| { |
| 196 | context.err = e; |
| 197 | return error.ReadFailed; |
| 198 | }, |
| 199 | error.EndOfStream => |e| return e, |
| 200 | }; |
| 201 | if (context.err != null) return error.ReadFailed; |
| 202 | if (context.eos) return error.EndOfStream; |
| 215 | 203 | } |
| 216 | 204 | |
| 217 | 205 | pub const FillError = Io.Batch.WaitError || error{ |
| ... | ... | @@ -221,7 +209,7 @@ pub const FillError = Io.Batch.WaitError || error{ |
| 221 | 209 | }; |
| 222 | 210 | |
| 223 | 211 | /// Wait until at least one stream receives more data. |
| 224 | | pub fn fill(mr: *MultiReader, timeout: Io.Timeout) FillError!void { |
| 212 | pub fn fill(mr: *MultiReader, unused_capacity: usize, timeout: Io.Timeout) FillError!void { |
| 225 | 213 | const contexts = mr.streams.contexts(); |
| 226 | 214 | const operations = mr.streams.operations(); |
| 227 | 215 | const io = contexts[0].fr.io; |
| ... | ... | @@ -243,14 +231,14 @@ pub fn fill(mr: *MultiReader, timeout: Io.Timeout) FillError!void { |
| 243 | 231 | } |
| 244 | 232 | const r = &context.fr.interface; |
| 245 | 233 | r.end += n; |
| 246 | | if (r.buffer.len - r.end == 0) { |
| 247 | | rebaseGrowing(mr, context, r.bufferedLen() + 1) catch |err| { |
| 234 | if (r.buffer.len - r.end < unused_capacity) { |
| 235 | rebaseGrowing(mr, context, r.bufferedLen() + unused_capacity) catch |err| { |
| 248 | 236 | context.err = err; |
| 249 | 237 | continue; |
| 250 | 238 | }; |
| 251 | 239 | assert(r.seek == 0); |
| 252 | | context.vec[0] = r.buffer; |
| 253 | 240 | } |
| 241 | context.vec[0] = r.buffer[r.end..]; |
| 254 | 242 | operation.file_read_streaming.status = .{ .unstarted = {} }; |
| 255 | 243 | mr.batch.add(i); |
| 256 | 244 | } |
| ... | ... | @@ -258,16 +246,30 @@ pub fn fill(mr: *MultiReader, timeout: Io.Timeout) FillError!void { |
| 258 | 246 | if (!any_completed) return error.EndOfStream; |
| 259 | 247 | } |
| 260 | 248 | |
| 261 | | fn fillUntimed(mr: *MultiReader, context: *Context) Io.Reader.Error!usize { |
| 262 | | fill(mr, .none) catch |err| switch (err) { |
| 263 | | error.Timeout, error.UnsupportedClock => unreachable, |
| 264 | | error.Canceled, error.ConcurrencyUnavailable => |e| { |
| 265 | | context.err = e; |
| 266 | | return error.ReadFailed; |
| 267 | | }, |
| 268 | | error.EndOfStream => |e| return e, |
| 269 | | }; |
| 270 | | if (context.err != null) return error.ReadFailed; |
| 271 | | if (context.eos) return error.EndOfStream; |
| 272 | | return 0; |
| 249 | fn rebaseGrowing(mr: *MultiReader, context: *Context, capacity: usize) Allocator.Error!void { |
| 250 | const gpa = mr.gpa; |
| 251 | const r = &context.fr.interface; |
| 252 | if (r.buffer.len >= capacity) { |
| 253 | const data = r.buffer[r.seek..r.end]; |
| 254 | @memmove(r.buffer[0..data.len], data); |
| 255 | r.seek = 0; |
| 256 | r.end = data.len; |
| 257 | } else { |
| 258 | const adjusted_capacity = std.ArrayList(u8).growCapacity(capacity); |
| 259 | |
| 260 | if (r.seek == 0) { |
| 261 | if (gpa.remap(r.buffer, adjusted_capacity)) |new_memory| { |
| 262 | r.buffer = new_memory; |
| 263 | return; |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | const data = r.buffer[r.seek..r.end]; |
| 268 | const new = try gpa.alloc(u8, adjusted_capacity); |
| 269 | @memcpy(new[0..data.len], data); |
| 270 | gpa.free(r.buffer); |
| 271 | r.buffer = new; |
| 272 | r.seek = 0; |
| 273 | r.end = data.len; |
| 274 | } |
| 273 | 275 | } |