Skip to content

Instantly share code, notes, and snippets.

@sinfu
Created July 16, 2010 22:51
Show Gist options
  • Save sinfu/479027 to your computer and use it in GitHub Desktop.
Save sinfu/479027 to your computer and use it in GitHub Desktop.
/*
* Handle + range I/O
*
--------------------
% wine dmd -run test
Leading char = '/'
Read 1024 bytes
Read 1024 bytes
Read 1024 bytes
Read 1024 bytes
Read 741 bytes
Done!
--------------------
*/
import std.stdio; // writeln
import std.utf; // toUTF16z
version (Windows)
{
import std.windows.syserror;
import core.sys.windows.windows;
enum ERROR_HANDLE_EOF = 38;
}
void main()
{
InputHandle file = new WindowsFileHandle(__FILE__, OpenMode.read);
scope(exit) file.close;
run(file.byChunk);
}
void run(InputRange!(ubyte[]) source)
{
writeln("Leading char = '", readUnit!char(source), "'");
ubyte[1024] storage = void;
ubyte[] inbuf;
while ((inbuf = rawRead(source, storage)).length > 0)
{
writeln("Read ", inbuf.length, " bytes");
}
writeln("Done!");
}
/*
* Naive implementation
*/
enum OpenMode
{
read,
write,
readWrite,
}
class WindowsFileHandle : InputHandle, OutputHandle
{
private HANDLE _handle = INVALID_HANDLE_VALUE;
this(string path, OpenMode mode)
{
DWORD access;
DWORD action;
final switch (mode)
{
case OpenMode.read:
access = GENERIC_READ;
action = OPEN_EXISTING;
break;
case OpenMode.write:
access = GENERIC_WRITE;
action = CREATE_NEW;
break;
case OpenMode.readWrite:
access = GENERIC_READ | GENERIC_WRITE;
action = CREATE_NEW;
break;
}
_handle = CreateFileW(path.toUTF16z(), access, 0, null, action, FILE_ATTRIBUTE_NORMAL, null);
if (_handle == INVALID_HANDLE_VALUE)
throw new Exception(sysErrorString(GetLastError()));
}
override void close()
{
if (_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(_handle);
_handle = INVALID_HANDLE_VALUE;
}
}
override @property bool isOpen()
{
return _handle != INVALID_HANDLE_VALUE;
}
/*
* byChunk
*/
class ByChunk : InputRange!(ubyte[])
{
override ubyte[]* getNext(ref ubyte[] store)
{
DWORD bytesRead;
BOOL success;
success = ReadFile(this.outer._handle,
store.ptr, store.length, &bytesRead, null);
if (success == FALSE)
{
switch (GetLastError())
{
case ERROR_HANDLE_EOF:
break;
default:
throw new Exception(sysErrorString(GetLastError()));
}
}
if (bytesRead == 0)
return null;
store = store[0 .. bytesRead];
return &store;
}
}
override @property ByChunk byChunk()
{
return new ByChunk();
}
/*
* blockWriter
*/
class BlockWriter : OutputRange!(const(ubyte)[])
{
override void put(const(ubyte)[] data)
{
while (data.length > 0)
{
DWORD bytesWritten;
BOOL success;
success = WriteFile(this.outer._handle,
data.ptr, data.length, &bytesWritten, null);
if (success == FALSE)
throw new Exception(sysErrorString(GetLastError()));
data = data[bytesWritten .. $];
}
}
}
override @property BlockWriter blockWriter()
{
return new BlockWriter();
}
}
//----------------------------------------------------------------------------//
// Range I/O utilities
//----------------------------------------------------------------------------//
/*
*
*/
ubyte[] rawRead(R)(ref R source, ubyte[] buffer)
// if (isInputRange!(R) && is(ElementType!R == ubyte[]))
{
if (auto p = source.getNext(buffer))
return *p;
else
return null;
}
/*
*
*/
E readUnit(E, R)(ref R source)
// if (isInputRange!(R) && is(ElementType!R == ubyte[]))
{
ubyte[E.sizeof] store = void;
for (size_t used = 0; used < E.sizeof; )
{
ubyte[] buffer = store[used .. $];
if (auto p = source.getNext(buffer))
used += (*p).length;
else
throw new Exception("EOF");
}
return *cast(E*) store.ptr;
}
//----------------------------------------------------------------------------//
// Handle
//----------------------------------------------------------------------------//
/*
* input handle
*/
interface InputHandle
{
void close();
@property bool isOpen();
@property InputRange!(ubyte[]) byChunk();
}
interface CharacterInputHandle : InputHandle
{
@property InputRange!dchar byChar();
@property InputRange!string byLine();
}
/*
* output handle
*/
interface OutputHandle
{
void close();
@property bool isOpen();
@property OutputRange!(const(ubyte)[]) blockWriter();
}
interface TextOutputHandle : OutputHandle
{
@property TextOutputRange textWriter();
}
interface TextOutputRange :
OutputRange!(const( char)[]),
OutputRange!(const(wchar)[]),
OutputRange!(const(dchar)[]),
OutputRange!dchar
{
override void put(const( char)[] str);
override void put(const(wchar)[] str);
override void put(const(dchar)[] str);
override void put(dchar c);
}
//----------------------------------------------------------------------------//
// Range
//----------------------------------------------------------------------------//
/*
* pure input range
*/
interface InputRange(E)
{
E* getNext(ref E item);
}
/*
* output range
*/
interface OutputRange(E)
{
void put(E e);
}
/*
* hasLength
*/
interface HaveLength(L = size_t)
{
@property L length();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment