Program Listing for File number.hpp
↰ Return to documentation for file (include/ecl/formatters/number.hpp
)
/*****************************************************************************
** Ifdefs
*****************************************************************************/
#ifndef ECL_FORMATTERS_NUMBER_HPP_
#define ECL_FORMATTERS_NUMBER_HPP_
/*****************************************************************************
** Includes
*****************************************************************************/
#include "common.hpp"
#include <ecl/exceptions/standard_exception.hpp>
#include <ecl/converters/char_strings.hpp>
/*****************************************************************************
** Namespaces
*****************************************************************************/
namespace ecl {
/*****************************************************************************
** Format Tags
*****************************************************************************/
enum IntegralBase
{
Bin,
Hex,
Dec,
};
namespace interfaces {
/*****************************************************************************
** FormatNumber Interface [Integral types]
*****************************************************************************/
template < typename Number >
class FormatNumber {
public:
/******************************************
** C&D's
*******************************************/
FormatNumber(int w = -1, ecl::Alignment a = NoAlign, ecl::IntegralBase b = Dec) : prm_width(w),prm_alignment(a),prm_base(b),width_(&prm_width),alignment_(&prm_alignment),base_(&prm_base),ready_to_format(false) {}
virtual ~FormatNumber() {}
/******************************************
** Set
*******************************************/
FormatNumber<Number>& base(ecl::IntegralBase b);
FormatNumber<Number>& width(int w);
FormatNumber<Number>& align(ecl::Alignment a);
/******************************************
* Set Format Combinations
******************************************/
FormatNumber<Number>& operator ()(int w, ecl::Alignment a, ecl::IntegralBase b);
/******************************************
** Format a value
*******************************************/
FormatNumber<Number>& operator() (Number n);
/******************************************
** Common format usages
*******************************************/
FormatNumber<Number>& operator() (Number n, int w, ecl::IntegralBase b);
FormatNumber<Number>& operator() (Number n, int w, ecl::Alignment a, ecl::IntegralBase b);
/******************************************
** Insert the formatter into a stream
*******************************************/
template <typename OutputStream, typename N> friend OutputStream& operator << (OutputStream& ostream, FormatNumber<N>& formatter);
protected:
/******************************************
** Paramaters
*******************************************/
int prm_width, tmp_width;
ecl::Alignment prm_alignment, tmp_alignment;
ecl::IntegralBase prm_base, tmp_base;
int *width_;
ecl::Alignment *alignment_; IntegralBase *base_;
bool ready_to_format;
Number value_;
/******************************************
** Padding
*******************************************/
template <typename OutputStream> void pad(int n, OutputStream &ostream) const;
template <typename OutputStream> void prePad(int n, OutputStream &ostream) const;
template <typename OutputStream> void postPad(int n, OutputStream &ostream) const;
/******************************************
** Formatter Functions
*******************************************/
template <typename OutputStream> void formatBin(OutputStream &ostream) const;
template <typename OutputStream> void formatHex(OutputStream &ostream) const;
template <typename OutputStream> void formatDec(OutputStream &ostream) const;
}; // FormatNumber
/*****************************************************************************
* FormatNumber Implementation [configuration]
*****************************************************************************/
template <typename Number>
FormatNumber<Number>& FormatNumber<Number>::base(ecl::IntegralBase b)
{
*base_ = b;
return *this;
}
template <typename Number>
FormatNumber<Number>& FormatNumber<Number>::width(int w)
{
*width_ = w;
if ( ( *width_ > 0 ) && ( *alignment_ == NoAlign ) ) {
*alignment_ = RightAlign;
}
return *this;
}
template <typename Number>
FormatNumber<Number>& FormatNumber<Number>::align(ecl::Alignment a)
{
*alignment_ = a;
if ( *alignment_ == NoAlign )
{
*width_ = 0;
}
return *this;
}
template <typename Number>
FormatNumber<Number>& FormatNumber<Number>::operator () (int w, ecl::Alignment a, ecl::IntegralBase b)
{
base(b);
width(w);
align(a);
return *this;
}
/*****************************************************************************
* FormatNumber Implementation [internal formatting]
*****************************************************************************/
template <typename Number>
template <typename OutputStream>
void FormatNumber<Number>::formatBin(OutputStream &ostream) const
{
int size = 8*sizeof(Number);
prePad(*width_ - (size + 2),ostream);
ostream << "0b";
for (int i = size - 1; i>=0; i--)
{
ostream << "01"[((value_ >> i) & 1)];
}
postPad(*width_ - (size + 2),ostream);
}
template <typename Number>
template <typename OutputStream>
void FormatNumber<Number>::formatHex(OutputStream &ostream) const
{
static const char hex_string[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
int size = 2*sizeof(Number);
prePad(*width_ - (size + 2),ostream);
ostream << "0x";
for (int i = size - 1; i>=0; i--)
{
// ostream << "0123456789abcdef"[((value_ >> i*4) & 0xF)];
ostream << hex_string[((value_ >> i*4) & 0xF)]; // Dont have to recreate this every time
}
postPad(*width_ - (size + 2),ostream);
}
template <typename Number>
template <typename OutputStream>
void FormatNumber<Number>::formatDec(OutputStream &ostream) const
{
static ecl::Converter<char*> convert;
char *s = convert(value_);
int size = strlen(s);
prePad(*width_ - size,ostream);
ostream << s;
postPad(*width_ - size,ostream);
}
template <typename Number>
template <typename OutputStream>
void FormatNumber<Number>::prePad(int n, OutputStream &ostream) const
{
if ( n <= 0 ) { return; }
switch ( *alignment_ )
{
case ( NoAlign ) : { break; }
case ( LeftAlign ) : { break; }
case ( RightAlign ) : { pad(n,ostream); break; }
case ( CentreAlign ) : { pad(n/2+ n%2,ostream); break; } // Add the remainder
default : break;
}
}
template <typename Number>
template <typename OutputStream>
void FormatNumber<Number>::postPad(int n, OutputStream &ostream) const
{
if ( n <= 0 ) { return; }
switch ( *alignment_ )
{
case ( NoAlign ) : { break; }
case ( LeftAlign ) : { pad(n,ostream); break; }
case ( RightAlign ) : { break; }
case ( CentreAlign ) : { pad(n/2,ostream); break; } // Do not add the remainder
default : break;
}
}
template <typename Number>
template <typename OutputStream>
void FormatNumber<Number>::pad(int n, OutputStream &ostream) const
{
for (int i = n; i > 0; --i )
{
ostream << ' ';
}
}
/*****************************************************************************
* FormatNumber Implementation [value]
*****************************************************************************/
template <typename Number>
FormatNumber<Number>& FormatNumber<Number>::operator()(Number n)
{
value_ = n;
ready_to_format = true;
return *this;
}
/*****************************************************************************
* FormatNumber Implementation [temporary formatting]
*****************************************************************************/
template <typename Number>
FormatNumber<Number>& FormatNumber<Number>::operator() (Number n, int w, ecl::IntegralBase b)
{
width_ = &tmp_width;
alignment_ = &tmp_alignment;
base_ = &tmp_base;
base(b);
width(w);
value_ = n;
ready_to_format = true;
return *this;
}
template <typename Number>
FormatNumber<Number>& FormatNumber<Number>::operator() (Number n, int w, ecl::Alignment a, ecl::IntegralBase b)
{
width_ = &tmp_width;
alignment_ = &tmp_alignment;
base_ = &tmp_base;
base(b);
width(w);
align(a);
value_ = n;
ready_to_format = true;
return *this;
}
/*****************************************************************************
* FormatNumber Implementation [streaming]
*****************************************************************************/
template <typename OutputStream, typename N>
OutputStream& operator << (OutputStream &ostream, FormatNumber<N>& formatter )
{
bool ready = formatter.ready_to_format;
ecl_assert_throw(ready, StandardException(LOC,UsageError,"The formatter cannot print any data - "
"either there is no data available, or you have tried to use the "
"formatter more than once in a single streaming operation. "
"C++ produces unspecified results when functors are used multiply "
"in the same stream sequence, so this is not permitted here.") );
if ( ready )
{
switch(*(formatter.base_) )
{
case(Bin) : {
formatter.formatBin(ostream);
break;
}
case(Hex) : {
formatter.formatHex(ostream);
break;
}
case(Dec) : {
formatter.formatDec(ostream);
break;
}
}
if ( formatter.width_ != &(formatter.prm_width) ) {
formatter.width_ = &(formatter.prm_width);
formatter.alignment_ = &(formatter.prm_alignment);
formatter.base_ = &(formatter.prm_base);
}
formatter.ready_to_format = false;
}
return ostream;
}
} // namespace interfaces
/*****************************************************************************
* Format Classes
*****************************************************************************/
template <>
class Format<short> : public interfaces::FormatNumber<short>
{
public:
Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<short>(w, a, b) {}
virtual ~Format() {}
};
template <>
class Format<int> : public interfaces::FormatNumber<int>
{
public:
Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<int>(w, a, b) {}
virtual ~Format() {}
};
template <>
class Format<long> : public interfaces::FormatNumber<long>
{
public:
Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<long>(w, a, b) {}
virtual ~Format() {}
};
template <>
class Format<char> : public interfaces::FormatNumber<char>
{
public:
Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<char>(w, a, b) {}
virtual ~Format() {}
};
template <>
class Format<signed char> : public interfaces::FormatNumber<signed char>
{
public:
Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<signed char>(w, a, b) {}
virtual ~Format() {}
};
template <>
class Format<unsigned short> : public interfaces::FormatNumber<unsigned short>
{
public:
Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<unsigned short>(w, a, b) {}
virtual ~Format() {}
};
template <>
class Format<unsigned int> : public interfaces::FormatNumber<unsigned int>
{
public:
Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<unsigned int>(w, a, b) {}
virtual ~Format() {}
};
template <>
class Format<unsigned long> : public interfaces::FormatNumber<unsigned long>
{
public:
Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<unsigned long>(w, a, b) {}
virtual ~Format() {}
};
template <>
class Format<unsigned char> : public interfaces::FormatNumber<unsigned char>
{
public:
Format(int w = -1, Alignment a = NoAlign, IntegralBase b = Dec) : interfaces::FormatNumber<unsigned char>(w, a, b) {}
virtual ~Format() {}
};
} // namespace ecl
#endif /*ECL_FORMATTERS_NUMBER_HPP_*/