Streaming library

Daniel Gibson metalcaedes at gmail.com
Wed Oct 13 11:45:14 PDT 2010


Andrei Alexandrescu schrieb:
> On 10/11/2010 07:49 PM, Daniel Gibson wrote:
>> Andrei Alexandrescu schrieb:
>>> Agreed. Maybe this is a good time to sart making a requirements list
>>> for streams. What are the essential features/feature groups?
>>>
>>> Andrei
>>
>> Maybe something like the following (I hope it's not too extensive):
>>
>> * Input- Output- and InputAndOutput- Streams
>> - having InputStream and OutputStream as an interface like in the old
>> design may be a good idea
>> - implementing the standard operations that are mostly independent from
>> the data source/sink
>> like read/write for basic types, strings, ... in mixin templates is
>> probably elegant to create
>> streams that are both Input and Output (one mixin that implements most
>> of InputStream and
>> one that implements most of OutputStream)
> 
> So far so good. I will point out, however, that the classic read/write 
> routines are not all that good. For example if you want to implement a 
> line-buffered stream on top of a block-buffered stream you'll be forced 
> to write inefficient code.

So what's a possible alternative to the classic read/write routines?

> 
> Also, a requirement that I think is essential is separation between 
> formatting and transport. std.stream does not have that. At the top 
> level there are two types of transport: text and binary. On top of that 
> lie various formatters.
> 

Ok, one should differ between text and binary streams. I was mostly focused on binary streams 
(because that's what I use).
So there might be a hierarchy like
* Input/Output-Stream (interface for all those read/write operations)
   - BinaryStream // abstract class implementing writeInt() etc using write(void* buf, size_t len)
     * BinarySocketStream
     * BinaryFileStream
     * ...
   - TextStream // abstract class implementing writeInt() etc using something like to!string and 
write(char[])
     * TextFileStream
     * ...

(This for both Input- and Outputstreams)

>> * Two kinds of streams:
>> 1. basic streams: reading/writing from/to:
>> * network (socket)
>> * files
>> * just memory (currently MemoryStream)
>> * Arrays/Ranges?
>> * ...
>> 2. streams wrapping other streams:
>> * for buffering - buffer input/output/both
>> - with the possibility to peek?
>> * to modify data when it's read/written (e.g. change endianess -
>> important for networking!)
>> * custom streams.. e.g. could parse/create CSV (comma seperated values)
>> data or similar
> 
> Would these be streams be different in their interface?

No. I just wanted to point out that it must be possible (and should be easy) to wrap streams.

> 
>> * Also there are different types of streams: seekable, resettable (a
>> network stream is neither), ...
> 
> Agreed. Question: is there a file system that offers resettable but not 
> seekable files? I'm thinking of collapsing the two together.

As mentioned before in other branches of this thread: Probably no file system, but maybe archive 
files (zip, ...)

> 
>> * functionality/methods needed/desirable:
>> - low level access
>> * void read(void *buf, size_t len) // read *exactly* len bytes into buf
>> * void write(void *buf, size_t len) // write *exactly* len bytes from
>> buf to stream
>> - convenient methods to read/write basic types in binary (!) from/to 
>> stream
> 
> Again, binary vs. text is a capability of the stream. For example, a tty 
> can never transport binary data - programs like gzip refuse to write 
> binary data to a terminal. (Then of course a binary stream can always 
> accommodate text data.)
> 
>> * <type> read<Type>() (like int readInt()) or T read(T)() (like int
>> read!int())
> 
> Templates will be difficult for a class hierarchy.

Ok.
Another issue, as you mentioned line based streams: of course read(T)()/write(T)() would be quite 
messy on them (endless static if(is(T==int)) { ... } else static if(is(T==float)) {...} etc).

(here were a lot of templated methods)
>> * void writeString(char[] str) // same for wchar and dchar
>> - could write str into the stream with its length (as ushort xor uint
>> xor ulong,
>> _not_ size_t!) prepended
>> * char[] readString() // same for wchar and dchar
>> - read length of the string and then the string itself that will be
>> returned
> 
> Many of these capabilities involve template methods. Is a template-based 
> approach preferable to a straight class hierarchy? I tend to think that 
> in the case of streams, classic hierarchies are most adequate.

Ok agreed.
I forgot that templated methods can't be overridden.

As writeArray(T)() etc is hardly possible, at least for strings there should be write(char[]) 
write(dchar[]) and write(wchar[]) (maybe with some const-stuff added). These should just write the 
string to the stream, without its length.
(Analogous for read(...))

> 
>> - all that array/string/low level stuff but reading *at most* len (or
>> array.length) values
>> and returning the amount actually read ( readUpTo() ?)
>> * useful e.g. for parsing http (you don't know how long the header is 
>> etc)
>> * the same for write? don't see much use for that though..
>>
>> - some way to determine whether the stream
>> * is at its definite end (eof on file, socket closed or something like
>> that)
>> * currently empty (for input stream) - just doing a read() would block ?
>>
>> - Output streams need flush()
>> - for Input streams skip(size_t noBytes) or even skip(T)(size_t noElems)
>> may be
>> handy to just throw away data we're not interested in without having it
>> copied around - especially for non-seekable streams (network..)
> 
> OK, that's a good start. Let's toss this back and forth a few times and 
> see what sticks.
> 
> 
> Andrei


Cheers,
- Daniel


More information about the Digitalmars-d mailing list