|
Boost : |
From: Maciej Sobczak (maciej_at_[hidden])
Date: 2002-10-23 04:59:36
Hi Boosters,
Few days ago Jaakko Jarvi asked for safe wrapper for the xalloc, iword
and pword functionality in ios_base.
I've replied with my first draft and Gennaro Prota answered with remarks
about the safe destruction.
Now I would like to present some revamped implementation, see attachments.
It is a generic wrapper around the xalloc and pword (iword is out of
concern here, but can be easily added).
The simple test program (compiled on VC++6.5) is also provided.
I'd be very glad to know your opinion and comments on this code and I
hope you will find it useful.
Cheers,
Maciej Sobczak
http://www.maciejsobczak.com/
// a test program for the streamstate utility
#include "streamstate.h"
#include <iostream>
struct brackets
{
// default state
brackets()
: left_('('), right_(')') {}
// arbitrary state
brackets(char l, char r)
: left_(l), right_(r) {}
char left_;
char right_;
};
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
brackets &b = streamstate<brackets>::get(os);
return os << b.left_ << a_ << ", " << b_ << b.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 << streamstate<brackets>(brackets('[', ']'));
std::cout << p << std::endl;
std::cout << streamstate<brackets>(brackets('{', '}'));
std::cout << p << std::endl;
return 0;
}
// Copyright Maciej Sobczak, 2002
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.
#ifndef STREAMSTATE_H_INCLUDED
#define STREAMSTATE_H_INCLUDED
#include <iostream>
#include <new>
// State should be:
// default-constructible
// copy-constructible
// assignable
template <class State>
class streamstate
{
public:
// construct with the default state value
streamstate() {}
// construct with the given stream value
streamstate(const State &s) : state_(s) {}
// modifies the stream
// the return value is not really useful,
// it has to be downcasted to the expected stream type
std::ios_base & modify(std::ios_base &ios) const
{
void *&p = state_slot(ios, false);
if (p == NULL)
p = new State(state_);
else
*static_cast<State*>(p) = state_;
return ios;
}
static State & get(std::ios_base &ios)
{
State *p = static_cast<State*>(state_slot(ios, false));
// construct default state, if it is a new slot
if (p == NULL)
p = new State;
return *p;
}
private:
static void state_cleanup(std::ios_base::event e,
std::ios_base &ios, int)
{
if (e == std::ios_base::erase_event)
{
// safe delete if state_slot fails
delete static_cast<State*>(state_slot(ios, true));
}
}
static void *& state_slot(std::ios_base &io, bool cleanup)
{
static int index = std::ios_base::xalloc();
void *&p = io.pword(index);
if (cleanup == false)
{
if (io.bad())
throw std::bad_alloc();
if (p == NULL)
{
// it is a newly allocated slot
io.register_callback(state_cleanup, 0);
}
}
// note: if cleanup == true && pword failed,
// then p is a valid void *& initialized to 0
// (27.4.2.5/5)
return p;
}
State state_;
};
// convenience inserter for ostream classes
template <
class State,
class charT,
class traits
>
std::basic_ostream<charT, traits> &
operator<<(std::basic_ostream<charT, traits> &os,
const streamstate<State> &s)
{
s.modify(os);
return os;
}
#endif // STREAMSTATE_H_INCLUDED
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk