How to update boost::io::ios_all_saver? - c++

I am writing a file reader class Filereader. It has iterators that take a reference to the file the filereader object is assigned to (Filereader fr(filename);). Each instance of the iterator Filereader::output_iterator has a members that store the state of the file when Filereader::output_iterator::operator++() was called last:
void load_state()
{
ias.update(); // this method does not exist
file_m.copyfmt(state);
file_m.seekg(read_pointer);
file_m.seekp(write_pointer);
}
void store_state()
{
ias.restore();
state.copyfmt(file_m);
read_pointer = file_m.tellg();
write_pointer = file_m.tellp();
}
std::fstream& file_m;
std::string line;
int line_number;
const std::string& file_name;
std::ios state;
decltype(file_m.tellg()) read_pointer;
decltype(file_m.tellp()) write_pointer;
boost::io::ios_all_saver ias{file_m};
The incrementation operator looks like this:
output_iterator& operator++()
{
load_state();
if (std::getline(file_m, line)) {
line_number++;
} else {
assert_not_bad();
line_number = -1;
}
store_state();
return *this;
}
The problem is that this does not quite work yet. copyfmt does not save the state flags, so when for instance the eof bit is being set, because one iterator reaches the end of the file, the other ierators will stop moving forward when incremented.
So then I tried to bring boost::io::ios_all_saver into this, but I don't understand hwo I can update the field ias of type boost::io::ios_all_saver like I do with state of type std::ios. I don't understand the documentation. Is there a way to update boost::io::ios_all_saver like I suggest in my snippet?

The state savers are designed as RAII containers: they unconditionally free restore the state on destruction.
Your interface is incompatible with that because users might elect /not/ to restore state (store_state).
If you can live with restore being unconditional at destruction, you can fix it by adhering to the same design.

Related

Is this use of callbacks idiomatic?

I noticed a common pattern in some of my code
std::string line;
if (!in || !std::getline(in, line)) {
throw line_read_error(in,line_counter);
}
++line_counter;
std::istringstream sin{line};
// ...read from sin...
if (!sin.eof()) {
sin.clear();
throw incomplete_read_error(in,line_counter,sin.tellg());j
}
What I read from the line was different in each location, but the setup and post-read check were identical.
I factored it out, creating an object to hold my in stream and line_counter, and passing a callback
for the body:
class LineReader {
std::istream& in;
size_t line_counter;
public:
template <typename Function>
void with_next_line(Function callback) {
std::string line;
if (!in || !std::getline(in, line)) {
throw line_read_error(in,line_counter);
}
++line_counter;
std::istringstream sin{line};
callback(sin);
if (!sin.eof()) {
sin.clear();
throw incomplete_read_error(in,line_counter,sin.tellg());j
}
}
// ...
}
Changing my uses to
line_reader.with_next_line([/*...*/](auto& sin){
// ...read from sin...
});
This is certainly less repetition, but it's still a bit awkward.
What I'm really concerned with, however, is whether it'll be easy for other
people to follow, as I'm really trying to make my code as legible as possible.
Would I be better off with something like
auto sin = line_reader.get_next_line();
// ...read from sin...
line_reader.check_done(std::move(sin));
The normal way to do setup + cleanup is to have an object whose constructor does the setup and destructor does the cleanup (RAII).
However, the cleanup you want to do, is to throw if you haven't read to the end - and throwing from a destructor is evil, bad, and wrong. That means you can't use RAII in this particular case.
If it is really important to do the check, then the code you have will enforce it. If it is just "a good idea", then I think the two calls (before and after) is probably slightly cleaner than the lambda. (I wouldn't bother with the std::move(sin) - using a move doesn't really add anything here.)

How to read data from a file from within a function

