xostream2.h

// xostream2.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2008

#pragma once
#ifndef Ceda_cxUtils_xostream2_H
#define Ceda_cxUtils_xostream2_H

#include "cxUtils.h"
#include "xchar.h"
#include "Archive.h"
#include <iostream>

namespace ceda
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// xostream2

/*
An xostream2 writes text, and text is assumed to consist of characters that are of 
type xchar.
*/

class cxUtils_API xostream2
{
    cxNotCloneable(xostream2)
    
public:
    xostream2(Archive& ar);
    
    // todo : should use same type as used by the STL
    typedef ssize_t streamsize;
    
    void close() { flush(); }
    void flush() { m_ar.Flush(); }
    void endl();
    void ends();

    /////////////////////////////////////// unformatted output /////////////////////////////////////

    // Write the given string directly to the archive, without accounting for field width
    // fill character and jusitifcation (contrast with put(str,numChars) method)
    void write(const xchar* str, ssize_t numChars)
    {
        cxAssert(numChars == 0 || str != nullptr);
        m_ar.WriteBuffer(str,numChars * sizeof(xchar));
    }
    
    // Write the given bytes to the underlying archive
    void writebytes(const octet_t* buffer, ssize_t numBytes)
    {
        cxAssert(numBytes == 0 || buffer != nullptr);
        cxAssert(numBytes % sizeof(xchar) == 0);
        m_ar.WriteBuffer(buffer,numBytes);
    }
    
    /////////////////////////////////////// formatted output /////////////////////////////////////
    /*
    The put functions are used for formatted output - meaning that
    items are written to the output stream accounting for the current field width, fill character
    and justification.
    
    Note: it appears that in STL 'put' is actually used for unformatted output, so some renaming is
    in order.
    */

    // VS2008
    //      std::basic_ostream<char> writes an unsigned char as a character not an integer.
    //      std::basic_ostream<wchar_t> writes an unsigned char as an integer not a character.
    // This behaviour seems unnecessarily inconsistent.

    void put(bool);
    void put(char);
    void put(signed char);
    void put(unsigned char);
    void put(wchar_t);
    void put(char16_t);
    void put(char32_t);
    void put(short);
    void put(unsigned short);
    void put(int);
    void put(unsigned int);
    void put(long);
    void put(unsigned long);
    void put(long long);
    void put(unsigned long long);
    void put(float);
    void put(double);
    void put(long double);

    void put(const void* f); 
    
    void unformatted_put(xchar v)
    {
        m_ar << v;
    }

    void put(ConstStringZ str) { put(str, strlen(str)); }
    void put(const xchar* str, ssize_t numChars);
        
    void put_internal(const xchar* buffer, ssize_t ln, ssize_t tn);

    typedef xostream2& (*Manipulator)(xostream2& os);
    xostream2& operator<<(Manipulator f)
    {
        return f(*this);
    }

	streamsize precision() const { return m_precision; }
	streamsize precision(streamsize p) { streamsize prev = m_precision; m_precision = p; return prev; }
	streamsize width() const { return m_width; }
	streamsize width(streamsize w) { streamsize prev = m_width; m_width = w; return prev; }

    typedef std::ios_base::fmtflags fmtflags;

    fmtflags get_flags() const 
    { 
        return m_flags; 
    }

	void set_flags(fmtflags f)
	{
        cxAssert((f & 0xffff) == f);
	    m_flags = f;
	}

	void setf(fmtflags f)
	{
        cxAssert((f & 0xffff) == f);
	    m_flags |= f;
	}

	void setf(fmtflags f, fmtflags mask)
	{
        cxAssert((mask & 0xffff) == mask);
        cxAssert((mask & f) == f);

	    m_flags = (m_flags & ~mask) | f;
	}

	void unsetf(fmtflags mask)
	{
        cxAssert((mask & 0xffff) == mask);
    	m_flags &= ~mask;
	}
	
    Archive& m_ar;
    streamsize m_width;
    streamsize m_precision;
    xchar m_fillChar;
    fmtflags m_flags;
};

inline xostream2& operator<<(xostream2& os, bool f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, char f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, signed char f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, unsigned char f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, wchar_t f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, char16_t f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, char32_t f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, short f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, unsigned short f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, int f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, unsigned int f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, long f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, unsigned long f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, long long f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, unsigned long long f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, float f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, double f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, long double f) { os.put(f); return os; }

