Another new io library

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Tue Feb 16 22:45:41 PST 2016


It's no secret that I've been looking to create an updated io library 
for phobos. In fact, I've been working on one on and off since 2011 (ouch).

After about 5 iterations of API and design, and testing out ideas, I 
think I have come up with something pretty interesting. It started out 
as a plan to replace std.stdio (and that did not go over well: 
https://forum.dlang.org/post/j3u0l4$1atr$1@digitalmars.com), in addition 
to trying to find a better way to deal with i/o. However, I've scaled 
back my plan of world domination to just try for the latter, and save 
tackling the replacement of Phobos's i/o guts for a later battle, if at 
all. It's much easier to reason about something new than to muddle the 
discussion with how it will break code. It's also much easier to build 
something that doesn't have to be a drop-in replacement of something so 
insanely complex.

I also have been inspired over the last few years by various great 
presentations and libraries, two being Dmitry's proof-of-concept library 
to have buffers that automatically move/fill when more data is needed, 
and Andrei's std.allocator library. They have changed drastically the 
way I have approached this challenge.

Therefore, I now have a new dub-based repository available for playing 
with: https://github.com/schveiguy/iopipe. First, the candy:

- This is a piping library. It allows one to hook buffered i/o through 
various processors/transformers much like unix pipes or range 
functions/algorithms. However, unlike unix pipes, this library attempts 
to make as few copies as possible of the data.

example:

foreach(line; (new IODevice(0)).bufferedInput
     .asText!(UTFType.UTF8)
     .byLine
     .asInputRange)
    // handle line

- It can handle 5 forms of UTF encoding - UTF8, UTF16, UTF16LE, UTF32, 
UTF32LE (phobos only partially handles UTF8). Sorry, no grapheme support 
or other utf-related things, but this of course can be added later.

- Arrays are first-class ioPipe types. This works:

foreach(line; "one\ntwo\nthree\nfour\n".byLine.asInputRange)

- Everything is compile-time for the most part, and uses lots of 
introspection. The intent is to give the compiler full gamut of 
optimization capabilities.

- I added rudimentary compression/decompression support using 
etc.c.zlib. Using compression is done like so:

foreach(line; (new IODevice(0)).bufferedInput
     .unzip
     .asText!(UTFType.UTF8)
     .byLine
     .asInputRange)

- The plan is for this to be a basis to make super-fast and modular 
parsing libraries. I plan to write a JSON one as a proof of concept. So 
all you have to do is add a parseJSON function to the end of any chain, 
as long as the the input is some pipe of text data (including a string 
literal).


=================

I will stress some very very important things:

1. This library is FAR from finished. Even the concepts probably need 
some tweaking. But I'm very happy with the current API/usage.

2. Docs are very thin. Unit tests are sparse (but do pass).

3. The focus of this library is NOT replacement of std.stream, or even 
low-level i/o in general. In fact, I have copied over my stream class 
from previous attempts at this i/o rewrite ONLY as a mechanism to have 
something that can read/write from file descriptors with the right API 
(located in iopipe/stream.d). I admit to never having looked at 
std.stream really, so I have no idea how it would compare.

4. As the stream framework is only for playing with the other useful 
parts of the library, I only wrote it for my OS (OSX), so you won't be 
able to play out of the box on Windows (probably can be added without 
much effort, or use another stream library such as this one that was 
recently announced: 
https://forum.dlang.org/post/xtxiuxcmewxnhseubyik@forum.dlang.org), but 
it will likely work on other Unixen.

5. This is NOT thread-aware out of the box.

6. There is a concept in here I called "valves". It's very weird, but it 
allows unifying input and output into one seamless chain. In fact, I 
can't think of how I could have done output in this regime without them. 
See the convert example application for details on how it is used.

7. I expect to be changing the buffer API, as I think perhaps I have the 
wrong abstraction for buffers. However, I did attempt to have a 
std.allocator version of the buffer.

8. It's not on code.dlang.org yet. I'll work on this.

Destroy!

-Steve


More information about the Digitalmars-d mailing list