Skip to content

Instantly share code, notes, and snippets.

@sinfu
Created July 25, 2010 04:45
Show Gist options
  • Save sinfu/489306 to your computer and use it in GitHub Desktop.
Save sinfu/489306 to your computer and use it in GitHub Desktop.
Handle+Port [試A]
import core.stdc.stdio : printf;
void main()
{
auto file = new File(__FILE__);
scope(exit) file.close;
// file に対してバイナリ入力を始める
auto binport = new BinaryInputPort(file);
// バイトごと読んで,0x3B が見つかったら break
foreach (u; binport.byByte)
{
if (u == cast(ubyte) ';')
break;
}
// byVariableChunk は内部バッファを直接取り出すので速い
foreach (chunk; binport.byVariableChunk)
printf(" -> %zu bytes: %c\n", chunk.length, chunk[0]);
}
//----------------------------------------------------------------------------//
interface Handle
{
interface IO
{
size_t read(void[] buffer);
size_t write(in void[] buffer);
}
IO startIO();
void close();
@property bool isOpen();
}
//----------------------------------------------------------------------------//
import core.stdc.errno;
import core.sys.posix.fcntl;
import core.sys.posix.unistd;
import std.string : toStringz;
@system class File : Handle, private Handle.IO
{
this(string path)
{
handle_ = .open(path.toStringz(), O_RDONLY);
if (handle_ < 0)
throw new Exception("open");
}
override IO startIO()
{
if (owned_)
return null;
owned_ = true;
return this;
}
override void close()
{
.close(handle_);
handle_ = -1;
}
override @property bool isOpen()
{
return handle_ >= 0;
}
protected:
override size_t read(void[] buffer)
{
immutable nbread = .read(handle_, buffer.ptr, buffer.length);
if (nbread < 0)
throw new Exception("read");
return nbread;
}
override size_t write(in void[] buffer)
{
immutable nbwritten = .write(handle_, buffer.ptr, buffer.length);
if (nbwritten < 0)
throw new Exception("write");
return nbwritten;
}
private:
int handle_;
bool owned_;
}
//----------------------------------------------------------------------------//
@system final class BinaryInputPort
{
this(Handle handle, size_t bufferSize = 1024)
{
reader_ = handle.startIO();
buffer_.length = bufferSize;
}
//----------------------------------------------------------------//
/*
* バッファから1バイトずつ読み込む
*/
@property ByByte byByte()
{
return new ByByte();
}
final class ByByte
{
//-- 'Lazy input' pattern
@property bool empty()
{
if (wantNext_) popFrontLazy();
return empty_;
}
@property ubyte front()
{
if (wantNext_) popFrontLazy();
return front_;
}
void popFront()
{
if (wantNext_) popFrontLazy();
wantNext_ = true;
}
//--
private void popFrontLazy()
{
wantNext_ = false;
with (this.outer) while (true)
{
if (bufferPos_ < bufferEnd_)
{
front_ = buffer_[bufferPos_++];
}
else
{
if (this.outer.fetch())
continue;
else
empty_ = true;
}
break;
}
}
private:
ubyte front_;
bool empty_;
bool wantNext_ = true;
}
//----------------------------------------------------------------//
/*
* バッファを直接取り出す
*/
@property ByVariableChunk byVariableChunk()
{
return new ByVariableChunk();
}
class ByVariableChunk
{
//-- 'Lazy input' pattern
@property bool empty()
{
if (wantNext_) popFrontLazy();
return empty_;
}
@property ubyte[] front()
{
if (wantNext_) popFrontLazy();
return front_;
}
void popFront()
{
if (wantNext_) popFrontLazy();
wantNext_ = true;
}
//--
private void popFrontLazy()
{
wantNext_ = false;
with (this.outer) while (true)
{
if (bufferPos_ < bufferEnd_)
{
front_ = buffer_[bufferPos_ .. bufferEnd_];
bufferPos_ = bufferEnd_;
}
else
{
if (this.outer.fetch())
continue;
else
empty_ = true;
}
break;
}
}
private:
ubyte[] front_;
bool empty_;
bool wantNext_ = true;
}
//----------------------------------------------------------------//
// 非 range な手段
//----------------------------------------------------------------//
/+
void readExact(void[] buffer)
{
while (buffer.length > 0)
{
if ((bufferEnd_ - bufferPos_) >= buffer.length)
}
}
T readValue(T)()
{
T store = void;
readExact( (&store)[0 .. 1] );
return store;
}
+/
//----------------------------------------------------------------//
private:
/*
* Fetch a chunk into the buffer. Returns false on EOF.
*/
bool fetch()
{
assert(bufferPos_ == bufferEnd_);
bufferEnd_ = reader_.read(buffer_);
bufferPos_ = 0;
return bufferEnd_ > 0;
}
//----------------------------------------------------------------//
private:
Handle.IO reader_;
ubyte[] buffer_;
size_t bufferPos_;
size_t bufferEnd_;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment