interface iBuffer extends BaseIface {
// COUNTERS
function AvailByteCount() : int; // bytes currently remaining (buffered + source)
function SpentByteCount() : int; // bytes already processed/transferred (read or written)
// ACCESS
function RewindAll() : void; // reset to beginning of input or output file
function AppendBytes(string $s); // write bytes into buffer
function &CurrentBytes() : string; // get reference to currently available bytes
function DiscardBytes(int $nBytes); // remove $nBytes bytes from the buffer
function RemoveBytes() : string; // read bytes out of buffer
function RestoreBytes(string $s); // put bytes back into buffer (this is a bit of a kluge, I guess...)
function IsMore() : bool; // there is more to read (or room to write to, I guess?)
}
abstract class caBuffer extends BaseClass implements iBuffer {
// ++ CONFIG ++ //
protected function InspectorClass() : string { return ViewClass::class; }
// -- CONFIG -- //
// ++ ACCESS ++ //
protected $sBuff;
protected function AvailBuffByteCount() : int { // bytes available to read from buffer
return strlen($this->sBuff);
}
protected function AvailSrceByteCount() : int { echo self::PromptForMethod(); } // bytes currently remaining to read from source
// RETURNS: {bytes in buffer} + {size of file} - {bytes already read from file}
public function AvailByteCount() : int { return $this->AvailBuffByteCount() + $this->AvailSrceByteCount() - $this->SpentByteCount(); }
// ++ ACCESS: tracking ++ //
private $qnSpent = NULL;
public function QNSpent() : QIntIface { return $this->qnSpent ?? ($this->qnSpent = QIntClass::AsNew()); }
public function SpentByteCount() : int { return $this->QNSpent()->GetItNz(); }
// ++ ACCESS: info ++ //
public function IsMore() : bool { return $this->AvailByteCount() > 0; } // assumes static file
// ++ ACCESS: R/W ++ //
public function RewindAll() : void { $this->nSpent = 0; $this->sBuff = ''; }
// TODO: rename to something better
public function AppendBytes(string $s) {
$this->ErrorIfShut('write to');
#if (!$this->IsOpen()) {
# $id = $this->ObjectID();
# self::ThrowHissy("Writing to buffer (id$id) before it has been opened.");
#}
$this->sBuff .= $s;
#self::GotToHere();
}
protected function AddBytesForFetch(string $s) { $this->sBuff .= $s; }
public function &CurrentBytes() : string { return $this->sBuff; }
public function DiscardBytes(int $nBytes) {
$this->sBuff = substr($this->sBuff,$nBytes); // remove $nBytes from the buffer
$this->QNSpent()->AddIt($nBytes); // increment the "spent bytes" counter
}
// TODO: rename to something better
public function RemoveBytes() : string {
$this->ErrorIfShut('read from');
$sOut = $this->sBuff;
$nLen = strlen($sOut);
$this->nSpent += $nLen;
$this->sBuff = '';
return $sOut;
}
public function RestoreBytes(string $s) {
$this->nSpent -= strlen($s);
$this->sBuff = $s.$this->sBuff; // restore $s to beginning of buffer
}
protected function ErrorIfShut(string $sAction) {
if (!$this->IsOpen()) {
$id = $this->ObjectID();
self::ThrowHissy("Trying to $sAction closed buffer (id$id).");
}
}
// -- ACCESS -- //
// ++ UI OUTPUT ++ //
public function DescribeInline() : string { return $this->StatusLine(); }
// DEBUGGING, mainly
public function StatusLine() : string {
$sID = $this->ObjectID();
$nBuff = $this->AvailBuffByteCount();
$nSrce = $this->AvailSrceByteCount();
$nSpent = $this->SpentByteCount();
$sAlive = $this->IsOpen() ? 'OPEN' : 'SHUT';
return "id$sID [$sAlive]: buff=$nBuff srce=$nSrce spent=$nSpent";
}
// -- UI OUTPUT -- //
}