gsf
gsf

Reputation: 7242

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?

Upvotes: 1

Views: 174

Answers (2)

Adam H. Peterson
Adam H. Peterson

Reputation: 4591

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.

Upvotes: 0

Dietmar Kühl
Dietmar Kühl

Reputation: 153840

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.

Upvotes: 3

Related Questions