Spaces:
Runtime error
Runtime error
""" | |
This is a port of Zig's buffered reader. | |
See: https://github.com/ziglang/zig/blob/master/lib/std/io/buffered_reader.zig | |
The MIT License (Expat) | |
Copyright (c) Lukas Hermann | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
THE SOFTWARE. | |
""" | |
from utils.list import Dim | |
from math import min | |
from math.limit import max_finite | |
from memory import memcpy | |
from memory.buffer import Buffer | |
from memory.unsafe import Pointer, DTypePointer | |
from sys.info import sizeof | |
from utils.index import Index | |
from utils.vector import DynamicVector | |
import testing | |
from .libc.stdio import fopen, fread, fclose, FILE | |
from .libc.dirent import readdir, opendir, closedir, DIR, dirent | |
from .libc.string import strnlen | |
alias BUF_SIZE = 4096 | |
# Types aliases | |
alias c_char = UInt8 | |
fn to_char_ptr(s: String) -> Pointer[c_char]: | |
"""Only ASCII-based strings.""" | |
let ptr = Pointer[c_char]().alloc(len(s) + 1) | |
for i in range(len(s)): | |
ptr.store(i, ord(s[i])) | |
ptr.store(len(s), ord("\0")) | |
return ptr | |
struct File: | |
var handle: Pointer[FILE] | |
var fname: Pointer[c_char] | |
var mode: Pointer[c_char] | |
fn __init__(inout self, filename: String): | |
let fname = to_char_ptr(filename) | |
let mode = to_char_ptr("r") | |
let handle = fopen(fname, mode) | |
self.fname = fname | |
self.mode = mode | |
self.handle = handle | |
fn __bool__(self) -> Bool: | |
return self.handle.__bool__() | |
fn __del__(owned self) raises: | |
if self.handle: | |
pass | |
# let c = fclose(self.handle) | |
# if c != 0: | |
# raise Error("Failed to close file") | |
if self.fname: | |
self.fname.free() | |
if self.mode: | |
self.mode.free() | |
fn __moveinit__(inout self, owned other: Self): | |
self.fname = other.fname | |
self.mode = other.mode | |
self.handle = other.handle | |
other.handle = Pointer[FILE]() | |
other.fname = Pointer[c_char]() | |
other.mode = Pointer[c_char]() | |
fn do_nothing(self): | |
pass | |
fn read[D: Dim](self, buffer: Buffer[D, DType.uint8]) raises -> Int: | |
return fread( | |
buffer.data.as_scalar_pointer(), sizeof[UInt8](), BUF_SIZE, self.handle | |
).to_int() | |
struct DirEntry: | |
var _pointer: Pointer[dirent] | |
var name: String | |
fn __init__(inout self, pointer: Pointer[dirent]): | |
self.name = String() | |
if pointer: | |
print("hit") | |
let name_ptr = pointer.bitcast[UInt8]().offset( | |
sizeof[UInt64]() * 2 + sizeof[UInt16]() + sizeof[UInt8]() | |
) | |
let name_len = strnlen(name_ptr) | |
for i in range(name_len): | |
self.name += chr(name_ptr.load(i).to_int()) | |
self._pointer = pointer | |
struct DirIter: | |
var handle: Pointer[DIR] | |
var data: Pointer[dirent] | |
fn __iter__(inout self) -> Self: | |
self.data = readdir(self.handle) | |
fn __next__(self) raises -> Pointer[dirent]: | |
return self.data | |
fn __len__(self) -> Int: | |
if self.handle and self.data: | |
return 1 | |
return 0 | |
struct Dir: | |
var handle: Pointer[DIR] | |
var path: Pointer[c_char] | |
fn __init__(inout self, path: String): | |
self.path = to_char_ptr(path) | |
self.handle = opendir(self.path) | |
fn __bool__(self) -> Bool: | |
return self.handle.__bool__() | |
fn __iter__(self) -> DirIter: | |
return DirIter(self.handle, Pointer[dirent]()) | |
fn __del__(owned self) raises: | |
let c = closedir(self.handle) | |
if c != 0: | |
raise Error("failed to close dir") | |
self.path.free() | |
fn do_nothing(self): | |
pass | |
struct BufReader[BUF_SIZE: Int]: | |
var unbuffered_reader: File | |
var data: DTypePointer[DType.uint8] | |
var end: Int | |
var start: Int | |
fn __init__(inout self, owned reader: File): | |
self.unbuffered_reader = reader ^ | |
self.data = DTypePointer[DType.uint8]().alloc(BUF_SIZE) | |
self.end = 0 | |
self.start = 0 | |
fn read[D: Dim](inout self, dest: Buffer[D, DType.uint8]) raises -> Int: | |
var dest_index = 0 | |
let buf = Buffer[BUF_SIZE, DType.uint8](self.data) | |
while dest_index < len(dest): | |
let written = min(len(dest) - dest_index, self.end - self.start) | |
memcpy(dest.data.offset(dest_index), self.data.offset(self.start), written) | |
if written == 0: | |
# buf empty, fill it | |
let n = self.unbuffered_reader.read(buf) | |
if n == 0: | |
# reading from the unbuffered stream returned nothing | |
# so we have nothing left to read. | |
return dest_index | |
self.start = 0 | |
self.end = n | |
self.start += written | |
dest_index += written | |
return len(dest) | |
fn do_nothing(self): | |
pass | |