glob2-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[glob2-devel] Stream I/O


From: Andrew Sayers
Subject: [glob2-devel] Stream I/O
Date: Fri, 30 Sep 2005 18:53:24 +0100
User-agent: Mutt/1.5.11

As part of the map rewrite, I've been looking at stream I/O.  Although
Stephane's done a lot of work making it more efficient, the interface
is still a bit unwieldy, and it duplicates a lot of work already done by
C++'s own implementation of streams.  After a lot of thought, I've come
up with what I think will be a better implementation.  I've written
about 75% of it (enough to know that it works), but I'd like to get
everyone's opinions before finishing it off.

_Background_

For those that haven't used Glob2's stream system before, this is a
basic explanation:

Glob2 supports two different stream classes: binary and text.

The binary class reads and writes binary data so that a stream written
on a PC can be properly read on a Mac.  This class is used for most
ordinary jobs: Internet messages and maps (which obviously need to work
across many architectures) saved games (which should be architecture-
neutral so I can save a game on my computer and send it in a bug
report), and so on.

The text class outputs values in a human-readable way, complete with names for
each variable and section of the file.  So far as I know, this is only
used for debugging purposes.  For example:

Map
{
        width = 64;
        height = 64;
        ...
}

Both classes can be written to either a file or a string stored in
memory (much like C++'s file and string streams).  They can also be read
back again - and reading text streams is quite difficult.

The interface to the stream system is defined in
libgag/include/Stream.h, which defines virtual base classes for both
binary and string streams.  A typical stream function might look like
this:

void saveMap(OutputStream& myStream)
{
        myStream.writeEnterSection("Map");
        myStream.writeSint8(64, "width");
        myStream.writeSint8(64, "height");
        // ...
        myStream.writeLeaveSection();
}

Streams are created and destroyed using the functions defined in
libgag/include/FileManager.h - but I'm not familiar enough with that
file to explain how it works.

_Proposal_

The system I propose essentially adapts C++'s stream classes to our
needs.  Most C++ programmers are used to working with the normal
"istream" and "ostream" data types, but these are just special cases of
the more general basic_istream and basic_ostream templates.  With a bit
of sneakiness that I won't go into here, I've been able to define
basic_istream and basic_ostream classes for binary and text I/O.  The
interface to these classes is therefore based on the normal stream I/O
interface:

template<class Ch, class Tr>
basic_ostream& operator<<(basic_ostream&<Ch, Tr>& out)
{
        return out
                << enterSection("Map")
                << title("width") << 64
                << title("height") << 64
                // ...
                << leaveSection;
}

The files and classes used in this implementation ape their STL
equivalents: Istream.h, Ostream.h, Fstream.h and Sstream.h.  In a break
from normal Glob2 practice, the classes are also based on their STL
equivalents, so a new output file could be defined like this:

#include <Fstream.h>
obfstream myStream("filename");

The benefits of this system include:
* Newcomers can understand the code more quickly
* Reuses standard code rather than reinventing it
* std::cerr << myMap returns meaningful results
* All the normal benefits of the C++ iostream implementation

As I said above, I've finished 75% of this code.  It's available in CVS:
        
http://savannah.nongnu.org/cgi-bin/viewcvs/glob2/glob2/libgag/include/?only_with_tag=map-rewrite

Unfortunately, I got rid of all the whitespace on empty lines (4KB
worth!) in the same CVS upload, so it looks like I've done rather more
work than I actually have.

The 25% I've not yet done is text stream input.  The current text format
is quite difficult to parse, and it strikes me that if this is only for
debugging purposes, we should be using a simpler system.  I can stick
with the current system if needs be, but does anyone object to using a
system like:

Map.width=64
Map.height=64
Map.someString=Strings are not commented,\
literal newlines are marked by backslashes,\
\s only need to be escaped at the end of a line\\
Map.otherValue=-1

This would be much easier to parse, and in my opinion, no harder to
read.

        - Andrew




reply via email to

[Prev in Thread] Current Thread [Next in Thread]