Boost logo

Boost :

From: Maciej Sobczak (maciej_at_[hidden])
Date: 2002-10-21 01:57:18


Hi,

Jaakko Jarvi wrote:
> Hello Boosters,
>
> xalloc, pword, iword can be used to store stuff (e.g. manipulator state)
> in an internal array of a stream.
[...]
> Has anyone dealt with this before?
> Or is there someone out there who knows about iostreams and would be
> interested in the task of creating some wrapping around these
> functions to make them more accessible?

Some time ago I have tried to find a safe idiom for this task.
I have sent it to comp.lang.c++.moderated (msg id:
<aeqbci$h4r$1_at_[hidden]>, sent on 19 Jun 2002) and nobody
shouted at me. ;-)

I think I can safely repeat the code here:

---
#include <iostream>
class mymodifier
{
public:
     // a state for parentheses, "()" by default
     struct mystate
     {
     mystate()
         : left_('('), right_(')') {}
     char left_;
     char right_;
     };
     mymodifier(char left, char right)
         : left_(left), right_(right) {}
     std::ostream & modify(std::ostream &os) const
     {
         mystate *ms = mystate_slot(os);
         ms->left_ = left_;
         ms->right_ = right_;
         return os;
     }
     static mystate * mystate_slot(std::ios_base &io)
     {
         static int index = std::ios_base::xalloc();
         void *&p = io.pword(index);
         if (io.bad())
             throw std::bad_alloc();
         if (p == NULL)
         {
             // allocate default state if new
             p = new mystate;
             io.register_callback(mystate_cleanup, 0);
         }
         return static_cast<mystate*>(p);
     }
     static void mystate_cleanup(std::ios_base::event e,
         std::ios_base &io, int)
     {
         if (e == std::ios_base::erase_event)
         {
             mystate *ms = mystate_slot(io);
             delete ms;
         }
     }
private:
     char left_;
     char right_;
};
std::ostream & operator<<(std::ostream &os,
     const mymodifier &m)
{
     return m.modify(os);
}
class mypair
{
public:
     mypair(int a, int b) : a_(a), b_(b) {}
     std::ostream & print(std::ostream &os) const
     {
         // get the stream state (maybe default) and use it
         mymodifier::mystate *ms =
             mymodifier::mystate_slot(os);
         return os << ms->left_ << a_ << ", " << b_ << ms->right_;
     }
private:
     int a_;
     int b_;
};
std::ostream & operator<<(std::ostream &os,
     const mypair &p)
{
     return p.print(os);
}
int main()
{
     mypair p(1, 2);
     std::cout << p << std::endl;
     std::cout << mymodifier('[', ']') << p << std::endl;
     std::cout << mymodifier('{', '}') << p << std::endl;
     return 0;
}
This program prints:
(1, 2)
[1, 2]
{1, 2}
---
I think it can be a good place to start.
The first shot (not tested) is to templatize the object stored in the slot:
template <class T>
class modifier
{
public:
     modifier() {} // default state value
     modifier(const T &s) : state_(s) {}
     std::ostream & modify(std::ostream &os) const
     {
         T *ps = state_slot(os);
	state_ = *ps;
         return os;
     }
     static T * state_slot(std::ios_base &io)
     {
         static int index = std::ios_base::xalloc();
         void *&p = io.pword(index);
         if (io.bad())
             throw std::bad_alloc();
         if (p == NULL)
         {
             // allocate default state if new
             p = new T;
             io.register_callback(state_cleanup, 0);
         }
         return static_cast<T*>(p);
     }
private:
     static void state_cleanup(std::ios_base::event e,
         std::ios_base &io, int)
     {
         if (e == std::ios_base::erase_event)
         {
             T *ps = state_slot(io);
             delete ps;
         }
     }
     T state_;
};
template <class T>
std::ostream & operator<<(std::ostream &os,
     const modifier<T> &m)
{
     return m.modify(os);
}
I did not compile it, but I think it is quite generic.
The only difference from the original code is that now the type stored 
in the slot is external to the modifier wrapper (previously it was 
nested class).
Do you think it is a good idea to push it forward?
I would like to volunteer, but give me few days. ;)
Cheers,
Maciej Sobczak
http://www.maciejsobczak.com/

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk