Created
July 25, 2010 04:45
-
-
Save sinfu/489306 to your computer and use it in GitHub Desktop.
Handle+Port [試A]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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