Listing 3 - Temperature.cpp

// My header
#include "Temperature.h"

#include <ostream>
#include <istream>
#include <stdexcept>

namespace Util {

// iword / pword index
const int Temperature::strm_index = std::ios::xalloc();

// Facet id
std::locale::id            Temperature::temp_put::id;

// Static facets
Temperature::temp_put    Temperature::temp_put_asK(&_putK);
Temperature::temp_put    Temperature::temp_put_asC(&_putC);
Temperature::temp_put    Temperature::temp_put_asF(&_putF);


// manipulators
std::ostream&
Temperature::asK(std::ostream& os)
{
    os.pword(strm_index) = &_putK;
    return os;
};

std::ostream&
Temperature::asC(std::ostream& os)
{
    os.pword(strm_index) = &_putC;
    return os;
};

std::ostream&
Temperature::asF(std::ostream& os)
{
    os.pword(strm_index) = &_putF;
    return os;
};

std::ostream&
Temperature::showscale(std::ostream& os)
{
    os.iword(strm_index) = 1;
    return os;
};

std::ostream&
Temperature::noscale(std::ostream& os)
{
    os.iword(strm_index) = 0;
    return os;
};

// output formaters
std::ostream&
Temperature::_putK(std::ostream& os, Temperature obj, long flags)
{
    bool show_scale = flags bitand 1;
    int width = os.width();
    if (show_scale and width > 0) 
        os.width(width-1);
        
    os << obj.inK();
    if (show_scale) os << 'K';
    return os;
}

std::ostream&
Temperature::_putC(std::ostream& os, Temperature obj, long flags)
{
    bool show_scale = flags bitand 1;
    int width = os.width();
    if (show_scale and width > 0) 
        os.width(width-1);
        
    os << obj.inC();
    if (show_scale) os << 'C';
    return os;
}

std::ostream&
Temperature::_putF(std::ostream& os, Temperature obj, long flags)
{
    bool show_scale = flags bitand 1;
    int width = os.width();
    if (show_scale and width > 0) 
        os.width(width-1);
        
    os << obj.inF();
    if (show_scale) os << 'F';
    return os;
}

// ostream inserter
std::ostream&
operator<<(std::ostream& os, Temperature obj)
{
    int idx = Temperature::strm_index;
    Temperature::Formater fmt = Temperature::Formater(os.pword(idx));
    if (fmt)
        return fmt(os, obj, os.iword(idx));

    // no format specified, check the locale
    std::locale loc = os.getloc();
    bool found = std::has_facet<Temperature::temp_put>(loc));
    if (not found) {
        os.setstate(std::ios::failbit);    // may throw exception
        return os;
    }

    // get and use the facet
    const Temperature::temp_put& fac =
       std::use_facet<Temperature::temp_put>(loc));
    return fac.put(os, obj, os.iword(idx));
}


// istream extractor
std::istream&
operator>>(std::istream& is, Temperature& obj)
{
    // Assumed to be in format 'nn.nX' where 'X' is F/C/K
    // Read the number
    float val = -1.0;
    is >> val;
    
    // Get next character
    int ch = is.get();
    switch (char(ch)) {
    case 'F':
        obj = Temperature::inF(val);
        break;
    case 'C':
        obj = Temperature::inC(val);
        break;
    case 'K':
        obj = Temperature::inK(val);
        break;
    default:
        is.setstate(std::ios::failbit);    // may throw exception
        obj = Temperature::inK(-1.0);
    }
    return is;
}


} //> namespace