inline xostream2& operator<<(xostream2& os, const void* f) { os.put(f); return os; }
inline xostream2& operator<<(xostream2& os, ConstStringZ f) { os.put(f); return os; }

// store function pointer and argument value
template<typename Arg>
struct SingleArgManip2
{	
    SingleArgManip2(void (*fn)(xostream2&, Arg), Arg arg)
	    : m_fn(fn), m_arg(arg)
	{
	}

    void (*m_fn)(xostream2&, Arg);	    // the function pointer
    Arg m_arg;	                        // the argument value
};

// insert by calling function with output stream and argument
template<typename Arg> 
inline xostream2& operator<<(xostream2& os, const SingleArgManip2<Arg>& m)
{
	(*m.m_fn)(os, m.m_arg);
	return os;
}

cxUtils_API SingleArgManip2<ssize_t> setprecision2(ssize_t p);
cxUtils_API SingleArgManip2<ssize_t> setw2(ssize_t w);
cxUtils_API SingleArgManip2<xchar> setfill2(xchar c);

inline xostream2& endl(xostream2& os)
{
    os.endl();
    return os;
}

inline xostream2& ends(xostream2& os)
{
    os.ends();
    return os;
}

inline xostream2& flush(xostream2& os)
{
    os.flush();
    return os;
}


inline xostream2& boolalpha(xostream2& os) 
{ 
    os.setf(std::ios::boolalpha); 
    return os; 
}

inline xostream2& noboolalpha(xostream2& os) 
{ 
    os.unsetf(std::ios::boolalpha);
    return os; 
}


inline xostream2& showbase(xostream2& os) 
{ 
    os.setf(std::ios::showbase); 
    return os; 
}

inline xostream2& noshowbase(xostream2& os) 
{ 
    os.unsetf(std::ios::showbase);
    return os; 
}


inline xostream2& showpoint(xostream2& os) 
{ 
    os.setf(std::ios::showpoint); 
    return os; 
}

inline xostream2& noshowpoint(xostream2& os) 
{ 
    os.unsetf(std::ios::showpoint);
    return os; 
}


inline xostream2& showpos(xostream2& os) 
{ 
    os.setf(std::ios::showpos); 
    return os; 
}

inline xostream2& noshowpos(xostream2& os) 
{ 
    os.unsetf(std::ios::showpos);
    return os; 
}


inline xostream2& skipws(xostream2& os) 
{ 
    os.setf(std::ios::skipws); 
    return os; 
}

inline xostream2& noskipws(xostream2& os) 
{ 
    os.unsetf(std::ios::skipws);
    return os; 
}

inline xostream2& unitbuf(xostream2& os) 
{ 
    os.setf(std::ios::unitbuf); 
    return os; 
}

inline xostream2& nounitbuf(xostream2& os) 
{ 
    os.unsetf(std::ios::unitbuf);
    return os; 
}


inline xostream2& uppercase(xostream2& os) 
{ 
    os.setf(std::ios::uppercase); 
    return os; 
}

inline xostream2& nouppercase(xostream2& os) 
{ 
    os.unsetf(std::ios::uppercase);
    return os; 
}


inline xostream2& dec(xostream2& os) 
{ 
    os.setf(std::ios::dec, std::ios::basefield);
    return os; 
}

inline xostream2& oct(xostream2& os) 
{ 
    os.setf(std::ios::oct, std::ios::basefield);
    return os; 
}

inline xostream2& hex(xostream2& os) 
{ 
    os.setf(std::ios::hex, std::ios::basefield);
    return os; 
}


inline xostream2& left(xostream2& os) 
{ 
    os.setf(std::ios::left, std::ios::adjustfield);
    return os; 
}

inline xostream2& internal(xostream2& os) 
{ 
    os.setf(std::ios::internal, std::ios::adjustfield);
    return os; 
}

inline xostream2& right(xostream2& os) 
{ 
    os.setf(std::ios::right, std::ios::adjustfield);
    return os; 
}

inline xostream2& scientific(xostream2& os) 
{ 
    os.setf(std::ios::scientific, std::ios::floatfield);
    return os; 
}

inline xostream2& fixed(xostream2& os) 
{ 
    os.setf(std::ios::fixed, std::ios::floatfield);
    return os; 
}

///////////////////////////////////////////////////////////////////////////////////////////////////
extern cxUtils_API xostream2 xcout2;

} // namespace ceda

#endif // include guard