Subscribe to 10 GOTO 10        RSS Feed
-----

ios_base::xalloc and iostream

Icon 3 Comments
Over the years I have written a few stream manipulators and one thing that has kind of confounded me is a way to save persistent information for each stream. Well today I found a way.

Lets take a really simple example. You would like to add line numbers your output lines. Simple enough to do with a static variable and a manipulator:

ostream& NumLine(ostream& out) {
    static int linenum = 0;
    return out << linenum++ << ": ";
}

...

cout << NumLine << "I had a tiny turtle;" << endl;
cout << NumLine << "His name was Tiny Tim." << endl;


Well there are some problems here:

First of all there is no way (that I know of anyway) to reset the static variable -- so we are going to have to make this into a class and overload operator<< if we want to be able to reset the line numbers.

Next problem is that the numbers will be universal across streams. That is cout/wcout/cerr/clog/myfile will all have the same line numbers. If I made this into a class then I can create a unique NumLine object for each stream. Tada!

struct NumLine {
    int linenum;
    NumLine() : linenum(0) { }
    void reset() {
        linenum = 0;
    }
};

ostream& operator<<(ostream& out, NumLine& lnum) {
    return out << lnum.linenum++ << ": ";
}

NumLine coutNumber;

...

    cout << coutNumber << "I had a tiny turtle;" << endl
         << coutNumber << "His name was Tiny Tim." << endl;



Only after a while you begin to realize that having to create new objects and then either make them global or pass them about beings to be kind of pain.

So next solution? Add a static map<basic_ostream*, int> into your object?

Until today I had never really found a satisfying solution. BUT today I learned that each stream maintains an extensible array of data that can be, and is meant to be used for just this sort of thing!

#include <iostream>

using namespace std;

ostream& NumLine(ostream& out) {
    const static int index = ios_base::xalloc();
    return out << out.iword(index)++ << ": ";
}



int main() {
   
    
    cout << NumLine << "I had a tiny turtle;" << endl
         << NumLine << "His name was Tiny Tim." << endl
         << NumLine << "I put him in the bathtub;" << endl
         << NumLine << "to see if he could swim." << endl;
    cerr << NumLine << "He drank up all the water," << endl
         << NumLine << "And ate up all the soap," << endl
         << NumLine << "Now he's stuck in bed" << endl
         << NumLine << "With a bubble in his throat." << endl;

    return 0;
}



The static function ios_base::xalloc() returns a new index/handle to a member of the streams internal extensible array accessible though iword()/pword() -- the data can be access either as a long& (iword()) or as a pointer (pword() returns a void*&). The element is initialized to zero (handy).

Now there are still some problems, namely that the stream may contain the data but it is unaware of it. That means that the data must be maintained by external objects/function. So for example if pword(index) points to a dynamic chunk of memory the stream will not free/delete that memory when it is destoryed. HOWEVER you can register a callback function using ios_base::register_callback() so do your clean up. So all in all this is a pretty neat little adventure into extending the iostream capability.

References:
[1] Rogue Wave Software: Standard C++ Library Iostreams and Locales User's Guide : Chapter 15: Stream Storage for Private Use
[2] MSDN ios_base::xalloc / ios_base::iword() / ios_base::pword()
[3] ACCU: Extensibility - A Reason For Using Streams in C++
[4] cppreference.com : ios_base::xalloc / ios_base::iword / ios_base::pword
[5] The C++ standard library: a tutorial and handbook, Nicolai M. Josuttis

3 Comments On This Entry

Page 1 of 1

diego_pmc Icon

16 March 2011 - 10:58 AM
Very interesting! I'll bookmark this.
0

ishkabible Icon

16 March 2011 - 08:26 PM
really neat actually, i might be able to this in error handling for my little language, i finished the parser like an hour ago. i may modifiy my error handlers using this. thanks!!
0

Kutlar Icon

18 March 2011 - 07:28 PM
Nice! :bigsmile:
0
Page 1 of 1

September 2014

S M T W T F S
  1 23456
78910111213
14151617181920
21222324252627
282930    

Recent Entries

Search My Blog

0 user(s) viewing

0 Guests
0 member(s)
0 anonymous member(s)