Phobos I/O


投稿ツリー



なし Phobos I/O

msg# 1
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 .2 | 投稿日時 2010/12/29 2:21
SHOO  管理人   投稿数: 658
Andrei先生が新しいストリームモジュールのたたき台を書いてくれました。

http://erdani.com/d/phobos/std_stream2.html

今一度、PhobosのI/Oがどうあるべきかを議論したいと思います。
上記URLをご覧になって、感想や、要望、質問などをこのトピックにて行い、必要と有らば議論の結果をMLに報告させていただきたいと思います。

なお、今回のたたき台の概要としましては、

>ストリームは、2レイヤーで構成されます。ベースには、トランスポートレイヤーがあります。そして、それはストリームのopen, close,シークをして、バイトを転送する役割を果たします。
>トランスポートレイヤーの上層では、フォーマットレイヤーがあります。それはトランスポートレイヤーに入力されたデータを書式化して、生のバイト列として流し込みます。

と、おそらくこのようなことが書かれています。
投票数:22 平均点:5.00
返信する

なし Re: Phobos I/O

msg# 1.1
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 | 投稿日時 2010/12/29 2:38
SHOO  管理人   投稿数: 658
ちなみに、私は、以下のような返信をしました。
>議論が白熱することをマジで期待している。 I/OはPhobosにとって重要なコンポーネント。
>
>このインターフェースには幾つか疑問がある。
>
>1.
>継承をベースにしているようだけど、現状のstd.streamと比べて何が利点なの?
>
>2.
>I/Oを「標準」ライブラリとして提供するのは、2つの利点があると思っている。デバイスを定義する人に対する利点と、デバイスを使う人に対する利点。
>
>I/Oのインターフェースを標準ライブラリで指定することで、デバイスを定義する人にとって指標となる。デバイスを定義する人は、この指標にインターフェースを合わせてやることで、Phobosによる様々なヘルパに対応することが出来る。これは、RangeとAlgorithmに似た関係だ。
>この場合、重要になるのは、その定義がシンプルに出来ることだ。 Rangeはとてもシンプルで、たった3つの定義(front, popFront, empty)をするだけだ。
>こんなかんじで、I/Oのインターフェースも最小限の定義だけで完結するのが望ましい。
>しかしながら、TransportBaseはそうはなっていない。
>ダックタイピングでもっと簡単なインターフェースにすることは出来ないのか?
>
>また、デバイスの利用者にとっては、統一されたインターフェースとヘルパーを利用出来ることが利点だ。様々なデバイスに対して同じ操作で取り扱える点。
>この点、Rangeベースなのはいい感じだ。(Formatter/Unformatterみたいなの) ユーザーはRangeに対応したアルゴリズムを使うことが出来る。
>
>3.
>Formatterはwritefを持っているが、不要だと思う。
>出力先がバイナリデータだから。writefはテキストデータを書き出すので、TextFormatterなどにすべき。
>Unformatterのreadfについても同じ。
投票数:23 平均点:4.78
返信する

なし Re: Phobos I/O

msg# 1.1.1
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 .2 | 投稿日時 2010/12/29 4:03 | 最終変更
haru-s  新米   投稿数: 17
AndreiがHTMLに変換したものしか公開していないのでとりあえずコメント以外の部分だけコンパイルできる形式に整えました.
ちなみにaliasの文が不完全だったのでそれぞれwriteとemptyに対応づけてあります.

#code{{
module std.stream2;

import std.variant;

abstract interface TransportBase
{
abstract ulong seek(ulong position);
abstract ulong seekFromCurrent(long position);
abstract ulong seekFromEnd(long position);
abstract const ulong tell();
abstract const bool atEnd();
abstract const bool isOpen();
abstract void close();
}

abstract interface UnbufferedInputTransport: std.stream2.TransportBase
{
abstract ubyte[] read(ubyte[] buffer);
}

abstract interface UnbufferedOutputTransport: std.stream2.TransportBase
{
abstract void write(in ubyte[] buffer);
alias write put;
}

abstract interface BufferedInputTransport: std.stream2.UnbufferedInputTransport
{
alias atEnd empty;
abstract ubyte[] front();
abstract void popFront();
abstract ubyte[] peek(size_t n);
abstract ulong advance(ulong n);
}