I want to make my code more efficient, specifically the reading of data from a text file. Here is a snapshot of what it looks like now:
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)));
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)));
... // and so on
Basically, the read_value function creates an ifstream object, opens the file, reads one line of data, and closes the file connection. This happens many times. What I want to do is to open the file once, read every line that is needed into the struct, and then close the file connection.
Here is the creating values struct function with parameters:
static values create_struct(std::string name, std::map<std::string, int> mapping) {
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)), file);
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)), file);
// more values here
return V;
}
The function that calls create_struct is shown below:
void initialize_data(string name) {
// read the appropriate data from file into a struct
value_container = Utility::create_struct(name, this->mapping);
}
I am thinking of instead defining the ifstream object in the function initialize_data. Given what is shown about my program, would that be the best location to create the file object, open the connection, read the values, then close the connection? Also, would I need to pass in the ifstream object into the create_values struct, and if so, by value, reference or pointer?
The short answer is to create your ifstream object first and pass it as reference to your parser. Remember to seek the stream back to the beginning before you leave your function, or when you start to read.
The RAII thing to do would be to create a wrapper object that automatically does this when it goes out of scope.
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::ifstream& mStream;
}
Then you create a wrapper instance when entering a method that will read the fstream.
void read_value(std::ifstream& input, ...){
ifStreamRef autoRewind(input);
}
Or, since the Ctor can do the conversion...
void read_value(ifStreamRef streamRef, ...) {
streamRef.mStream.getLine(...);
}
std::ifstream itself follows RAII, so it will close() the stream for you when your stream goes out of scope.
The long answer is that you should read up on dependency injection. Don't create dependencies inside of objects/functions that can be shared. There are lots of videos and documents on dependency injection and dependency inversion.
Basically, construct the objects that your objects depend on and pass them in as parameters.
The injection now relies on the interface of the objects that you pass in. So if you change your ifStreamRef class to act as an interface:
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::string getLine(){
// todo : mStream.getLine() + return "" on error;
}
bool eof() { return mStream.eof(); }
std::ifstream& mStream;
}
Then later on you can change the internal implementation that would take a reference to vector<string>& instead of ifstream...
class ifStreamRef{
ifStreamRef(std::vector<string>& _in) : mStream(_in), mCursor(0){}
~ifStreamRef(){}
std::string getLine(){
// todo : mStream[mCursor++] + return "" on error;
}
bool eof() { return mCursor >= mStream.size(); }
std::vector<string>& mStream;
size_t mCursor;
}
I have oversimplified a few things.

Stop process if there is an error in the constructor

