Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git

Adds buffering to the buffered reader

AuthorDave Jarvis <email>
Date2026-02-21 19:47:24 GMT-0800
Commitb1ae5b6da3993fbc787683114cc458b04459bfd9
Parent82b2e36
git/BufferedReader.php
class BufferedReader implements StreamReader {
- private mixed $handle;
- private bool $temporary;
- private bool $owned;
+ private const CHUNK_SIZE = 65536;
- private function __construct( mixed $handle, bool $temporary, bool $owned = true ) {
+ private mixed $handle;
+ private bool $temporary;
+ private bool $owned;
+ private string $buffer;
+ private int $bufferPos;
+ private int $bufferLen;
+
+ private function __construct(
+ mixed $handle,
+ bool $temporary,
+ bool $owned = true
+ ) {
$this->handle = $handle;
$this->temporary = $temporary;
$this->owned = $owned;
+ $this->buffer = '';
+ $this->bufferPos = 0;
+ $this->bufferLen = 0;
}
public static function open( string $path ): self {
return new self( @fopen( $path, 'rb' ), false );
}
public static function createTemp(): self {
- return new self( @tmpfile(), true );
+ return new self( @fopen( 'php://temp/maxmemory:8388608', 'w+b' ), true );
}
public function __destruct() {
- $this->owned && $this->isOpen() ? fclose( $this->handle ) : null;
+ if( $this->owned && $this->isOpen() ) {
+ fclose( $this->handle );
+ }
}
public function read( int $length ): string {
- return $this->isOpen() && ! $this->eof()
- ? (string)fread( $this->handle, $length )
- : '';
+ $result = '';
+
+ if( $this->isOpen() ) {
+ $available = $this->bufferLen - $this->bufferPos;
+
+ if( $available < $length && !feof( $this->handle ) ) {
+ $need = $length - $available;
+ $fetch = $need > self::CHUNK_SIZE ? $need : self::CHUNK_SIZE;
+ $chunk = (string)fread( $this->handle, $fetch );
+
+ $this->buffer .= $chunk;
+ $this->bufferLen += strlen( $chunk );
+ }
+
+ $result = substr( $this->buffer, $this->bufferPos, $length );
+
+ $this->bufferPos += strlen( $result );
+
+ if( $this->bufferPos >= $this->bufferLen ) {
+ $this->buffer = '';
+ $this->bufferPos = 0;
+ $this->bufferLen = 0;
+ } elseif( $this->bufferPos > self::CHUNK_SIZE ) {
+ $this->buffer = substr( $this->buffer, $this->bufferPos );
+ $this->bufferLen = strlen( $this->buffer );
+ $this->bufferPos = 0;
+ }
+ }
+
+ return $result;
}
public function write( string $data ): bool {
- return $this->temporary && $this->isOpen()
- ? fwrite( $this->handle, $data ) !== false
- : false;
+ $result = false;
+
+ if( $this->temporary && $this->isOpen() ) {
+ $this->buffer = '';
+ $this->bufferPos = 0;
+ $this->bufferLen = 0;
+
+ $result = fwrite( $this->handle, $data ) !== false;
+ }
+
+ return $result;
}
public function seek( int $offset, int $whence = SEEK_SET ): bool {
- return $this->isOpen()
- ? fseek( $this->handle, $offset, $whence ) === 0
- : false;
+ $result = false;
+
+ if( $this->isOpen() ) {
+ if( $whence === SEEK_CUR ) {
+ $current = (int)ftell( $this->handle );
+ $logical = $current - ($this->bufferLen - $this->bufferPos);
+ $offset = $logical + $offset;
+ $whence = SEEK_SET;
+ }
+
+ $result = fseek( $this->handle, $offset, $whence ) === 0;
+
+ if( $result ) {
+ $this->buffer = '';
+ $this->bufferPos = 0;
+ $this->bufferLen = 0;
+ }
+ }
+
+ return $result;
}
public function tell(): int {
return $this->isOpen()
- ? (int)ftell( $this->handle )
+ ? (int)ftell( $this->handle ) - ($this->bufferLen - $this->bufferPos)
: 0;
}
public function eof(): bool {
return $this->isOpen()
- ? feof( $this->handle )
+ ? feof( $this->handle ) && $this->bufferPos >= $this->bufferLen
: true;
}
public function rewind(): void {
- $this->isOpen() ? rewind( $this->handle ) : null;
+ if( $this->isOpen() ) {
+ rewind( $this->handle );
+
+ $this->buffer = '';
+ $this->bufferPos = 0;
+ $this->bufferLen = 0;
+ }
}
}
Delta90 lines added, 18 lines removed, 72-line increase