Some days ago, I decided that it would be fun to write a streambuf subclass that would use mmap and read-ahead.
I looked at how my STL (SGI) implemented filebuf and realized that basic_filebuf contains a FILE*. So inheriting from basic_filebuf is out of the question.
So I inherited from basic_streambuf. Then i wanted to bind my mmapbuf to a fstream.
I thought the only thing that I would have to do would be to copy the implicit interface of filebuf... but that was a clear mistake. In the SGI, basic_fstream owns a basic_filebuf. No matter if I call basic_filestream.std::::ios::rdbuf( streambuf* ), the filestream completely ignores it and uses its own filebuf.
So now I'm a bit confused... sure, I can create my own mmfstream, that would be the exact copy/paste of the fstream but that sounds really not DRY-oriented.
What I can't understand, is: why does fstream is so tightly coupled with filebuf, so that it is not possible to use anything else than a filebuf? The whole point of separating streams and bufs is that one can use a stream with a different buffer.
Solutions:
=> filestream should rely on the implicit interface of filebuf. That is, fstream should be templated by a streambuf class. That would allow everyone to provide its own streambuf subclass to a fstream as long as it implements filebuf's implicit interface. Problem: we cannot add a template parameter to fstream since it would break template selectors while using fstream as template template parameter.
=> filebuf should be a pure virtual class without any additional attributes. So that one can inherit from it without carrying all its FILE* garbage.
Your ideas on the subject ?
In the IO streams' design, most of the actual streams' functionality (as opposed to the stream buffers' functionality) is implemented in std::basic_istream, std::basic_ostream, and their base classes. The string and file stream classes are more or less just convenience wrappers which make sure a stream with the right type of buffer is instantiated.
If you want to extend the streams, you almost always want to provide your own stream buffer class, and you almost never need to provide your own stream class. .
Once you have your own stream buffer type, you can then make it the buffer for any stream object you happen to have around. Or you derive your own classes from std::basic_istream, std::basic_ostream, and std::basic_iostream which instantiates your stream buffer and pass it to their base classes.
The latter is more convenient for users, but requires you to write some boiler-plate code for the buffer's instantiation (namely constructors for the stream class).
To answer your question: File streams and file buffer are coupled so tightly because the former only exists to ease the creation of the latter. Using a file stream makes it easy to set it all up.
Using your own stream class to wrap construction of your own stream buffer shouldn't be a problem, since you shouldn't be passing around file streams anyway, but only (references) to the base classes.
Check out mapped_file in the Boost.Iostreams library. I've never used used it myself, but it seems like it might already do what you need.
EDIT: Oops, reread your questions and I see you're doing this for fun. Perhaps you can draw inspiration from Boost.Iostreams?
fstream in itself is not a big class. It inherits from basic_stream to provide support for all the << and >> operations, contains a specialized steambuf that have to be initialized, and the corresponding constructors to pass the parameters to the streambuf constructor.
In a sense, what you wrote about your templated solution is OK. But basic_stream can also be derived into a tcp_stream for example. In that case, the constructors of fstream are a bit useless. Thus you need to provide a new tcpstream class, inheriting from basic_stream with the correct parameters for the constructors to be able to create the tcp_stream. In the end, you wouldn't use anything from fstream. Creating this new tcpstream is a matter of writing 3 or 4 functions only.
In the end, you would derive from the fstream class without any real reason to. This would add more coupling in the class hierarchy, unneeded coupling.
The whole point of std::fstream is that it is a _F_ile based std::stream. If you want an ordinary std::stream backed by your mmstreambuf, then you should create a mmstreambuf and pass it to std::stream::stream(std::streambuf*)
Related
I have a function which works with a std::ostream. I need to support using a C file handle (FILE*). Should I be creating my own subclass of std::ostream which delegates to a FILE*?
As Ben Voigt points out, you want to subclass streambuf. There are pages on the University of Southern California's website which have the documentation, header, and source for a GNU implementation of a streambuf subclass (stdiobuf) that wraps a FILE*. It has some dependencies on the library it is a part of (GroovX), but those should be easily to remove (I would begin by removing all references to GVX_TRACE).
Interestingly, it also provides a minimalistic subclass (stdiostream) of std::iostream, in spite of what Ben Voigt said. But this does not seem to be necessary, as the rdbuf ("read buffer"/set the stream buffer) method which the stdiostream class uses to connect the stdiobuf class to a stream object is publicly accessible.
You can find more about subclassing streambuf here (look particularly at the bottom of the page, which discussing the virtual functions). The implementation linked above overrides sync, underflow (to support input) and overflow (to support output).
Further notes about the linked implementation:
The init method uses the setg and setp methods to set the pointers for the input and output sequences.
The line const int num = pptr()-pbase(); is calculating the number of characters to flush by subtracting the base output pointer from the current output pointer ("put pointer").
The variable unhelpfully named om is the mode parameter.
The variable named fd is the file descriptor.
No, ostream is not meant to be derived from. The way the iostreams library allows customization is by supplying a streambuf pointer when creating an ostream. streambuf has a lot of virtual functions so you can change its behavior.
You need to derive either directly from streambuf or from the existing filebuf subclass. You probably only need to provide the overflow function, the defaults for all the others should work ok.
For a project I'm working on for loading/storing data in files, I made the decision to implement the iostream library, because of some of the features it holds over other file io libraries. One such feature, is the ability to use either the deriving fstream or stringstream classes to allow the loading of data from a file, or an already existent place in memory. Although, so far, there is one major fallback, and I've been having trouble getting information about it for a while.
Similar to the functions available in the POSIX library, I was looking for some implementation of the truncate or ftruncate functions. For stringstream, this would be as easy as passing the associated string back to the stream after reconstructing it with a different size. For fstream, I've yet to find any way of doing this, actually, because I can't even find a way to pull the handle to the file out of this class. While giving me a solution to the fstream problem would be great, an even better solution to this problem would have to be iostream friendly. Because every usage of either stream class goes through an iostream in my program, it would just be easier to truncate them through the base class, than to have to figure out which class is controlling the stream every time I want to change the overall size.
Alternatively, if someone could point me to a library that implements all of these features I'm looking for, and is mildly easy to replace iostream with, that would be a great solution as well.
Edit: For clarification, the iostream classes I'm using are more likely to just be using only the stringstream and fstream classes. Realistically, only the file itself needs to be truncated to a certain point, I was just looking for a simpler way to handle this, that doesn't require me knowing which type of streambuf the stream was attached to. As the answer suggested, I'll look into a way of using ftruncate alongside an fstream, and just handle the two specific cases, as the end user of my program shouldn't see the stream classes anyways.
You can't truncate an iostream in place. You have to copy the first N bytes from the existing stream to a new one. This can be done with the sgetn() and sputn() methods of the underlying streambuf object, which you can obtain by iostream::rdbuf().
However, that process may be I/O intensive. It may be better to use special cases to manipulate the std::string or call ftruncate as you mentioned.
If you want to be really aggressive, you can create a custom std::streambuf derivative class which keeps a pointer to the preexisting rdbuf object in a stream, and only reads up to a certain point before generating an artifiicial end-of-file. This will look to the user like a shorter I/O sequence, but will not actually free memory or filesystem space. (It's not clear if that is important to you.)
I want to define a new type of filestream in C++. What should I inherit from?
Inherit from basic_filebuf, or basic_streambuf if you're writing the I/O parts from scratch. You might also want a class derived from basic_[i/o]fstream, but that is strictly optional, for convenience. If templating is not required, drop the basic_ and inherit from the classes, not the templates.
The *stream classes all dispatch I/O through a polymorphic pointer which you can get and set using the rdbuf() method. So unless/until you implement the convenience class, you can test by instantiating std::iostream and calling rdbuf with your pointer.
It is very useful to have a copy of the Standard handy, to work through the requirements for the derived class. Your main functionality will be in the virtual functions overflow and underflow.
I have a function which works with a std::ostream. I need to support using a C file handle (FILE*). Should I be creating my own subclass of std::ostream which delegates to a FILE*?
As Ben Voigt points out, you want to subclass streambuf. There are pages on the University of Southern California's website which have the documentation, header, and source for a GNU implementation of a streambuf subclass (stdiobuf) that wraps a FILE*. It has some dependencies on the library it is a part of (GroovX), but those should be easily to remove (I would begin by removing all references to GVX_TRACE).
Interestingly, it also provides a minimalistic subclass (stdiostream) of std::iostream, in spite of what Ben Voigt said. But this does not seem to be necessary, as the rdbuf ("read buffer"/set the stream buffer) method which the stdiostream class uses to connect the stdiobuf class to a stream object is publicly accessible.
You can find more about subclassing streambuf here (look particularly at the bottom of the page, which discussing the virtual functions). The implementation linked above overrides sync, underflow (to support input) and overflow (to support output).
Further notes about the linked implementation:
The init method uses the setg and setp methods to set the pointers for the input and output sequences.
The line const int num = pptr()-pbase(); is calculating the number of characters to flush by subtracting the base output pointer from the current output pointer ("put pointer").
The variable unhelpfully named om is the mode parameter.
The variable named fd is the file descriptor.
No, ostream is not meant to be derived from. The way the iostreams library allows customization is by supplying a streambuf pointer when creating an ostream. streambuf has a lot of virtual functions so you can change its behavior.
You need to derive either directly from streambuf or from the existing filebuf subclass. You probably only need to provide the overflow function, the defaults for all the others should work ok.
I have a file with saved data that sometimes needs to be accessed, written to, erased, etc. when the program is running. I decided to write a SavedDataHandler class to accomplish this. I'm currently using the fstream class.
I considered having one data member be the fstream itself, opening it in the constructor, and closing it in the destructor. However, I realized that different functions called on the SavedDataHandler open the stream differently ( setting different flags, etc. ) so I decided not to go that route.
Instead I just have a static const std::string with the file name, with the public member functions handling the opening and closing of the file as they need to. Performance is not an issue.
Is this route a valid option? Since it has no data members, providing a constructor isn't even necessary. It's just a class that contains functions ( and one static constant ), with the functions operating on a resource rather than a data member.
Hmya, the fstream class is by itself already a capable wrapper class around an operating system handle for a file. If you can't think of a way to add functionality to your own wrapper around fstream, take it as a hint that you don't actually need a wrapper.
Don't wrap (or inherit) just because you can.
Well in some projects, wrapping is essential. Just stop to think if later you'll need for example, to change the file I/O libs (dunno why you'd want to do that, since C++ libs are optimized and ISO). What would you do then? Change all the calls from fstream to YourNewSuperMegaLib::SuperFileSystem::MegaFileStream?
If you want simplicity, I'd just inherit fstream and in the constructor, pass the opening modes you want and invoke the super constructor accodingly.