abstract interface BufferedOutputTransport: std.stream2.UnbufferedOutputTransport
{
abstract void flush();
}

abstract interface Formatter
{
abstract UnbufferedOutputTransport transport();
abstract void transport(UnbufferedOutputTransport);
abstract void put(ubyte value);
abstract void put(ushort value);
abstract void put(uint value);
abstract void put(ulong value);
abstract void put(byte value);
abstract void put(short value);
abstract void put(int value);
abstract void put(long value);
abstract void put(char value);
abstract void put(wchar value);
abstract void put(dchar value);
abstract void put(float value);
abstract void put(double value);
abstract void put(real value);
abstract void put(in char[] value);
abstract void put(in wchar[] value);
abstract void put(in dchar[] value);
abstract void put(void[] value, TypeInfo elementType);
void put_(T)(in T[] array);
abstract void put(Object obj);
void put_(S)(auto ref S);
abstract void beforeStruct(void* s, TypeInfo ti);
abstract void afterStruct(void* s, TypeInfo ti);
enum maxSize = 15; // experimental
abstract void writef(in char[] format, VariantN!(maxSize)[] data...);
}

abstract interface Unformatter
{
abstract UnbufferedInputTransport transport();
abstract void transport(UnbufferedInputTransport);
abstract void read(ref ubyte value);
abstract void read(ref ushort value);
abstract void read(ref uint value);
abstract void read(ref ulong value);
abstract void read(ref byte value);
abstract void read(ref short value);
abstract void read(ref int value);
abstract void read(ref long value);
abstract void read(ref char value);
abstract void read(ref wchar value);
abstract void read(ref dchar value);
abstract void read(ref float value);
abstract void read(ref double value);
abstract void read(ref real value);
abstract void read(ref char[] value);
abstract void read(ref wchar[] value);
abstract void read(ref dchar[] value);
abstract void read(ref void[] value, TypeInfo elementType);
void read_(T)(in T[] array);
abstract void read(ref Object obj);
void read_(S)(ref S);
abstract void beforeStruct(void* s, TypeInfo ti);
abstract void afterStruct(void* s, TypeInfo ti);
enum maxSize = 15; // experimental
abstract void readf(in char[] format, VariantN!(maxSize)[] data...);
}
}}
投票数:24 平均点:4.17
返信する

なし Re: Phobos I/O

msg# 1.1.1.1
前の投稿 - 次の投稿 | 親投稿 - 子投稿.1 | 投稿日時 2010/12/29 5:01 | 最終変更
haru-s  新米   投稿数: 17
[img align=left]http://img.f.hatena.ne.jp/images/fotolife/h/haru-s/20101229/20101229054701_original.png?1293569244[/img]

ついでにクラス図も作ってみました.
どういう使い方を想定しているのかこれから考える予定・・・.
投票数:22 平均点:6.36
返信する

なし Re: Phobos I/O

msg# 1.1.1.1.1
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2010/12/29 11:30
SHOO  管理人   投稿数: 658
使用例についてですが、勝手な予想ですが、以下のような感じになるのではないかなぁと思います。

#code(d){{{
import std.stream2;

void main()
{
/*
<data>
<int>123</int>
<double>55.98</double>
<string>aabbccddee</string>
</data>
*/
auto infile = new BufferedFileTransport("intest.xml");
auto unfmt = new XmlUnformatter(infile);

int a;
double b;
string c;

unfmt.read(a);
unfmt.read(b);
unfmt.read(c);

writeln(a); // 123
writeln(b); // 55.98
writeln(c); // aabbccddee

auto outfile = new UnbufferedFileTransport("outtest.dat");
auto fmt = new BinaryFormatter(outfile);

fmt.put(a);
fmt.put(b);
fmt.put(c);
/*
| 0 1 2 3 4 5 6 7 8 9 A B C D E F
----+------------------------------------------------
0000| 7B-00-00-00-00-00-00-00-3D-0A-D7-A3-70-FD-4B-40
0001| 0A-00-00-00-61-61-62-62-63-63-64-64-65-65
*/
}
}}}
投票数:28 平均点:4.64
返信する

