August 08, 2005
Ben Hinkle wrote:
> OK. Now that I think about it repeatedly wrapping a stream with another stream and going back and forth might wind up with some odd state in the original stream wrt unget buffers and end-of-line flags.

What would you suggest then? Especially what would be the nicest way of using EndianStream in a library function that takes a Stream argument and where no assumptions can be made about the passed Stream object:

1) Always create an EndianStream wrapper.

2) Check whether the given stream is EndianStream. If yes, use that stream. If not, create an EndianStream wrapper.

3) Take an EndianStream argument instead of a Stream thus forcing the client to create an EndianStream wrapper.

4) Ignore endianness completely. The client will create an EndianStream wrapper if needed.

> I should add some documentation that if you wrap and unwrap a stream that is already in use the binary operations are the only truly safe operations.

Agreed.

-- 
Niko Korhonen
SW Developer
August 08, 2005
"Niko Korhonen" <niktheblak@hotmail.com> wrote in message news:dd86q0$30sl$1@digitaldaemon.com...
> Ben Hinkle wrote:
>> OK. Now that I think about it repeatedly wrapping a stream with another stream and going back and forth might wind up with some odd state in the original stream wrt unget buffers and end-of-line flags.
>
> What would you suggest then? Especially what would be the nicest way of using EndianStream in a library function that takes a Stream argument and where no assumptions can be made about the passed Stream object:
>
> 1) Always create an EndianStream wrapper.
>
> 2) Check whether the given stream is EndianStream. If yes, use that stream. If not, create an EndianStream wrapper.
>
> 3) Take an EndianStream argument instead of a Stream thus forcing the client to create an EndianStream wrapper.
>
> 4) Ignore endianness completely. The client will create an EndianStream wrapper if needed.

Since in your initial post you mentioned your code only does binary i/o then
you can safely wrap. I'd do 2a) which is 2) but throwing if the EndianStream
is the wrong endianness. That way the user can make their own EndianStream
if they don't want the performance hit of making lots of little wrappers and
yet if they make the wrong EndianStream they'll find out about it quickly.
If you want you can write a little helper method "getCompatibleStream" or
something:
 class Foo {
    // returns a stream possibly wrapping the source stream s that
    // is compatible with class Foo. Returns null if s can't be made
compatible.
    // Using the same compatible stream instance to write multiple Foo
    // instances is more efficient than getting a compatible stream for
    // each Foo instance.
    Stream getCompatibleStream(Stream s) {
      assert( s );
      EndianStream es = cast(EndianStream)s;
      if (!es) es = new EndianStream(s,Endian.LittleEndian);
      is (es.endian != Endian.LittleEndian) es = null;
      return es;
    }
    void write(Stream s) {
      s = getCompatibleStream(s);
      assert( s );
      ... carry on, nothing to see here ...
 }

>> I should add some documentation that if you wrap and unwrap a stream that
>> is
>> already in use the binary operations are the only truly safe operations.
>
> Agreed.
>
> -- 
> Niko Korhonen
> SW Developer


August 09, 2005
How about using a stream and a wrapper simultaneously, something like this:

void write(Stream s)
{
  EndianStream es = new EndianStream(s, Endian.LittleEndian);
  es.write(/* uint argument */);
  s.writeString(/* string argument*/ );
  es.write(/* long argument */);
  s.write(/* ubyte argument */);
}

Do you see any problems with that?

-- 
Niko Korhonen
SW Developer
August 09, 2005
"Niko Korhonen" <niktheblak@hotmail.com> wrote in message news:dd9ldm$1hr8$1@digitaldaemon.com...
> How about using a stream and a wrapper simultaneously, something like this:
>
> void write(Stream s)
> {
>   EndianStream es = new EndianStream(s, Endian.LittleEndian);
>   es.write(/* uint argument */);
>   s.writeString(/* string argument*/ );
>   es.write(/* long argument */);
>   s.write(/* ubyte argument */);
> }
>
> Do you see any problems with that?
>
> -- 
> Niko Korhonen
> SW Developer

Stream.writeString is fine since it writes the length as binary followed by the string contents. The problem methods are the ones that call getc/getcw like readLine and readf. Now that I think about it, though, mixing get/unget with binary reading isn't a good idea even with one stream let alone wrapper (I should have thought of that earlier - sorry!). The unget buffer is not checked by the binary read methods so anything you unget sits unnoticed until you getc again and it magically pops back up. I believe this matches how C streams work but I haven't ever actually tried mixing getc/ungetc with fread.


1 2
Next ›   Last »