Boost logo

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