In a utility class file, I want to open a file to read or write it.
If I can't open it, I don't want to continue the process.
FileUtility::FileUtility(const char *fileName) {
ifstream in_stream;
in_stream.open(filename);
}
FileUtility fu = FileUtility("bob.txt");
fu.read();
fu.write();
File bob.txt doesn't exist, so I don't want method to read and write.
Is there a clean way to do it?
When construction of an object fails in C++, you should throw an exception, or propagate the exception from the failed construction of the subobject.
FileUtility(const char* filename) {
std::ifstream in_stream;
in_stream.exceptions(std::ios_base::failbit);
in_stream.open(filename); // will throw if file can't be opened
}
In the calling code you can choose to handle the exception:
try {
FileUtility fu = FileUtility("bob.txt");
} catch (std::ios_base::failure) {
printf("Failed to open bob.txt\n");
exit(EXIT_FAILURE);
}
// do other stuff
Or, if you don't catch the exception, the runtime will just call std::terminate(), which will print out its own error message, which may or may not be helpful:
terminate called after throwing an instance of 'std::ios_base::failure'
what(): basic_ios::clear
Aborted
There are generally four ways error state can be communicated from a callee to a caller:
1. Direct return value (return code or OUT parameter).
A return code is not possible for a constructor call, although an OUT parameter is. However, it's somewhat invasive to require every function to provide its return code or an OUT parameter for this purpose, so I don't like this solution in general, although it is certainly heavily used in various libraries and APIs. You could use this approach by adding a pointer or reference parameter to your constructor, to which the caller could provide the address of some local error variable, into which the constructor could store a possible return value. I don't recommend this.
2. Exceptions.
There is a somewhat polarized debate on the pros and cons of exceptions, in both C++ code and in other languages. I may take some downvotes for saying this, but my personal opinion is that exceptions should be avoided like the plague. See http://www.joelonsoftware.com/items/2003/10/13.html for someone who shares my view. But this is a workable solution if you're so inclined. See #Brian's answer for a good demonstration of this solution.
3. Object attribute.
The std::ifstream object actually does this, so you can leverage that. (Actually, from your example code, you define your std::ifstream as a local variable in the constructor, which implies it won't persist after the call, but since you call some kind of read() and write() methods on the constructed object, that implies that you do persist it after the call, so I'm going to assume the latter is the correct inference.) You can leverage that, by calling std::ifstream::is_open(). If you want to maintain encapsulation of the std::ifstream, you can define your own is_open() equivalent on FileUtility that will simply return in_stream.is_open();, again, assuming it is retained as an attribute on your FileUtility class.
struct FileUtility {
ifstream ifs;
FileUtility(const char* fileName);
bool is_open(void) const;
};
FileUtility::FileUtility(const char* fileName) { ifs.open(fileName); }
bool FileUtility::is_open(void) const { return ifs.is_open(); }
FileUtility fu = FileUtility("bob.txt");
if (!fu.is_open()) return 1;
Alternatively, you could create a whole new error state layer just for the FileUtility class, and propagate the std::ifstream error through that. For example:
struct FileUtility {
static const int ERROR_NONE = 0;
static const int ERROR_BADFILE = 1;
ifstream ifs;
int error;
FileUtility(const char* fileName);
};
FileUtility::FileUtility(const char* fileName) : error(ERROR_NONE) {
ifs.open(fileName);
if (!ifs.is_open()) { error = ERROR_BADFILE; return; }
}
FileUtility fu = FileUtility("bob.txt");
if (fu.error != FileUtility::ERROR_NONE) return 1;
These are reasonable solutions.
4. Global error state.
I wouldn't be surprised if some programmers were to respond with a "that sounds like a bad idea" reaction to this possible solution, but the truth is that many extremely successful and prominent code bases use this solution for communicating error state. Perhaps the best examples are the errno variable used by the C Standard Library (although it should be mentioned that errno sort of works in conjunction with direct return codes), and the GetLastError() system used by the Windows C API. I suppose some might argue that that's really the "C approach", and exceptions are the "C++ approach", but again, I avoid exceptions like the plague.
As an aside, multithreadedness is not a problem for this solution, because errno and GetLastError() both use thread-local error state, rather than true global error state.
I like this solution best, because it's simple, extremely uninvasive, and can easily be reused by different code bases, provided of course that you define the error framework (basically the thread-local variable and possibly the ERROR_NONE macro/global; see below) in its own library, in which case your code gains a consistency when it comes to error handling.
Example:
#define ERROR_NONE 0
thread_local int error = ERROR_NONE;
struct FileUtility {
static const int ERROR_BADFILE = 1;
ifstream ifs;
FileUtility(const char* fileName);
};
FileUtility::FileUtility(const char* fileName) {
ifs.open(fileName);
if (!ifs.is_open()) { error = ERROR_BADFILE; return; }
}
FileUtility fu = FileUtility("bob.txt");
if (error != ERROR_NONE) return 1;
This is the solution I'd recommend; otherwise I'd go with an object attribute solution.

Expressing "read-only, no modification of position" for std::ifstream