なし Re: Phobos I/O

msg# 1.1.1.2
前の投稿 - 次の投稿 | 親投稿 - | 投稿日時 2010/12/29 16:42
haru-s  新米   投稿数: 17
http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=125463

Andreiによる元のコードが公開されました.
内容がちょっと新しくなっているみたいなのでこちらで議論するのがいいですね.
投票数:22 平均点:4.09
返信する

なし Re: Phobos I/O

msg# 1.1.1.1.1.1
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2010/12/29 17:16 | 最終変更
haru-s  新米   投稿数: 17
おお,流石.全然イメージできてませんでした.

ところでAndrei曰く,

- Transport only transports untyped bits
- Formatter only formats primitive types

だそうです.
Transportはバイト列でデバイスとやり取りするのを担当し,
Formatterは原始的な型とバイト列の間を担当するのですね.

前から議論になっていた様々なストリームに対するアルゴリズムの適用についてですが,
Formatterがそのアルゴリズムに相当すると考えてよいのでしょう.
#code{{
auto file = new BufferedFileTransport("file.txt");
auto lineReader = new LineReader(file);
char[] s;
lineReader.read(s);
}}
ここでLineReaderの代わりにChunkReaderみたいなもので差し替えられるということでしょうか.
それとも,もう一段上の階層にRangeアルゴリズムが来る?

また,TransportやFormatterなどのinterfaceで定義されているのも動的多態を実現するために使おうということでしょう.
動的多態が想定されてないとInputStreamやOutputStreamの配列が作れないという話もこの設計なら問題なさそうです.

このままでは辛い所と言えば,やはりabstractメソッドの多さでしょうかね^^;
自分でTransportやFormatterを作る時にこんなにたくさん実装したくないです.

あと,RangeをサポートしているのがBufferedInputTransportと,UnbufferedOutputTransport(およびBufferedOutputTransport)で,
I/Oで非対称なんですよね.
何か理由があるんだろうなと思いつつ,この辺で.
投票数:19 平均点:7.37
返信する

なし Re: Phobos I/O

msg# 1.2
前の投稿 - 次の投稿 | 親投稿 - | 投稿日時 2010/12/30 2:07 | 最終変更
SHOO  管理人   投稿数: 658
このインターフェース、もし自分でTransportとかFormatter/Unformatterを書くとしたら、かなり面倒くさそうですよね…。

完全に別物ですが、本当に基本的なものを抽出したものと、オプションをそれぞれinterfaceと継承で表現すると以下のような感じになるかと思いますが、

#code(d){{{
interface Seekable
{
void seek(ulong);
long position();
}

interface Buffered
{
ubyte[] peek(size_t);
}

interface InputStream
{
ubyte[] read(ubyte[]);
}

class FileStream: InputStream, Buffered, Seekable
{
/* ... */
}
}}}

これって、次みたいなコードを書かなければ SeekableでかつBufferedかどうかを判定できないと思うのですが、

#code(d){{{
BmpData readBmp(InputStream strm)
{
auto seekable = cast(Seekable)strm;
auto buffered = cast(Buffered)strm;
if (!seekable || !buffered) return null;
seekable.seek(3);
ubyte[40] xbuf;
auto x = strm.read(xbuf);
auto y = buffered.peek();
/* ... */
}
}}}

これってものすごく面倒くさくありませんか?
投票数:21 平均点:7.14
返信する

なし Re: Phobos I/O

msg# 1.1.1.1.1.1.1
前の投稿 - 次の投稿 | 親投稿 - 子投稿なし | 投稿日時 2011/1/2 19:06
tama  一人前   投稿数: 111
引用:
このままでは辛い所と言えば,やはりabstractメソッドの多さでしょうかね^^; 自分でTransportやFormatterを作る時にこんなにたくさん実装したくないです.
これに関してAndreiって何か返信してましたっけ?いまいちそういうreplyを見つけれなかったのですが…
投票数:24 平均点:4.58
返信する

このトピックに投稿する

題名
ゲスト名
投稿本文

  条件検索へ


メインメニュー

ログイン

ユーザー名:


パスワード:





パスワード紛失  |新規登録

Menu