In my code, I want to identify some properties about the contents of a file, before deciding how to read the file. (That is, I search for a keyword, if found, it's going to be read with foo(std::ifstream&), else with bar(std::ifstream&)).
I implemented the method that searches for the keyword as
bool containsKeyword(std::ifstream& file, const char* keyword)
{
for ( std::string line; std::getline(file, line); )
{
if ( line == keyword )
{
return true;
}
}
return false;
}
This modifies the position of the file stream (either the end, if the keyword isn't found, or the position of the keyword). However I want that the position is reset after the search. This can be done with a ScopeGuard:
class FilePositionScopeGuard
{
private:
std::ifstream& file;
using FilePosition = decltype(std::declval<std::ifstream>().tellg());
FilePosition initial_position;
public:
FilePositionScopeGuard(std::ifstream& file_)
:
file(file_),
initial_position(file.tellg())
{
}
~FilePositionScopeGuard()
{
file.clear();
file.seekg(initial_position);
}
};
Now we add this to the method:
bool containsKeyword(std::ifstream& file, const char* keyword)
{
FilePositionScopeGuard guard(file);
for ( std::string line; std::getline(file, line); )
{
...
That's nice, because with exactly one additional line in the method, we get the behaviour of not modifying the std::ifstream no matter how the method is exited (one of the returns or an exception).
However, the method bool containsKeyword(std::ifstream&, const char*); does not express the constness. How can I adjust my method to express (at the level of the interface) that the method will not alter the current state?
You could change the signature to take a position-guarded file:
bool containsKeyword(const FilePositionScopeGuard &, const char *);
This allows the caller to pass an ifstream per the current signature (constructing a temporary guard for that operation), or to make their own guard and use it for several operations.
You'll need to make the ifstream member publicly accessible.
Do it with the text comment // the method does read from file but resets the read pointer.
Do not expect a user of the API to be a monkey at keyboard. Specifically don't mark ifstream argument as const while casting constancy out inside the method. It does make difference in a multithreaded program.

check if something was serialized in std::ostream

Is there an easy way to check if something was serialized in stl::ostream. I am looking for something like:
some preparation
// ... a very complex code that may result in adding or not to the stream,
// that I will prefer not to change
check if the stream has something added
Note that this will need to works recursively. Is using register_callback is a good idea or there is easier way?
First the immediate question: register_callback() is intended to deal with appropriate copying and releasing of resources stored in pword() and will have operations only related to that (i.e., copying, assigning, and releasing plus observing std::locale changes). So, no, that won't help you at all.
What you can do, however, is to create a filtering stream buffer which observes if there was a write to the stream, e.g., something like this:
class changedbuf: std::streambuf {
std::streambuf* d_sbuf;
bool d_changed;
int_type overflow(int_type c) {
if (!traits_type::eq_int_type(c, traits_type::eof())) {
this->d_changed = true;
}
return this->d_sbuf->sputc(c);
}
public:
changedbuf(std::streambuf* sbuf): d_sbuf(d_sbuf), d_changed() {}
bool changed() const { return this->d_changed; }
}
You can use this in place of the std::ostream you already have, e.g.:
void f(std::ostream& out) {
changedbuf changedbuf(out.rdbuf());
std::ostream changedout(&changedbuf);
// use changedout instead of out; if you need to use a global objects, you'd
// replace/restore the used stream buffer using the version of rdbuf() taking
// an argument
if (changedbuf.change()) {
std::cout << "there was a change\n";
}
}
A real implementation would actually provide a buffer and deal with proper flushing (i.e., override sync()) and sequence output (i.e., override xsputn()). However, the above version is sufficient as a proof-of-concept.
Others are likely to suggest the use of std::ostringstream. Depending on the amount of data written, this can easily become a performance hog, especially compared to an advanced version of changedbuf which appropriately deals with buffering.
Are you passing the stream into the complex code, or is it globally visible? Can it be any kind of ostream or can you constrain the type to ofstream or ostringstream?
You may be able to use tellp to determine whether the file position has changed since your preparation code, if your ostream type supports it (such as with most fstreams). Or, if you're passing the stream in, you could pass an empty ostringstream in and check that it's not empty when the string is extracted to be printed out.
It's not entirely obvious which solution, if any, would be appropriate for you without knowing more about the context of your code and the specifics of your problem. The best answer may be to return (or set as a by-reference out-parameter) a flag indicating whether the stream was inserted into.