mirror of
https://github.com/boostorg/numeric_conversion.git
synced 2026-07-21 13:33:43 +00:00
Myself Added
[SVN r23175]
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
* text=auto !eol svneol=native#text/plain
|
||||
*.gitattributes text svneol=native#text/plain
|
||||
|
||||
# Scriptish formats
|
||||
*.bat text svneol=native#text/plain
|
||||
*.bsh text svneol=native#text/x-beanshell
|
||||
*.cgi text svneol=native#text/plain
|
||||
*.cmd text svneol=native#text/plain
|
||||
*.js text svneol=native#text/javascript
|
||||
*.php text svneol=native#text/x-php
|
||||
*.pl text svneol=native#text/x-perl
|
||||
*.pm text svneol=native#text/x-perl
|
||||
*.py text svneol=native#text/x-python
|
||||
*.sh eol=lf svneol=LF#text/x-sh
|
||||
configure eol=lf svneol=LF#text/x-sh
|
||||
|
||||
# Image formats
|
||||
*.bmp binary svneol=unset#image/bmp
|
||||
*.gif binary svneol=unset#image/gif
|
||||
*.ico binary svneol=unset#image/ico
|
||||
*.jpeg binary svneol=unset#image/jpeg
|
||||
*.jpg binary svneol=unset#image/jpeg
|
||||
*.png binary svneol=unset#image/png
|
||||
*.tif binary svneol=unset#image/tiff
|
||||
*.tiff binary svneol=unset#image/tiff
|
||||
*.svg text svneol=native#image/svg%2Bxml
|
||||
|
||||
# Data formats
|
||||
*.pdf binary svneol=unset#application/pdf
|
||||
*.avi binary svneol=unset#video/avi
|
||||
*.doc binary svneol=unset#application/msword
|
||||
*.dsp text svneol=crlf#text/plain
|
||||
*.dsw text svneol=crlf#text/plain
|
||||
*.eps binary svneol=unset#application/postscript
|
||||
*.gz binary svneol=unset#application/gzip
|
||||
*.mov binary svneol=unset#video/quicktime
|
||||
*.mp3 binary svneol=unset#audio/mpeg
|
||||
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
|
||||
*.ps binary svneol=unset#application/postscript
|
||||
*.psd binary svneol=unset#application/photoshop
|
||||
*.rdf binary svneol=unset#text/rdf
|
||||
*.rss text svneol=unset#text/xml
|
||||
*.rtf binary svneol=unset#text/rtf
|
||||
*.sln text svneol=native#text/plain
|
||||
*.swf binary svneol=unset#application/x-shockwave-flash
|
||||
*.tgz binary svneol=unset#application/gzip
|
||||
*.vcproj text svneol=native#text/xml
|
||||
*.vcxproj text svneol=native#text/xml
|
||||
*.vsprops text svneol=native#text/xml
|
||||
*.wav binary svneol=unset#audio/wav
|
||||
*.xls binary svneol=unset#application/vnd.ms-excel
|
||||
*.zip binary svneol=unset#application/zip
|
||||
|
||||
# Text formats
|
||||
.htaccess text svneol=native#text/plain
|
||||
*.bbk text svneol=native#text/xml
|
||||
*.cmake text svneol=native#text/plain
|
||||
*.css text svneol=native#text/css
|
||||
*.dtd text svneol=native#text/xml
|
||||
*.htm text svneol=native#text/html
|
||||
*.html text svneol=native#text/html
|
||||
*.ini text svneol=native#text/plain
|
||||
*.log text svneol=native#text/plain
|
||||
*.mak text svneol=native#text/plain
|
||||
*.qbk text svneol=native#text/plain
|
||||
*.rst text svneol=native#text/plain
|
||||
*.sql text svneol=native#text/x-sql
|
||||
*.txt text svneol=native#text/plain
|
||||
*.xhtml text svneol=native#text/xhtml%2Bxml
|
||||
*.xml text svneol=native#text/xml
|
||||
*.xsd text svneol=native#text/xml
|
||||
*.xsl text svneol=native#text/xml
|
||||
*.xslt text svneol=native#text/xml
|
||||
*.xul text svneol=native#text/xul
|
||||
*.yml text svneol=native#text/plain
|
||||
boost-no-inspect text svneol=native#text/plain
|
||||
CHANGES text svneol=native#text/plain
|
||||
COPYING text svneol=native#text/plain
|
||||
INSTALL text svneol=native#text/plain
|
||||
Jamfile text svneol=native#text/plain
|
||||
Jamroot text svneol=native#text/plain
|
||||
Jamfile.v2 text svneol=native#text/plain
|
||||
Jamrules text svneol=native#text/plain
|
||||
Makefile* text svneol=native#text/plain
|
||||
README text svneol=native#text/plain
|
||||
TODO text svneol=native#text/plain
|
||||
|
||||
# Code formats
|
||||
*.c text svneol=native#text/plain
|
||||
*.cpp text svneol=native#text/plain
|
||||
*.h text svneol=native#text/plain
|
||||
*.hpp text svneol=native#text/plain
|
||||
*.ipp text svneol=native#text/plain
|
||||
*.tpp text svneol=native#text/plain
|
||||
*.jam text svneol=native#text/plain
|
||||
*.java text svneol=native#text/plain
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../boost.css">
|
||||
<TITLE>Boost Numeric Conversion Library - Bounds</TITLE>
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
|
||||
<TABLE BORDER="0" CELLPADDING="7" CELLSPACING="0" WIDTH="100%"
|
||||
SUMMARY="header">
|
||||
<TR>
|
||||
<TH VALIGN="top" WIDTH="300">
|
||||
<H3><A HREF="../../../../index.htm"><IMG HEIGHT="86" WIDTH="277"
|
||||
ALT="C++ Boost" SRC="../../../../c++boost.gif" BORDER="0"></A></H3> </TH>
|
||||
<TH VALIGN="top">
|
||||
<H1 ALIGN="center">Boost Numeric Conversion Library</H1>
|
||||
|
||||
<H1><A HREF="http://www.boost.org">Header </A><A
|
||||
HREF="../../../../boost/numeric/bounds.hpp">boost/numeric/bounds.hpp</A></H1>
|
||||
</TH>
|
||||
</TR>
|
||||
</TABLE><HR>
|
||||
<H2>Contents</H2>
|
||||
<UL>
|
||||
<LI><A HREF="#introduction">Introduction</A></LI>
|
||||
<LI><A HREF="#bounds"><code>template class bounds<N></CODE></A></LI>
|
||||
<LI><A HREF="#examples">Examples</A></LI>
|
||||
<LI><A HREF="#implementation">Implementation</A></LI>
|
||||
<LI><A HREF="#portability">Portability</A></LI>
|
||||
</UL> <HR>
|
||||
<H2><A NAME="introduction">Introduction</A></H2>
|
||||
<P>To determine the ranges of numeric types with std:: numeric_limits
|
||||
[18.2.1], different syntax have to be used depending on numeric type.
|
||||
Specifically, numeric_limits<T>::min() for integral types returns the
|
||||
minimum finite value, whereas for floating point types it returns the minimum
|
||||
positive normalized value. The difference in semantics makes client code
|
||||
unnecessarily complex and error prone. <BR> <BR>
|
||||
boost::numeric::bounds<> provides a consistent interface for retrieving
|
||||
the maximum finite value, the minimum finite value and the minimum positive
|
||||
normalized value (0 for integral types) for numeric types. The selection of
|
||||
implementation is performed at compile time, so there is no runtime overhead.
|
||||
<BR>
|
||||
<BR> </P> <HR>
|
||||
<H2><A NAME="bounds"><CODE>traits class bounds<N></CODE></A></H2>
|
||||
<BLOCKQUOTE>
|
||||
|
||||
<PRE>template<class N>
|
||||
struct bounds
|
||||
{
|
||||
static N lowest () { return <i>implementation_defined</i>; }
|
||||
static N highest () { return <i>implementation_defined</i>; }
|
||||
static N smallest() { return <i>implementation_defined</i>; }
|
||||
};</PRE>
|
||||
</BLOCKQUOTE>
|
||||
<H3>Members</H3>
|
||||
<PRE>lowest()</PRE>
|
||||
<P>Returns the minimum finite value, equivalent to
|
||||
numeric_limits<T>::min() when T is an integral type, and to
|
||||
-numeric_limits<T>::max() when T is a floating point type. </P>
|
||||
<PRE>highest()</PRE>
|
||||
<P>Returns the maximum finite value, equivalent to
|
||||
numeric_limits<T>::max(). </P>
|
||||
<PRE>smallest()</PRE>
|
||||
|
||||
<P>Returns the smallest positive normalized value for floating point types with
|
||||
denormalization, or returns 0 for integral types. <BR>
|
||||
<BR>
|
||||
</P> <HR>
|
||||
<H2><A NAME="examples">Examples</A></H2>
|
||||
|
||||
<P>The following example demonstrates the use of numeric::bounds<> and the
|
||||
equivalent code using numeric_limits: </P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<PRE>#include <iostream>
|
||||
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
|
||||
int main() {
|
||||
|
||||
std::cout << "numeric::bounds versus numeric_limits example.\n";
|
||||
|
||||
std::cout << "The maximum value for float:\n";
|
||||
std::cout << boost::numeric::bounds<float>::highest() << "\n";
|
||||
std::cout << std::numeric_limits<float>::max() << "\n";
|
||||
|
||||
std::cout << "The minimum value for float:\n";
|
||||
std::cout << boost::numeric::bounds<float>::lowest() << "\n";
|
||||
std::cout << -std::numeric_limits<float>::max() << "\n";
|
||||
|
||||
std::cout << "The smallest positive value for float:\n";
|
||||
std::cout << boost::numeric::bounds<float>::smallest() << "\n";
|
||||
std::cout << std::numeric_limits<float>::min() << "\n";
|
||||
|
||||
return 0;
|
||||
}</PRE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<hr>
|
||||
<P>Back to <A HREF="index.html">Numeric Conversion library index</A></P>
|
||||
<HR>
|
||||
<P>Revised 23 June 2004</P>
|
||||
<p>© Copyright Fernando Luis Cacciola Carballal, 2000-2004</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -0,0 +1,334 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../boost.css">
|
||||
<TITLE>Boost Numeric Conversion Library - Conversion Traits</TITLE>
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000ff" VLINK="#800080">
|
||||
<TABLE BORDER="0" CELLPADDING="7" CELLSPACING="0" WIDTH="100%"
|
||||
SUMMARY="header">
|
||||
<TR>
|
||||
<TH VALIGN="top" WIDTH="300">
|
||||
<H3><A HREF="../../../../index.htm"><IMG HEIGHT="86" WIDTH="277"
|
||||
ALT="C++ Boost" SRC="../../../../c++boost.gif" BORDER="0"></A></H3> </TH>
|
||||
<TH VALIGN="top">
|
||||
<H1 ALIGN="center">Boost Numeric Conversion Library</H1>
|
||||
|
||||
<H1><A HREF="http://www.boost.org">Header </A><A
|
||||
HREF="../../../../boost/numeric/conversion_traits.hpp">boost/numeric/conversion_traits.hpp</A></H1>
|
||||
</TH>
|
||||
</TR>
|
||||
</TABLE> <HR>
|
||||
<H2>Contents</H2>
|
||||
<DL CLASS="page-index">
|
||||
<DT><A HREF="#types">Types</A></DT>
|
||||
</DL>
|
||||
<UL>
|
||||
|
||||
<LI><A HREF="#ncm"><CODE>enumeration boost::numeric::int_float_mixture_enum;</CODE></A></LI>
|
||||
<LI><A HREF="#ncsm"><CODE>enumeration boost::numeric::sign_mixture_enum;</CODE></A></LI>
|
||||
<LI><A HREF="#ncum"><CODE>enumeration boost::numeric::udt_builtin_mixture_enum;</CODE></A></LI>
|
||||
<LI><A HREF="#ifm"><CODE>template class boost::numeric::int_float_mixture<T,S></CODE></A></LI>
|
||||
<LI><A HREF="#sm"><CODE>template class boost::numeric::sign_mixture<T,S></CODE></A></LI>
|
||||
<LI><A HREF="#ubm"><CODE>template class boost::numeric::udt_builtin_mixture<T,S></CODE></A></LI>
|
||||
<LI><A HREF="#isr"><CODE>template class boost::numeric::is_subranged<T,S></CODE></A></LI>
|
||||
<LI><A HREF="#nct"><CODE>template class boost::numeric::conversion_traits<T,S></CODE></A></LI>
|
||||
</UL>
|
||||
<DL><DT><A HREF="#examples">Example(s)</A></DT></DL>
|
||||
<HR>
|
||||
|
||||
<H2><A NAME="types"></A>Types</H2>
|
||||
|
||||
<H2><CODE><A NAME="ncm">enumeration int_float_mixture</A>_enum</CODE></H2>
|
||||
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
enum int_float_mixture_enum
|
||||
{
|
||||
integral_to_integral
|
||||
,integral_to_float
|
||||
,float_to_integral
|
||||
,float_to_float
|
||||
} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
</PRE>
|
||||
|
||||
<H2><CODE><A NAME="ncsm">enumeration sign_mixture</A>_enum</CODE></H2>
|
||||
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
enum sign_mixture_enum
|
||||
{
|
||||
unsigned_to_unsigned
|
||||
,signed_to_signed
|
||||
,signed_to_unsigned
|
||||
,unsigned_to_signed
|
||||
} ;
|
||||
|
||||
} } // namespace boost::numeric</PRE>
|
||||
|
||||
<H2><CODE><A NAME="ncum">enumeration udt_builtin_mixture</A>_enum</CODE></H2>
|
||||
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
enum udt_builtin_mixture_enum
|
||||
{
|
||||
builtin_to_builtin
|
||||
,builtin_to_udt
|
||||
,udt_to_builtin
|
||||
,udt_to_udt
|
||||
} ;
|
||||
|
||||
} } // namespace boost::numeric</PRE>
|
||||
|
||||
<hr>
|
||||
|
||||
<H2><A NAME="ifm"><CODE>template class int_float_mixture<></CODE></A></H2>
|
||||
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
template <class T, class S>
|
||||
struct int_float_mixture : mpl::integral_c<int_float_mixture_enum, <i>impl-def-value</i>> {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
</PRE>
|
||||
<p>Classifying <code>S</code> and <code>T</code> as either <code>integral</code>
|
||||
or <code>float</code>, this <a href="../../../mpl/doc/ref/Integral_Constant.html">MPL's Integral Constant</a>
|
||||
indicates the combination of these attributes. <br>
|
||||
Its <code>::value</code> is of enumeration type <A HREF="#ncm"><CODE>boost::numeric::int_float_mixture_enum</CODE></A>
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<H2><A NAME="sm"><CODE>template class sign_mixture<></CODE></A></H2>
|
||||
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
template <class T, class S>
|
||||
struct sign_mixture : mpl::integral_c<sign_mixture_enum, <i>impl-def-value</i>> {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
</PRE>
|
||||
<p>Classifying <code>S</code> and <code>T</code> as either <code>signed</code>
|
||||
or <code>unsigned</code>, this <a href="../../../mpl/doc/ref/Integral_Constant.html">MPL's Integral Constant</a>
|
||||
indicates the combination of these attributes. <br>
|
||||
Its <code>::value</code> is of enumeration type <A HREF="#ncm"><CODE>boost::numeric::sign_mixture_enum</CODE></A>
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<H2><A NAME="ubm"><CODE>template class udt_builtin_mixture<></CODE></A></H2>
|
||||
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
template <class T, class S>
|
||||
struct udt_builtin_mixture : mpl::integral_c<udt_builtin__mixture_enum, <i>impl-def-value</i>> {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
</PRE>
|
||||
<p>Classifying <code>S</code> and <code>T</code> as either <code>user-defined</code>
|
||||
or <code>builtin</code>, this <a href="../../../mpl/doc/ref/Integral_Constant.html">MPL's Integral Constant</a>
|
||||
indicates the combination of these attributes. <br>
|
||||
Its <code>::value</code> is of enumeration type <A HREF="#ncm"><CODE>boost::numeric::udt_builtin_mixture_enum</CODE></A>
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<H2><A NAME="isr"><CODE>template class is_subranged<></CODE></A></H2>
|
||||
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
template <class T, class S>
|
||||
struct is_subranged : mpl::bool_<<i>impl-def-value</i>> {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
</PRE>
|
||||
<p>Indicates if the range of the target type T is a subset of the range of the source type S.
|
||||
That is: if there are some source values which fall out of the Target type's range.<br>
|
||||
It is a boolean <a href="../../../mpl/doc/ref/Integral_Constant.html">MPL's Integral Constant</a>..<br>
|
||||
It does not indicate if
|
||||
a <i>particular</i> conversion is effectively out of range; it indicates that
|
||||
some conversion <i>might be</i> out of range because not all the source values
|
||||
are representable as Target type.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<H2><A NAME="nct"><CODE>template class numeric_conversion_traits<></CODE></A></H2>
|
||||
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
|
||||
template <class T, class S>
|
||||
struct numeric_conversion_traits
|
||||
{
|
||||
mpl::integral_c<int_float_mixture_enum , ...> int_float_mixture ;
|
||||
mpl::integral_c<sign_mixture_enum , ...> sign_mixture;
|
||||
mpl::integral_c<udt_builtin_mixture_enum, ...> udt_builtin_mixture ;
|
||||
|
||||
mpl::bool_<...> subranged ;
|
||||
mpl::bool_<...> trivial ;
|
||||
|
||||
typedef ... target_type ;
|
||||
typedef ... source_type ;
|
||||
typedef ... argument_type ;
|
||||
typedef ... result_type ;
|
||||
typedef ... supertype ;
|
||||
typedef ... subtype ;
|
||||
} ;
|
||||
|
||||
} } // namespace numeric, namespace boost
|
||||
</PRE>
|
||||
<BLOCKQUOTE>
|
||||
|
||||
<P>This traits class indicates some properties of a <i>numeric conversion direction</i>:
|
||||
from a source type to a target type. It does not indicate the properties of
|
||||
a <i>specific</i> conversion, but of the conversion <i>direction</i>. See
|
||||
<A href="definitions.html#subranged">Definitions</A> for details.<br>
|
||||
</P>
|
||||
|
||||
<P>The traits class provides the following
|
||||
<a href="../../../mpl/doc/ref/Integral_Constant.html">MPL's Integral Constants</a>
|
||||
of enumeration type. They express the <i>combination</i> of certain attributes of the Source and
|
||||
Target types (thus they are call <i>mixture</i>):</P>
|
||||
<TABLE BORDER="1">
|
||||
<TR>
|
||||
<TD> <CODE><B>int_float_mixture</B></CODE> </TD>
|
||||
|
||||
<TD>
|
||||
<P>Same as given by the traits class <A HREF="#ifm"><CODE>int_float_mixture</CODE></A></P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <CODE><B>sign_mixture</B></CODE> </TD>
|
||||
|
||||
<TD>
|
||||
<P>Same as given by the traits class <A HREF="#sm"><CODE>sign_mixture</CODE></A></P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <CODE><B>udt_builtin_mixture</B></CODE> </TD>
|
||||
|
||||
<TD>
|
||||
<P>Same as given by the traits class <A HREF="#ubm"><CODE>udt_builtin_mixture</CODE></A></P>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<P>The traits class provides the following
|
||||
<a href="../../../mpl/doc/ref/Integral_Constant.html">MPL's Integral Constants</a>
|
||||
of boolean type which indicates indirectly the relation between the Source and Target
|
||||
<i>ranges</i>
|
||||
(see <A href="definitions.html#range">Definitions</A> for details).</P>
|
||||
<TABLE BORDER="1">
|
||||
<TR>
|
||||
<TD> <CODE> <B>subranged</B></CODE> </TD>
|
||||
|
||||
<TD>
|
||||
<P>Same as given by <A HREF="#isr"><CODE>is_subranged</CODE></A></P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <CODE> <B>trivial</B></CODE> </TD>
|
||||
|
||||
<TD>
|
||||
<P>Indicates if both Source and Target, <u>without cv-qualifications</u>, are
|
||||
the same type.<br>
|
||||
Its <code>::value</code> is of boolean type.</P>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<P>The traits class provides the following types. They are the Source and Target
|
||||
types classified and qualified for different purposes.</P>
|
||||
|
||||
<TABLE BORDER="1" width="720">
|
||||
<TR>
|
||||
<TD> <CODE><B>target_type</B></CODE> </TD>
|
||||
<TD>
|
||||
|
||||
<P>The template parameter <CODE>T</CODE><EM> without cv-qualifications</EM></P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <CODE><B>source_type</B></CODE> </TD>
|
||||
<TD>
|
||||
|
||||
<P>The template parameter <CODE>S</CODE><EM> without cv-qualifications</EM></P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <CODE><B>argument_type</B></CODE> </TD>
|
||||
<TD>
|
||||
<P>This type is either <CODE>source_type</CODE> or <CODE>source_type
|
||||
const&</CODE>. <BR> It represents the <I>optimal</I> argument type for the
|
||||
<A HREF="converter.html">converter</A> member functions.<BR>
|
||||
If <CODE>S</CODE> is a built-in type, this is <CODE>source_type</CODE>,
|
||||
otherwise, this is <CODE>source_type const&</CODE>. </P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <CODE><B>result_type</B></CODE></TD>
|
||||
<TD>
|
||||
<P>This type is either <CODE>target_type</CODE> or <CODE>target_type
|
||||
const&</CODE> <BR> It represents the return type of the
|
||||
<A HREF="converter.html">converter</A> member functions.<BR>
|
||||
If <CODE>T==S</CODE>, it is <CODE>target_type const&</CODE>, otherwise,
|
||||
it is <CODE>target_type</CODE>.</P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
|
||||
<TD height="37"> <CODE><B>supertype</B></CODE></TD>
|
||||
|
||||
<TD height="37">
|
||||
<P>If the conversion is <CODE>subranged</CODE>, it is <CODE>source_type</CODE>,
|
||||
otherwise, it is <CODE>target_type</CODE></P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <CODE><B>subtype</B></CODE></TD>
|
||||
<TD height="37">
|
||||
<P>If the conversion is <CODE>subranged</CODE>, it is <CODE>target_type</CODE>,
|
||||
otherwise, it is <CODE>source_type</CODE></P>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE> </BLOCKQUOTE> <HR>
|
||||
|
||||
<H2><A NAME="examples">Examples</A></H2>
|
||||
<BLOCKQUOTE>
|
||||
<PRE>#include <boost/numeric/conversion_traits.hpp>
|
||||
|
||||
int main() {
|
||||
|
||||
// A trivial conversion.
|
||||
typedef boost::numeric::conversion_traits<short,short> Short2Short_Traits ;
|
||||
assert ( Short2Short_Traits::trivial::value ) ;
|
||||
|
||||
// A subranged conversion.
|
||||
typedef boost::numeric::conversion_traits<double,unsigned int> UInt2Double_Traits ;
|
||||
assert ( UInt2Double_Traits::mixture::value == boost::numeric::integral_to_float ) ;
|
||||
assert ( UInt2Double_Traits::sign_mixture::value == boost::numeric::unsigned_to_signed ) ;
|
||||
assert ( !UInt2Double_Traits::subranged::value ) ;
|
||||
assert ( typeid(UInt2Double_Traits::supertype) == typeid(double) ) ;
|
||||
assert ( typeid(UInt2Double_Traits::subtype) == typeid(unsigned int) ) ;
|
||||
|
||||
// A doubly subranged conversion.
|
||||
assert ( boost::numeric::conversion_traits<short, unsigned short>::subranged::value
|
||||
&& boost::numeric::conversion_traits<unsigned short, short>::subranged::value
|
||||
)
|
||||
|
||||
return 0;
|
||||
}</PRE>
|
||||
</BLOCKQUOTE>
|
||||
<HR>
|
||||
<P>Back to <A HREF="index.html">Numeric Conversion library index</A></P>
|
||||
<HR>
|
||||
<P>Revised 23 June 2004</P>
|
||||
<p>© Copyright Fernando Luis Cacciola Carballal, 2000-2004</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -0,0 +1,268 @@
|
||||
<HTML>
|
||||
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../boost.css">
|
||||
<TITLE>Boost Numeric Conversion Library - Policy-based Converter</TITLE>
|
||||
</HEAD>
|
||||
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000ff" VLINK="#800080">
|
||||
<TABLE BORDER="0" CELLPADDING="7" CELLSPACING="0" WIDTH="100%"
|
||||
SUMMARY="header">
|
||||
<TR>
|
||||
<TD VALIGN="top" WIDTH="300"> <H3><A HREF="http://www.boost.org"><IMG
|
||||
HEIGHT="86" WIDTH="277" ALT="C++ Boost" SRC="../../../../c++boost.gif"
|
||||
BORDER="0"></A> </H3>
|
||||
</TD>
|
||||
<TD VALIGN="top"> <H1 ALIGN="center">Boost Numeric Conversion Library</H1>
|
||||
<H1><A HREF="http://www.boost.org">Header </A><A
|
||||
HREF="../../../../boost/numeric/converter.hpp">boost/numeric/converter.hpp</A></H1>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<HR>
|
||||
<H2>Contents</H2>
|
||||
<DT><A HREF="#synposis">Synopsis</A></DT>
|
||||
<DT><A HREF="udt_support.html">User Defined Types support</A></DT>
|
||||
<DT><A HREF="#rchklogic">Range Checking Logic</A></DT>
|
||||
<DT><A HREF="#examples">Examples</A></DT>
|
||||
|
||||
<HR>
|
||||
<H2><A NAME="synopsis">Synopsis</A></H2>
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
|
||||
template<class T,
|
||||
class S,
|
||||
class Traits, = conversion_traits<T,S>
|
||||
class OverflowHandler = def_overflow_handler,
|
||||
class Float2IntRounder = Trunc< typename Traits::source_type >,
|
||||
class RawConverter = raw_converter<Traits>,
|
||||
class UserRangeChecker = UseInternalRangeChecker
|
||||
>
|
||||
struct converter
|
||||
{
|
||||
typedef Traits traits ;
|
||||
|
||||
typedef typename Traits::source_type source_type ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
typedef typename Traits::result_type result_type ;
|
||||
|
||||
static result_type convert ( argument_type s ) ;
|
||||
|
||||
result_type operator() ( argument_type s ) const ;
|
||||
|
||||
// Internal member functions:
|
||||
|
||||
static range_check_result out_of_range ( argument_type s ) ;
|
||||
static void validate_range ( argument_type s ) ;
|
||||
static result_type low_level_convert ( argument_type s ) ;
|
||||
static source_type nearbyint ( argument_type s ) ;
|
||||
|
||||
} ;
|
||||
|
||||
} } // namespace numeric, boost
|
||||
</PRE>
|
||||
|
||||
<P><code>boost::numeric::converter<></code> is a
|
||||
<a href="http://www.sgi.com/tech/stl/UnaryFunction.html">Unary Function Object</a>
|
||||
encapsulating the code to perform a numeric conversion with the direction and properties specified
|
||||
by the <CODE>Traits</CODE> template parameter. It can optionally take some
|
||||
<A HREF="converter_policies.html">policies</a>
|
||||
which can be used to customize its behavior. The Traits parameter is not a policy but
|
||||
the parameter that defines the conversion.
|
||||
</P>
|
||||
<hr>
|
||||
<h2>Template parameters:</h2>
|
||||
<TABLE BORDER="1">
|
||||
<TR>
|
||||
<TD> <CODE>Traits</CODE> </TD>
|
||||
<TD> This must be a conversion traits class with the interface of
|
||||
<A HREF="conversion_traits.html">boost::numeric::conversion_traits</A>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <A HREF="converter_policies.html#oh"><CODE>OverflowHandler</CODE></A> </TD>
|
||||
<TD> <B>Stateless Policy</B> called to administrate the result of the
|
||||
range checking.<br>
|
||||
It is a <b>Function Object</b> which receives the result of <CODE>out_of_range()</CODE>
|
||||
and is called inside the <CODE>validate_range()</CODE> static member function
|
||||
exposed by the converter.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <A HREF="converter_policies.html#f2i"><CODE>Float2IntRounder</CODE></A> </TD>
|
||||
<TD> <B>Stateless Policy</B> which specifies the rounding mode used for
|
||||
float to integral conversions.<br>
|
||||
It supplies the <CODE>nearbyint()</CODE> static member function exposed
|
||||
by the converter.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <A HREF="converter_policies.html#rawc"><CODE>RawConverter</CODE></A> </TD>
|
||||
<TD> <B>Stateless Policy</B> which is used to perform the actual conversion.
|
||||
<br>
|
||||
It supplies the<CODE> low_level_convert()</CODE> static member function
|
||||
exposed by the converter.</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD> <A HREF="converter_policies.html#rangecheck"><CODE>UserRangeChecker</CODE></A> </TD>
|
||||
<TD><i>Special and Optional</i> <b>Stateless Policy</b> which can be used to override
|
||||
the internal range checking logic.<br>
|
||||
If given, supplies alternative code for the out_of_range() and validate_range()
|
||||
static member functions exposed by the converter.</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<br>
|
||||
<hr>
|
||||
<h2>Member functions:</h2>
|
||||
<P><CODE>static result_type converter<>::convert ( argument_type s ) ; //
|
||||
throw</CODE></P>
|
||||
<BLOCKQUOTE>
|
||||
<P>This static member function converts an rvalue of type source_type to an rvalue
|
||||
of type target_type.<BR>
|
||||
If the conversion requires it, it performs a range checking before the conversion
|
||||
and passes the result of the check to the overflow handler policy (the default
|
||||
policy throws an exception if out-of-range is detected)<BR>
|
||||
The implementation of this function is actually built from the policies and
|
||||
is basically as follows:</P>
|
||||
<PRE> result_type converter<>::convert ( argument_type s )
|
||||
{
|
||||
validate_range(s); // Implemented by the internal range checking logic
|
||||
// (which also calls the OverflowHandler policy)
|
||||
// or externally supplied by the UserRangeChecker policy.
|
||||
|
||||
s = nearbyint(s); // Externally supplied by the Float2IntRounder policy.
|
||||
// NOTE: This is actually called only for float to int conversions.
|
||||
|
||||
return low_level_convert(s); // Externally supplied by the RawConverter policy.
|
||||
}
|
||||
</PRE>
|
||||
|
||||
<P>"converter<>::operator() const" just calls <CODE>convert()</CODE></P>
|
||||
</BLOCKQUOTE>
|
||||
<P><CODE>static range_check_result numeric_converter<>::out_of_range (
|
||||
argument_type s ) ;</CODE></P>
|
||||
<BLOCKQUOTE>
|
||||
<P>This <A HREF="#int">internal</A> static member function determines if the
|
||||
value 's' can be represented by the target type without overflow. <BR>
|
||||
It does not determine if the conversion is <EM>exact</EM>; that is, it does
|
||||
not detect <i>inexact</i> conversions, only <i>out-of-range</i> conversions
|
||||
(see the <a href="definitions.html#roundoff">Definitions</a> for further details).<BR>
|
||||
The return value is of enum type
|
||||
<A HREF="converter_policies.html#rcr"><CODE>boost::numeric::range_check_result</CODE></A><BR>
|
||||
The actual code for the range checking logic is optimized for the combined
|
||||
properties of the source and target types. For example, a non-subranged conversion
|
||||
(i.e: int->float), requires no range checking, so out_of_range() returns
|
||||
cInRange directly. See the following <A HREF="#rchklogic">table</A> for more
|
||||
details.<br>
|
||||
If the user supplied a <a href="converter_policies.html#rangecheck">UserRangeChecker</a>
|
||||
policy, is this policy which implements this function, so the implementation
|
||||
is user defined, although it is expected to perform the same conceptual check
|
||||
and return the appropriate result.</P>
|
||||
</BLOCKQUOTE>
|
||||
<P><CODE>static void numeric_converter<>::validate_range ( argument_type
|
||||
s ) ; // no throw</CODE></P>
|
||||
<BLOCKQUOTE>
|
||||
<P>This <A HREF="#int">internal</A> static member function calls <CODE>out_of_range(s)</CODE>,
|
||||
and passes the result to the <A
|
||||
HREF="converter_policies.html#oh"><CODE>OverflowHandler</CODE></A> policy class
|
||||
<BR>
|
||||
For those Target/Source combinations which don't require range checking, this
|
||||
is an <U>empty inline function</U>.<br>
|
||||
If the user supplied a <a href="converter_policies.html#rangecheck">UserRangeChecker</a>
|
||||
policy, is this policy which implements this function, so the implementation
|
||||
is user defined, although it is expected to perform the same action as the
|
||||
default. In particular, it is expected to pass the result of the check to
|
||||
the overflow handler.</P>
|
||||
</BLOCKQUOTE>
|
||||
<P><CODE>static result_type numeric_converter<>::low_level_convert (
|
||||
argument_type s ) ;</CODE></P>
|
||||
<BLOCKQUOTE>
|
||||
<P>This <A HREF="#int">internal</A> static member function performs the actual
|
||||
conversion.<BR>
|
||||
This function is externally supplied by the <A
|
||||
HREF="converter_policies.html#rawc"><CODE>RawConverter</CODE></A> policy class.</P>
|
||||
</BLOCKQUOTE>
|
||||
<P><CODE>static source_type converter<>::nearbyint (
|
||||
argument_type s ) ;</CODE></P>
|
||||
<BLOCKQUOTE>
|
||||
<P>This <A HREF="#int">internal</A> static member function, which is <U>only
|
||||
used</U> for float to int conversions, returns an <I>integer value of <U>floating-point
|
||||
type</U></I> according to some rounding direction. <BR>
|
||||
This function is externally supplied by the <A
|
||||
HREF="converter_policies.html#f2i"><CODE>Float2IntRounder</CODE></A> policy class
|
||||
which encapsulates the specific rounding mode.</P>
|
||||
</BLOCKQUOTE>
|
||||
<hr>
|
||||
<P><A NAME="int"><B>Internal Member Functions</B>:</A> These static member functions
|
||||
build the actual conversion code used by <CODE>convert()</CODE>. The user does
|
||||
not have to call these if calling convert(), since convert() calls them infernally,
|
||||
but they can be called separately for specific needs.</P>
|
||||
<hr>
|
||||
<H2><A NAME="rchklogic">Range Checking Logic</A></H2>
|
||||
<P>The Following table summarizes the internal range checking logic performed
|
||||
for each combination of the properties of Source and Target.<br>
|
||||
LowestT/HighestT denotes the highest and lowest values of the Target type, respectively.<br>
|
||||
S(n) is short for "static_cast<S>(n)" (S denotes the Source
|
||||
type).<br>
|
||||
"NONE" indicates that for this case there is no range checking.</P>
|
||||
<Pre> int_to_int |--> sig_to_sig |--> subranged |--> ( s >= S(LowestT) ) && ( s <= S(HighestT) )
|
||||
| |--> not subranged |--> NONE
|
||||
|
|
||||
|--> unsig_to_unsig |--> subranged |--> ( s >= S(LowestT) ) && ( s <= S(HighestT) )
|
||||
| |--> not subranged |--> NONE
|
||||
|
|
||||
|--> sig_to_unsig |--> pos subranged |--> ( s >= S(0) ) && ( s <= S(HighestT) )
|
||||
| |--> not pos subranged |--> ( s >= S(0) )
|
||||
|
|
||||
|--> unsig_to_sig |--> subranged |--> ( s <= S(HighestT) )
|
||||
| |--> not subranged |--> NONE
|
||||
|
||||
int_to_float |--> NONE
|
||||
|
||||
float_to_int |--> round_to_zero |--> ( s > S(LowestT)-S(1) ) && ( s < S(HighestT)+S(1) )
|
||||
|--> round_to_even_nearest |--> ( s >= S(LowestT)-S(0.5) ) && ( s < S(HighestT)+S(0.5) )
|
||||
|--> round_to_infinity |--> ( s > S(LowestT)-S(1) ) && ( s <= S(HighestT) )
|
||||
|--> round_to_neg_infinity |--> ( s >= S(LowestT) ) && ( s < S(HighestT)+S(1) )
|
||||
|
||||
float_to_float |--> subranged |--> ( s >= S(LowestT) ) && ( s <= S(HighestT) )
|
||||
|--> not subranged |--> NONE
|
||||
|
||||
</Pre>
|
||||
<HR>
|
||||
<H2><A NAME="examples">Examples</A></H2>
|
||||
<BLOCKQUOTE>
|
||||
<PRE>#include <boost/numeric/conversion/converter.hpp>
|
||||
|
||||
int main() {
|
||||
|
||||
typedef boost::numeric::converter<int,doublegt; Double2Int ;
|
||||
|
||||
int x = Double2Int::convert(2.0);
|
||||
assert ( x == 2 );
|
||||
|
||||
int y = Double2Int()(3.14); // As a function object.
|
||||
assert ( y == 3 ) ; // The default rounding is trunc.
|
||||
|
||||
try
|
||||
{
|
||||
double m = boost::numeric::bounds<double>::highest();
|
||||
int z = Double2Int::convert(m); // By default throws positive_overflow()
|
||||
}
|
||||
catch ( boost::numeric::positive_overflow const& )
|
||||
{
|
||||
}
|
||||
|
||||
return 0;
|
||||
}</PRE>
|
||||
</BLOCKQUOTE>
|
||||
<HR>
|
||||
<P>Back to <A HREF="index.html">Numeric Conversion library index</A></P>
|
||||
<HR>
|
||||
<P>Revised 23 June 2004</P>
|
||||
<p>© Copyright Fernando Luis Cacciola Carballal, 2000-2004</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -0,0 +1,306 @@
|
||||
<HTML>
|
||||
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../boost.css">
|
||||
<TITLE>Boost Numeric Conversion Library - Converter Policies</TITLE>
|
||||
</HEAD>
|
||||
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000ff" VLINK="#800080">
|
||||
<TABLE BORDER="0" CELLPADDING="7" CELLSPACING="0" WIDTH="100%"
|
||||
SUMMARY="header">
|
||||
<TR>
|
||||
<TD VALIGN="top" WIDTH="300"> <H3><A HREF="http://www.boost.org"><IMG
|
||||
HEIGHT="86" WIDTH="277" ALT="C++ Boost" SRC="../../../../c++boost.gif"
|
||||
BORDER="0"></A> </H3>
|
||||
</TD>
|
||||
<TD VALIGN="top"> <H1 ALIGN="center">Boost Numeric Conversion Library</H1>
|
||||
<H1><A HREF="http://www.boost.org">Header </A><A
|
||||
HREF="../../../../boost/numeric/converter_policies.hpp">boost/numeric/converter_policies.hpp</A></H1>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<HR>
|
||||
<H2>Contents</H2>
|
||||
<ol>
|
||||
<LI><A HREF="#rcr"><CODE>enumeration range_check_result</CODE></A> </LI>
|
||||
<LI><A HREF="#oh"><CODE>Policy OverflowHandler</CODE></A>
|
||||
<UL>
|
||||
<LI>class <A HREF="#oh_silent"><CODE>silent_overflow_handler</CODE></A></LI>
|
||||
<LI>class <A HREF="#oh_def"><CODE>def_overflow_handler</CODE></A> (Default Policy)</LI>
|
||||
<ul>
|
||||
<LI>class <A HREF="#bad_numc"><CODE>bad_numeric_conversion</CODE></A></LI>
|
||||
<LI>class <A HREF="#negovr"><CODE>negative_overflow</CODE></A></LI>
|
||||
<LI>class <A HREF="#posovr"><CODE>positive_overflow</CODE></A></LI>
|
||||
</ul>
|
||||
</UL>
|
||||
</LI>
|
||||
<LI><A HREF="#f2i"><CODE>Policy FloatToIntRounder</CODE></A> <UL>
|
||||
<LI>class <A HREF="#trunc"><CODE>Trunc<T></CODE></A> (Default Policy)</LI>
|
||||
<LI>class <A HREF="#round"><CODE>RoundEven<T></CODE></A></LI>
|
||||
<LI>class <A HREF="#ceil"><CODE>Ceil<T></CODE></A></LI>
|
||||
<LI>class <A HREF="#floor"><CODE>Floor<T></CODE></A></LI>
|
||||
</UL>
|
||||
</LI>
|
||||
<LI><A HREF="#rawc"><CODE>Policy RawConverter</CODE></A><UL>
|
||||
<LI>class <A HREF="#rawnumc"><CODE>raw_converter class</CODE></A> (Default)</LI>
|
||||
</UL>
|
||||
</LI>
|
||||
<LI><A HREF="#rc"><CODE>Policy UserRangeChecker</CODE></A><UL>
|
||||
<LI>class <A HREF="#int_rc"><CODE>UseInternalRangeChecker class</CODE></A> (Default)</LI>
|
||||
</UL>
|
||||
</LI>
|
||||
</ol>
|
||||
|
||||
<HR>
|
||||
<H2><A NAME="types">Types</A></H2>
|
||||
<H2><A NAME="rcr"><CODE>enum range_check_result</CODE></A></H2>
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
|
||||
enum range_check_result
|
||||
{
|
||||
cInRange ,
|
||||
cNegOverflow ,
|
||||
cPosOverflow
|
||||
} ;
|
||||
|
||||
|
||||
} }</PRE>
|
||||
|
||||
<P>Defines the values returned by <CODE>boost::numeric::converter<>::out_of_range()</CODE>
|
||||
</P>
|
||||
<HR>
|
||||
<H2><A NAME="oh">Policy <CODE>OverflowHandler</CODE></A></H2>
|
||||
<P>This <EM>stateless</EM> non-template policy class must be a <I>function object</I>
|
||||
and is called to administrate the result of the range checking. It can throw
|
||||
an exception if overflow has been detected by the range checking as indicated
|
||||
by its argument. If it throws, is is recommended that it be <CODE>std::bad_cast</CODE>
|
||||
or derived.</P>
|
||||
<P>It must have the following interface (it does not has to be a template class):</P>
|
||||
<PRE> struct YourOverflowHandlerPolicy
|
||||
{
|
||||
void operator() ( boost::range_check_result ) ; // throw bad_cast or derived
|
||||
} ;
|
||||
</PRE>
|
||||
<P>It is called with the result of the converter's <CODE>out_of_range()</CODE>
|
||||
inside <CODE>validate_range()</CODE>.</P>
|
||||
<P>These are the two overflow handler classes provided by the
|
||||
library:</P>
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
|
||||
struct <A NAME="oh_def">def_overflow_handler</a>
|
||||
{
|
||||
void operator() ( range_check_result r ) // throw bad_numeric_conversion derived
|
||||
{
|
||||
if ( r == cNegOverflow )
|
||||
throw negative_overflow() ;
|
||||
else if ( r == cPosOverflow )
|
||||
throw positive_overflow() ;
|
||||
}
|
||||
} ;
|
||||
|
||||
struct <A NAME="oh_silent">silent_overflow_handler</a>
|
||||
{
|
||||
void operator() ( range_check_result ) // no-throw
|
||||
{}
|
||||
} ;
|
||||
|
||||
} }
|
||||
</PRE>
|
||||
|
||||
<P>And these are the Exception Classes thrown by the default
|
||||
overflow handler</P>
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
|
||||
class <a name="bad_numc">bad_numeric_conversion</a> : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char *what() const // throw()
|
||||
{ return "bad numeric conversion: overflow"; }
|
||||
};
|
||||
|
||||
class <a name="negovr">negative_overflow</a> : public bad_numeric_conversion
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char *what() const // throw()
|
||||
{ return "bad numeric conversion: negative overflow"; }
|
||||
};
|
||||
class <a name="posovr">positive_overflow</a> : public bad_numeric_conversion
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char *what() const // throw()
|
||||
{ return "bad numeric conversion: positive overflow"; }
|
||||
};
|
||||
} }
|
||||
</PRE>
|
||||
|
||||
<HR>
|
||||
<H2><A NAME="f2i">Policy <CODE>FloatToIntRounder</CODE></A></H2>
|
||||
<P>This <EM>stateless</EM> template policy class specifies the rounding mode used
|
||||
for<U> float to integral</U> conversions. It supplies the <CODE>"nearbyint()"</CODE>
|
||||
static member function exposed by the converter, which means that it <U>publicly
|
||||
inherits from this policy.</U></P>
|
||||
<P>The policy must have the following interface:</P>
|
||||
<PRE> template<class S>
|
||||
struct YourFloat2IntRounderPolicy
|
||||
{
|
||||
typedef S source_type ;
|
||||
typedef <I>{S or S const&}</I> argument_type ;
|
||||
|
||||
static source_type nearbyint ( argument_type s ) { ... }
|
||||
|
||||
typedef mpl::integral_c<std::float_round_style,std::<i>round_...</i>> round_style ;
|
||||
} ;
|
||||
</PRE>
|
||||
|
||||
<P>These are the rounder classes provided by the library:</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><EM>NOTE: These classes are not intended to be general purpose rounding functions
|
||||
but specific policies for converter<>. This is why <U>they are not function
|
||||
objects</U>.</EM></P>
|
||||
<P>(only the specific parts are shown, see the general policy form above)</P>
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
<A NAME="trunc"></A>template<class S>
|
||||
struct Trunc
|
||||
{
|
||||
static source_type nearbyint ( argument_type s )
|
||||
{
|
||||
using std::floor ;
|
||||
using std::ceil ;
|
||||
return s >= static_cast<S>(0) ? floor(s) : ceil(s) ;
|
||||
}
|
||||
|
||||
typedef mpl::integral_c<std::float_round_style,std::round_toward_zero> round_style ;
|
||||
} ;
|
||||
</PRE>
|
||||
<PRE> <A NAME="round"></A>template<class S>
|
||||
struct RoundEven
|
||||
{
|
||||
static source_type nearbyint ( argument_type s )
|
||||
{
|
||||
return <i>impl-defined-value</i> ;
|
||||
}
|
||||
|
||||
typedef mpl::integral_c<std::float_round_style,std::round_to_nearest> round_style ;
|
||||
} ;
|
||||
</PRE>
|
||||
<PRE> <A NAME="ceil"></A>template<class S>
|
||||
struct Ceil
|
||||
{
|
||||
static source_type nearbyint ( argument_type s )
|
||||
{<br> using std::ceil ;<br> return ceil(s) ;<br> }
|
||||
|
||||
typedef mpl::integral_c<std::float_round_style,std::round_toward_infinity> round_style ;
|
||||
} ;
|
||||
</PRE>
|
||||
<PRE> <A NAME="floor"></A>template<class S>
|
||||
struct Floor
|
||||
{
|
||||
static source_type nearbyint ( argument_type s )
|
||||
{<br> using std::floor ;<br> return floor(s) ;<br> }
|
||||
|
||||
typedef mpl::integral_c<std::float_round_style,std::round_toward_neg_infinity> round_style ;
|
||||
} ;
|
||||
|
||||
} } // namespace numeric, namespace boost</PRE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<H3>Math Functions used by the rounder policies</H3>
|
||||
<P>The rounder policies supplied by this header use math functions floor() and
|
||||
ceil(). The standard versions of these functions are introduced in context by
|
||||
a using directive, so in normal conditions, the standard functions will be used.
|
||||
<br>
|
||||
However, if there are other visible corresponding overloads an ambiguity could
|
||||
arise. In this case, the user can supply her own rounder policy which could,
|
||||
for instance, use a fully qualified call.<br>
|
||||
This technique allows the default rounder policies to be used directly with
|
||||
user defined types. The user only requires that suitable overloads of floor()
|
||||
and ceil() be visible. See also <a HREF="udt_support.html">User Defined Numeric Types support</a><br>
|
||||
</P>
|
||||
<HR>
|
||||
<H2><A NAME="rawc">Policy <CODE>RawConverter</CODE></A></H2>
|
||||
<P>This <EM>stateless</EM> template policy class is used to perform the actual
|
||||
conversion from Source to Target. It supplies the <CODE>"low_level_convert()"</CODE>
|
||||
static member function exposed by the converter, which means that it <U>publicly
|
||||
inherits from this policy.</U></P>
|
||||
<P>The policy must have the following interface:</P>
|
||||
<PRE> template<class Traits>
|
||||
struct YourRawConverterPolicy
|
||||
{
|
||||
typedef typename Traits::result_type result_type ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static result_type low_level_convert ( argument_type s ) { return <I><impl defined></I> ; }
|
||||
} ;
|
||||
</PRE>
|
||||
|
||||
<P>This policy is mostly provided as a hook for user defined types which don't
|
||||
support <CODE>static_cast<></CODE> conversions to some types</P>
|
||||
|
||||
<P>This is the only raw converter policy class provided
|
||||
by the library:</P>
|
||||
<PRE>namespace boost { namespace numeric {
|
||||
|
||||
|
||||
template<class Traits>
|
||||
struct <A NAME="rawnumc">raw_numeric_converter</A>
|
||||
{
|
||||
typedef typename Traits::result_type result_type ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static result_type low_level_convert ( argument_type s )
|
||||
{ return static_cast<result_type>(s) ; }
|
||||
} ;
|
||||
|
||||
}
|
||||
</PRE>
|
||||
|
||||
<HR>
|
||||
<H2><A NAME="rc">Policy <CODE>UserRangeChecker</CODE></A></H2>
|
||||
<P>This <EM>stateless</EM> template policy class is used -<u>only if supplied</u>-
|
||||
to <b>override</b> the internal range checking logic.<br>
|
||||
It supplies the <CODE>"validate_range()"</CODE> static member function
|
||||
exposed by the converter, which means that it <U>publicly inherits from this
|
||||
policy.</U></P>
|
||||
<P>The policy must have the following interface:</P>
|
||||
<PRE> template<class Traits>
|
||||
struct YourRangeCheckerPolicy
|
||||
{
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
// Determines if the value 's' fits in the range of the Target type.
|
||||
static range_check_result out_of_range ( argument_type s ) ;
|
||||
|
||||
// Checks whether the value 's' is out_of_range()
|
||||
// and passes the result of the check to the OverflowHandler policy.
|
||||
static void validate_range ( argument_type s )
|
||||
{
|
||||
OverflowHandler()( out_of_range(s) ) ;
|
||||
}
|
||||
} ;
|
||||
</PRE>
|
||||
<P>This policy is <b>only</b> provided as a hook for user defined types which
|
||||
require range checking (which is disabled by default when a UDT is involved).<br>
|
||||
The library provides a class: <A NAME="int_rc"><code>UseInternalRangeChecker{};</code></a> which
|
||||
is a <i>fake</i> RangeChecker policy used to signal the converter to use its
|
||||
internal range checking implementation.
|
||||
</P>
|
||||
<HR>
|
||||
<P>Back to <A HREF="index.html">Numeric Conversion library index</A></P>
|
||||
<HR>
|
||||
<P>Revised 23 June 2004</P>
|
||||
<p>© Copyright Fernando Luis Cacciola Carballal, 2000-2004</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -0,0 +1,471 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../boost.css">
|
||||
<TITLE>Boost Numeric Conversion Library - Definitions</TITLE>
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000ff" VLINK="#800080">
|
||||
<TABLE BORDER="0" CELLPADDING="7" CELLSPACING="0" WIDTH="100%"
|
||||
SUMMARY="header">
|
||||
<TR>
|
||||
<TH VALIGN="top" WIDTH="300">
|
||||
<H3><A HREF="../../../../index.htm"><IMG HEIGHT="86" WIDTH="277"
|
||||
ALT="C++ Boost" SRC="../../../../c++boost.gif" BORDER="0"></A></H3> </TH>
|
||||
<TH VALIGN="top">
|
||||
<H1 ALIGN="center">Boost Numeric Conversion Library</H1>
|
||||
<H1 ALIGN="center">Definitions</H1>
|
||||
</TH>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<HR>
|
||||
<H2>Contents</H2>
|
||||
<DL CLASS="page-index">
|
||||
<dt><A HREF="#intro">Introduction</A></dt>
|
||||
<dt><A HREF="#typeval">Types and Values</A></dt>
|
||||
<dt><A HREF="#stdtypes">C++ Arithmetic Types</A></dt>
|
||||
<dt><A HREF="#numtypes">Numeric Types</A></dt>
|
||||
<dt><A HREF="#range">Range and Precision</A></dt>
|
||||
<dt><A HREF="#roundoff">Exact, Correctly Rounded and Out-Of-Range Representations</A></dt>
|
||||
<dt><A HREF="#stdconv">Standard (numeric) Conversions</A></dt>
|
||||
<dt><A HREF="#subranged">Subranged Conversion Direction, Subtype and Supertype</A></dt>
|
||||
</DL>
|
||||
|
||||
|
||||
|
||||
<h2><A NAME="intro">Introduction</A></h2>
|
||||
<P>This section provides definitions of terms used in the Numeric Conversion library.</p>
|
||||
<p><b>Notation:</b>
|
||||
<li><u>underlined text</u> denotes terms defined in the C++ standard.</li>
|
||||
<li><b>bold face</b> denotes terms defined here but not in the standard.</li>
|
||||
<p></p>
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<h2><A NAME="typeval">Types and Values</A></h2>
|
||||
<p>As defined by the <u>C++ Object Model</u> (§1.7) the <u>storage</u> or
|
||||
memory on which a C++ program runs is a contiguous sequence of <u>bytes</u>
|
||||
where each byte is a contiguous sequence of <u>bits</u>.<br>
|
||||
An <u>object</u> is a region of storage (§1.8) and has a type (§3.9).<br>
|
||||
A <u>type</u> is a discrete set of values. <br>
|
||||
An object of type T has an <u>object representation</u> which is the sequence
|
||||
of bytes stored in the object (§3.9/4)<br>
|
||||
An object of type T has a <u>value representation</u> which is the set of bits
|
||||
that determine the <i>value</i> of an object of that type (§3.9/4). For
|
||||
<u>POD</u> types (§3.9/10), this bitset is given by the object representation,
|
||||
but not all the bits in the storage need to participate in the value representation
|
||||
(except for character types): for example, some bits might be used for padding
|
||||
or there may be trap-bits.</p>
|
||||
<p>The <b>typed value</b> that is held by an object is
|
||||
the value which is determined by its value representation.<br>
|
||||
An <b>abstract value</b> (untyped) is
|
||||
the conceptual information that is represented in a type
|
||||
(i.e. the number π).<br>
|
||||
The <b>intrinsic value</b> of an object is
|
||||
the binary value of the sequence of unsigned characters which form its object representation.</p>
|
||||
<p><i>Abstract values</i> can be <b>represented</b> in a given type.<br>
|
||||
To <b>represent</b> an abstract value 'V' in a type 'T'
|
||||
is to obtain a typed value 'v' which <i>corresponds</i> to the abstract value 'V'.<br>
|
||||
The operation is denoted using the 'rep()' operator, as in: <code>v=rep(V)</code>.<br>
|
||||
'v' is the <b>representation</b> of 'V' in the type 'T'.<br>
|
||||
For example, the abstract value π can be represented in the type <code>'double'</code> as the
|
||||
'double value M_PI' and in the type <code>'int'</code> as the 'int value 3'</p>
|
||||
<p>Conversely, <i>typed values</i> can be <b>abstracted</b>.<br>
|
||||
To <b>abstract</b> a typed value 'v' of type 'T' is to obtain the
|
||||
abstract value 'V' whose representation in 'T' is 'v'.<br>
|
||||
The operation is denoted using the 'abt()' operator, as in: <code>V=abt(v)</code>.<br>
|
||||
'V' is the <b>abstraction</b> of 'v' of type 'T'.<br>
|
||||
Abstraction is just an abstract operation (you can't do it); but it is defined nevertheless
|
||||
because it will be used to give the definitions in the rest of this document.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<h2><A NAME="stdtypes">C++ Arithmetic Types</A></h2>
|
||||
<P>The C++ language defines <u>fundamental types</u> (§3.9.1). The following
|
||||
subsets of the fundamental types are intended to represent <i>numbers</i>:</p>
|
||||
<li><u>signed integer types</u> (§3.9.1/2):<br>
|
||||
<blockquote>
|
||||
<code>{signed char, signed short int, signed int, signed long int}</code><br>
|
||||
Can be used to represent general integer numbers (both negative and positive).
|
||||
</blockquote>
|
||||
</li>
|
||||
<li><u>unsigned integer types</u> (§3.9.1/3):<br>
|
||||
<blockquote>
|
||||
<code>{unsigned char, unsigned short int, unsigned int, unsigned long int}</code><br>
|
||||
Can be used to represent positive integer numbers <u>with modulo-arithmetic</u>.<br>
|
||||
</blockquote>
|
||||
<li><u>floating-point types</u> (§3.9.1/8):<br>
|
||||
<blockquote>
|
||||
<code>{float,double,long double}</code><br>
|
||||
Can be used to represent real numbers.
|
||||
</blockquote>
|
||||
</li>
|
||||
<li><u>integral or integer types</u> (§3.9.1/7):<br>
|
||||
<blockquote>
|
||||
<code>{{signed integers},{unsigned integers}, bool, char and wchar_t}</code>
|
||||
</blockquote>
|
||||
</li>
|
||||
<li><u>arithmetic types</u> (§3.9.1/8):<br>
|
||||
<blockquote>
|
||||
<code>{{integer types},{floating types}}</code>
|
||||
</blockquote>
|
||||
</li>
|
||||
<P>The integer types are required to have a <i>binary</i> value representation.<br>
|
||||
Additionally, the signed/unsigned integer types of the same base type (short, int or long)
|
||||
are required to have the same value representation, that is:</P>
|
||||
<pre> int i = -3 ; // suppose value representation is: 10011 (sign bit + 4 magnitude bits)
|
||||
unsigned int u = i ; // u is required to have the same 10011 as its value representation.
|
||||
</pre>
|
||||
<P>In other words, the integer types signed/unsigned X use the same value representation
|
||||
but a different <i>interpretation</i> of it; that is, their <i>typed values</i>
|
||||
might differ.<br>
|
||||
Another consequence of this is that the range for signed X is always a smaller subset
|
||||
of the range of unsigned X, as required by §3.9.1/3.</P>
|
||||
<P>Note: always remember that unsigned types, unlike signed types, have modulo-arithmetic;
|
||||
that is, they do not overflow.<br>
|
||||
This means that:
|
||||
<li> Always be extra careful when mixing signed/unsigned types</li>
|
||||
<li> Use unsigned types only when you need modulo arithmetic or very very large numbers.
|
||||
Don't use unsigned types just because you intend to deal with positive values only
|
||||
(you can do this with signed types as well).</li>.
|
||||
<p></P>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<h2><A NAME="numtypes">Numeric Types</A></h2>
|
||||
<p>This section introduces the following definitions intended to integrate arithmetic
|
||||
types with user-defined types which behave like numbers. Some definitions are
|
||||
purposely broad in order to include a vast variety of user-defined number
|
||||
types.</p>
|
||||
<p>Within this library, the term <i>number</i> refers to an abstract numeric value.</p>
|
||||
<p>A type is <b>numeric</b> if:</p>
|
||||
<li>It is an arithmetic type, or,</li>
|
||||
<li>It is a user-defined type which</li>
|
||||
<blockquote>
|
||||
<li>Represents numeric abstract values (i.e. numbers).</li>
|
||||
|
||||
<li>Can be converted (either implicitly or explicitly) to/from at least one
|
||||
arithmetic type.</li>
|
||||
<li>Has <a href="#range">range</a> (possibly unbounded) and <a href="#range">precision</a>
|
||||
(possibly dynamic or unlimited).</li>
|
||||
<li>Provides an specialization of <code>std::numeric_limits</code>.</li>
|
||||
</blockquote>
|
||||
<p></p>
|
||||
<p>A numeric type is <b>signed</b> if the abstract values it represent include negative numbers.<br>
|
||||
A numeric type is <b>unsigned</b> if the abstract values it represent exclude negative numbers.<br>
|
||||
A numeric type is <b>modulo</b> if it has modulo-arithmetic (does not overflow).<br>
|
||||
A numeric type is <b>integer</b> if the abstract values it represent are whole numbers.<br>
|
||||
A numeric type is <b>floating</b> if the abstract values it represent are real numbers.<br>
|
||||
An <b>arithmetic value</b> is the typed value of an arithmetic type<br>
|
||||
A <b>numeric value</b> is the typed value of a numeric type</p>
|
||||
<p></p>
|
||||
<p>These definitions simply generalize the standard notions of arithmetic types
|
||||
and values by introducing a superset called <u>numeric</u>. All arithmetic types
|
||||
and values are numeric types and values, but not vice versa, since user-defined
|
||||
numeric types are not arithmetic types.</p>
|
||||
<p>The following examples clarify the differences between arithmetic and numeric types (and values):</p>
|
||||
<pre>// A numeric type which is not an arithmetic type (is user-defined)
|
||||
// and which is intended to represent integer numbers (i.e., an 'integer' numeric type)
|
||||
class MyInt
|
||||
{
|
||||
MyInt ( long long v ) ;
|
||||
long long to_builtin();
|
||||
} ;
|
||||
namespace std {
|
||||
template<> numeric_limits<MyInt> { ... } ;
|
||||
}
|
||||
|
||||
// A 'floating' numeric type (double) which is also an arithmetic type (built-in),
|
||||
// with a float numeric value.
|
||||
double pi = M_PI ;
|
||||
|
||||
// A 'floating' numeric type with a whole numeric value.
|
||||
// NOTE: numeric values are typed valued, hence, they are, for instance,
|
||||
// integer or floating, despite the value itself being whole or including
|
||||
// a fractional part.
|
||||
double two = 2.0 ;
|
||||
|
||||
// An integer numeric type with an integer numeric value.
|
||||
MyInt i(1234);
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<h2><A NAME="range">Range and Precision</A></h2>
|
||||
<p>Given a number set 'N', some of its elements are representable in a numeric type 'T'.<br>
|
||||
The set of representable values of type 'T', or numeric set of 'T', is a set of numeric values
|
||||
whose elements are the representation of some <i>subset</i> of 'N'.<br>
|
||||
For example, the interval of 'int' values [INT_MIN,INT_MAX] is the set of representable values
|
||||
of type 'int', i.e. the 'int' numeric set, and corresponds to the representation of the elements
|
||||
of the interval of abstract values [abt(INT_MIN),abt(INT_MAX)] from the integer numbers.<br>
|
||||
Similarly, the interval of 'double' values [-DBL_MAX,DBL_MAX] is the 'double' numeric set,
|
||||
which corresponds to the subset of the real numbers from abt(-DBL_MAX) to abt(DBL_MAX).
|
||||
</p>
|
||||
<p>Let <b>next(x)</b> denote the lowest numeric value greater than x.<br>
|
||||
Let <b>prev(x)</b> denote the highest numeric value lower then x.</p>
|
||||
<p>Let <code><b>v=prev(next(V))</b></code> and <code><b>v=next(prev(V))</b></code> be identities that relate a numeric
|
||||
typed value 'v' with a number 'V'.</p>
|
||||
<p>An ordered pair of numeric values <i>x,y</i> s.t. <i>x<y</i> are <b>consecutive</b> iff
|
||||
<code>next(x)==y</code>.</p>
|
||||
<p>The abstract distance between consecutive numeric values is usually referred
|
||||
to as a <u>Unit in the Last Place</u>, or <b>ulp</b> for short. A ulp is a quantity whose abstract
|
||||
magnitude is <i>relative</i> to the numeric values it corresponds to: If the numeric set is not evenly
|
||||
distributed, that is, if the abstract distance between consecutive numeric values varies along the set
|
||||
-as is the case with the floating-point types-, the magnitude of 1ulp after the numeric value x
|
||||
might be (usually is) different from the magnitude of a 1ulp after the numeric value y for x!=y.</p>
|
||||
<p>Since numbers are inherently ordered, a <b>numeric set</b> of type 'T'
|
||||
is an ordered sequence of numeric values (of type 'T') of the form:
|
||||
</p>
|
||||
<p><code>REP(T)={l,next(l),next(next(l)),...,prev(prev(h)),prev(h),h}</code>
|
||||
</p>
|
||||
<p>where 'l' and 'h' are respectively the lowest and highest values of type 'T', called the
|
||||
<b>boundary values</b> of type T.</p>
|
||||
<p>A numeric set is discrete. It has a <b>size</b> which is the number
|
||||
of numeric values in the set, a <b>width</b> which is the abstract difference between
|
||||
the highest and lowest boundary values: [abt(h)-abt(l)], and a <b>density</b>
|
||||
which is the relation between its size and width: 'density=size/width'.<br>
|
||||
The integer types have density 1, which means that there are no unrepresentable integer numbers
|
||||
between abt(l) and abt(h) (i.e. there are no gaps). On the other hand,
|
||||
floating types have density much smaller than 1, which means that there are
|
||||
real numbers unrepresented between consecutive floating values (i.e. there are gaps).
|
||||
</p>
|
||||
<p>The interval of <u>abstract values</u> [abt(l),abt(h)] is the <b>range</b> of the type 'T',
|
||||
denoted 'R(T)'.<br>
|
||||
A range is a set of abstract values and not a set of numeric values. In other
|
||||
documents, such as the C++ standard, the word 'range' is <i>sometimes</i> used
|
||||
as synonym for 'numeric set', that is, as the ordered sequence of numeric values
|
||||
from 'l' to 'h'. In this document, however, a range is an abstract interval
|
||||
which subtends the numeric set.<br>
|
||||
For example, the sequence [-DBL_MAX,DBL_MAX] is the numeric set of the type 'double', and
|
||||
the real interval [abt(-DBL_MAX),abt(DBL_MAX)] is its range.<br>
|
||||
Notice, for instance, that the range of a floating-point type is <i>continuous</i> unlike
|
||||
its numeric set.<br>
|
||||
This definition was chosen because:
|
||||
<li>(a) The discrete set of numeric values is already given by the numeric set.</li>
|
||||
<li>(b) Abstract intervals are easier to compare and overlap since only boundary values
|
||||
need to be considered.</li><br>
|
||||
This definition allows for a concise definition of 'subranged' as given in the last section.<br>
|
||||
The width of a numeric set, as defined, is exactly equivalent to the width of a range.
|
||||
<p></p>
|
||||
<p>The <b>precision</b> of a type is given by the width or density of the numeric set.<br>
|
||||
For integer types, which have density 1, the precision is conceptually equivalent to the range
|
||||
and is determined by the number of bits used in the value representation: The higher the
|
||||
number of bits the bigger the size of the numeric set, the wider the range, and the higher
|
||||
the precision.<br>
|
||||
For floating types, which have density <<1, the precision is given not by the
|
||||
width of the range but by the density. In a typical implementation,
|
||||
the range is determined by the number of bits used in the exponent, and the precision by
|
||||
the number of bits used in the mantissa (giving the maximum number of significant digits
|
||||
that can be exactly represented). The higher the number of exponent bits the
|
||||
wider the range, while the higher the number of mantissa bits, the higher the precision.
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<h2><A NAME="roundoff">Exact, Correctly Rounded and Out-Of-Range Representations</A></h2>
|
||||
<p>Given an abstract value 'V' and a type 'T' with its corresponding range [abt(l),abt(h)]:</p>
|
||||
<p>If <code>V < abt(l)</code> or <code>V > abt(h)</code>, 'V' is <b>not representable</b>
|
||||
(cannot be represented) in the type T, or, equivalently, it's representation in the type 'T'
|
||||
is <b>out of range</b>, or <b>overflows</b>.<br>
|
||||
If <code>V < abt(l)</code>, the <b>overflow is negative</b>.<br>
|
||||
If <code>V > abt(h)</code>, the <b>overflow is positive</b>.
|
||||
</p>
|
||||
<p>If <code>V ≥ abt(l)</code> and <code>V ≤ abt(h)</code>,'V' is <b>representable</b>
|
||||
(can be represented) in the type T, or, equivalently, its representation in the type 'T'
|
||||
is in <b>in range</b>, or <b>does not overflow</b>.</p>
|
||||
<p>Notice that a numeric type, such as a C++ unsigned type, can define that any 'V' does not
|
||||
overflow by always representing not 'V' itself but the abstract value <code>U = [ V % (abt(h)+1) ]</code>,
|
||||
which is always in range.</p>
|
||||
<p>Given an abstract value 'V' represented in the type 'T' as 'v', the <b>roundoff</b> error
|
||||
of the representation is the abstract difference: (abt(v)-V).<br>
|
||||
Notice that a representation is an <i>operation</i>, hence, the roundoff error corresponds to
|
||||
the representation operation and not to the numeric value itself (i.e. numeric values do not
|
||||
have any error themselves)<br>
|
||||
If the roundoff is 0, the representation is <b>exact</b>, and 'V' is <b>exactly representable</b>
|
||||
in the type T.<br>
|
||||
If the roundoff is not 0, the representation is <b>inexact</b>, and 'V' is <b>inexactly representable</b>
|
||||
in the type T.</p>
|
||||
<p>Given an abstract value 'V' representable in a type 'T', there are always two consecutive
|
||||
numeric values of type 'T', 'prev' and 'next', such that <code>abt(prev) ≤ V ≤ abt(next)</code>.
|
||||
These are called the <b>adjacents</b> of 'V' in the type 'T'.<br>
|
||||
If a representation 'v' in a type 'T' -either exact or inexact-, is any of the adjacents of 'V'
|
||||
in that type, that is, if <code>v==prev or v==next</code>, the representation is
|
||||
<b>faithfully rounded</b>. If the choice between 'prev' and 'next'
|
||||
matches a given <b>rounding direction</b>, it is <b>correctly rounded</b>.<br>
|
||||
All exact representations are correctly rounded, but not all inexact representations are. In particular,
|
||||
C++ requires numeric conversions (described below) and the result of arithmetic operations
|
||||
(not covered by this document) to be correctly rounded, but batch operations propagate roundoff, thus
|
||||
final results are usually incorrectly rounded, that is, the numeric value 'r' which is the computed
|
||||
result is neither of the adjacents of the abstract value 'R' which is the theoretical result.<br>
|
||||
Because a correctly rounded representation is always one of adjacents of the abstract value being
|
||||
represented, the roundoff is guaranteed to be at most 1ulp.</p>
|
||||
<P>The following examples summarize the given definitions. Consider:</p>
|
||||
<li>A numeric type 'Int' representing integer numbers with a <i>numeric set</i>: {-2,-1,0,1,2}
|
||||
and <i>range</i>: [-2,2]</li>.
|
||||
<li>A numeric type 'Cardinal' representing integer numbers with a <i>numeric set</i>:
|
||||
{0,1,2,3,4,5,6,7,8,9} and <i>range</i>: [0,9] (no modulo-arithmetic here)</li>.
|
||||
<li>A numeric type 'Real' representing real numbers with a <i>numeric set</i>:
|
||||
{-2.0,-1.5,-1.0,-0.5,-0.0,+0.0,+0.5,+1.0,+1.5,+2.0} and <i>range</i>: [-2.0,+2.0]</li>
|
||||
<li>A numeric type 'Whole' representing real numbers with a <i>numeric set</i>:
|
||||
{-2.0,-1.0,0.0,+1.0,+2.0} and <i>range</i>: [-2.0,+2.0]</li>
|
||||
<p>First, notice that the types 'Real' and 'Whole' both represent real numbers, have the
|
||||
same range, but different precision.</p>
|
||||
<p>The integer number 1 (an abstract value) can be exactly represented in any of these types.<br>
|
||||
The integer number -1 can be exactly represented in 'Int', 'Real' and 'Whole', but cannot
|
||||
be represented in 'Cardinal', yielding negative overflow.<br>
|
||||
The real number 1.5 can be exactly represented in 'Real', and inexactly represented in the
|
||||
other types.<br>
|
||||
If 1.5 is represented as either 1 or 2 in any of the types (except Real), the
|
||||
representation is correctly rounded.<br>
|
||||
If 0.5 is represented as +1.5 in the type 'Real', it is incorrectly rounded.<br>
|
||||
(-2.0,-1.5) are the 'Real' adjacents of any real number in the interval [-2.0,-1.5],
|
||||
yet there are no 'Real' adjacents for x < -2.0, nor for x > +2.0.
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<h2><A NAME="stdconv">Standard (numeric) Conversions</A></h2>
|
||||
<P>The C++ language defines <u>Standard Conversions</u> (§4) some of which are
|
||||
conversions between arithmetic types.<br>
|
||||
These are <u>Integral promotions</u> (§4.5), <u>Integral conversions</u> (§4.7),
|
||||
<u>Floating point promotions</u> (§4.6), <u>Floating point conversions</u> (§4.8)
|
||||
and <u>Floating-integral conversions</u> (§4.9).<br>
|
||||
In the sequel, integral and floating point promotions are called <b>arithmetic promotions</b>,
|
||||
and these plus integral, floating-point and floating-integral conversions are called
|
||||
<b>arithmetic conversions</b> (i.e, promotions are conversions).
|
||||
</P>
|
||||
<P>Promotions, both Integral and Floating point, are <i>value-preserving</i>, which means
|
||||
that the typed value is not changed with the conversion.</p>
|
||||
<p>In the sequel, consider a source typed value 's' of type 'S', the source abstract value 'N=abt(s)',
|
||||
a destination type 'T'; and whenever possible, a result typed value 't' of type 'T'.</p>
|
||||
<p>Integer to integer conversions are always defined:<br>
|
||||
If 'T' is unsigned, the abstract value which is effectively represented is not 'N' but
|
||||
'M=[ N % ( abt(h) + 1 ) ]', where 'h' is the highest unsigned typed value of type 'T'.<br>
|
||||
If 'T' is signed and 'N' is not directly representable, the result 't' is
|
||||
<u>implementation-defined</u>, which means that the C++ implementation is required to produce
|
||||
a value 't' even if it is totally unrelated to 's'.</p>
|
||||
<p>Floating to Floating conversions are defined only if 'N' is representable;
|
||||
if it is not, the conversion has <u>undefined behavior.</u><br>
|
||||
If 'N' is exactly representable, 't' is required to be the exact representation.<br>
|
||||
If 'N' is inexactly representable, 't' is required to be one of the two adjacents, with
|
||||
an implementation-defined choice of rounding direction; that is, the conversion is required
|
||||
to be correctly rounded.</p>
|
||||
<p>Floating to Integer conversions represent not 'N' but 'M=trunc(N)', were trunc() is to truncate: i.e.
|
||||
to remove the fractional part, if any.<br>
|
||||
If 'M' is not representable in 'T', the conversion has <u>undefined behavior</u>
|
||||
(unless 'T' is bool, see §4.12).</p>
|
||||
<p>Integer to Floating conversions are always defined.<br>
|
||||
If 'N' is exactly representable, 't' is required to be the exact representation.<br>
|
||||
If 'N' is inexactly representable, 't' is required to be one of the two adjacents, with
|
||||
an implementation-defined choice of rounding direction; that is, the conversion is required
|
||||
to be correctly rounded.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<h2><A NAME="subranged">Subranged Conversion Direction, Subtype and Supertype</A></h2>
|
||||
<P>Given a source type 'S' and a destination type 'T', there is a <b>conversion direction</b>
|
||||
denoted: <code>'S->T'</code>.<br>
|
||||
For any two ranges the following <i>range relation</i> can be defined: A range
|
||||
'X' can be <i>entirely contained</i> in a range 'Y', in which case it is said that
|
||||
'X' is enclosed by 'Y'.<br>
|
||||
Formally: R(S) is <b>enclosed</b> by R(T) iif (R(S) intersection R(T)) == R(S).</P>
|
||||
<P>If the source type range, R(S), is <i>not enclosed</i> in the target type range, R(T);
|
||||
that is, if (R(S) & R(T)) != R(S), the conversion direction is said to be <b>subranged</b>,
|
||||
which means that R(S) is not entirely contained in R(T) and therefore there is
|
||||
some portion of the source range which falls outside the target range. In other words,
|
||||
if a conversion direction S->T is subranged, there are values in S which cannot be represented
|
||||
in T because they are out of range.<br>
|
||||
Notice that for S->T, the adjective subranged applies to 'T'.</p>
|
||||
<p>Examples:<br>
|
||||
Given the following numeric types all representing real numbers:<br>
|
||||
<br>
|
||||
X with numeric set {-2.0,-1.0,0.0,+1.0,+2.0} and range [-2.0,+2.0]<br>
|
||||
Y with numeric set {-2.0,-1.5,-1.0,-0.5,0.0,+0.5,+1.0,+1.5,+2.0} and range [-2.0,+2.0]<br>
|
||||
Z with numeric set {-1.0,0.0,+1.0} and range [-1.0,+1.0]<br>
|
||||
<br>
|
||||
For:<br>
|
||||
<br>
|
||||
(a) X->Y:
|
||||
<blockquote>
|
||||
R(X) & R(Y) == R(X), then X->Y is not subranged.
|
||||
Thus, all values of type X are representable in the type Y.
|
||||
</blockquote>
|
||||
(b) Y->X:
|
||||
<blockquote>
|
||||
R(Y) & R(X) == R(Y), then Y->X is not subranged.
|
||||
Thus, all values of type Y are representable in the type X, but in this case, some values
|
||||
are <i>inexactly</i> representable (all the halves).<br>
|
||||
(note: it is to permit this case that a range is an interval of abstract values
|
||||
and not an interval of typed values)
|
||||
</blockquote>
|
||||
(b) X->Z:
|
||||
<blockquote>
|
||||
R(X) & R(Z) != R(X), then X->Z is subranged.
|
||||
Thus, some values of type X are not representable in the type Z, they fall out of range
|
||||
(-2.0 and +2.0)
|
||||
</blockquote>
|
||||
<p></p>
|
||||
<p>It is possible that R(S) is not enclosed by R(T), while neither is R(T) enclosed
|
||||
by R(S); for example, UNSIG=[0,255] is not enclosed by SIG=[-128,127]; neither is SIG
|
||||
enclosed by UNSIG.<br>
|
||||
This implies that is possible that a conversion direction is subranged both
|
||||
ways. This occurs when a mixture of signed/unsigned types are involved and indicates
|
||||
that in both directions there are values which can fall out of range.</P>
|
||||
<P>Given the range relation (subranged or not) of a conversion direction S->T,
|
||||
it is possible to classify 'S' and 'T' as <b>supertype</b> and <b>subtype</b>:<br>
|
||||
If the conversion is subranged, which means that 'T' cannot represent all possible values of type 'S',
|
||||
'S' is the supertype and 'T' the subtype; otherwise, 'T' is the supertype and 'S' the subtype.<br>
|
||||
<br>
|
||||
For example:<br>
|
||||
R(float)=[-FLT_MAX,FLT_MAX] and R(double)=[-DBL_MAX,DBL_MAX].<br>
|
||||
If FLT_MAX < DBL_MAX:<br>
|
||||
'double->float' is subranged and supertype=double, subtype=float.<br>
|
||||
'float->double' is not subranged and supertype=double, subtype=float.<br>
|
||||
Notice that while 'double->float' is subranged, 'float->double' is not,
|
||||
which yields the same supertype,subtype for both directions.<br>
|
||||
<br>
|
||||
Now consider:<br>
|
||||
R(int)=[INT_MIN,INT_MAX] and R(unsigned int)=[0,UINT_MAX].<br>
|
||||
A C++ implementation is required to have UINT_MAX > INT_MAX (§3.9/3), so:<br>
|
||||
'int->unsigned' is subranged (negative values fall out of range) and supertype=int, subtype=unsigned.<br>
|
||||
'unsigned->int' is <em>also</em> subranged (high positive values fall out of range)
|
||||
and supertype=unsigned, subtype=int.<br>
|
||||
In this case, the conversion is subranged in both directions and the supertype,subtype pairs
|
||||
are not invariant (under inversion of direction). This indicates that none of the types can
|
||||
represent all the values of the other.</p>
|
||||
<p>When the supertype is the same for both 'S->T' and 'T->S', it is effectively indicating
|
||||
a type which can represent all the values of the subtype.<br>
|
||||
Consequently, if a conversion X->Y is not subranged, but the opposite (Y->X)
|
||||
is, so that the supertype is always 'Y', it is said that the direction X->Y
|
||||
is <b>correctly rounded value preserving</b>, meaning that all such conversions
|
||||
are guaranteed to produce results in range and correctly rounded (even if inexact).<br>
|
||||
For example, all integer to floating conversions are correctly rounded value preserving.
|
||||
</p>
|
||||
<HR>
|
||||
<P>Back to <A HREF="index.html">Numeric Conversion library index</A></P>
|
||||
<HR>
|
||||
<P>Revised 23 June 2004</P>
|
||||
<p>© Copyright Fernando Luis Cacciola Carballal, 2000-2004</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</body>
|
||||
</HTML>
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../boost.css">
|
||||
<TITLE>Boost Numeric Conversion Library - Index</TITLE>
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000ff" VLINK="#800080">
|
||||
<TABLE BORDER="0" CELLPADDING="7" CELLSPACING="0" WIDTH="100%"
|
||||
SUMMARY="header">
|
||||
<TR>
|
||||
<TH VALIGN="top" WIDTH="300">
|
||||
<H3><A HREF="../../../../index.htm"><IMG HEIGHT="86" WIDTH="277"
|
||||
ALT="C++ Boost" SRC="../../../../c++boost.gif" BORDER="0"></A></H3> </TH>
|
||||
<TH VALIGN="top">
|
||||
<H1 ALIGN="center">Boost Numeric Conversion Library</H1> </TH>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<HR>
|
||||
<table border="0" cellpadding="0" width="100%">
|
||||
<tr>
|
||||
<td width="50%" valign="top"><font size="4">This Document</font><br><br>
|
||||
<a href="#Overview">Overview</a><br>
|
||||
<a href="#Ack">History and Acknowledgments</a><br>
|
||||
<a href="#Ref">Bibliography</a><br>
|
||||
</td>
|
||||
<td width="50%"><font size="4">Other Documents</font><br><br>
|
||||
<A HREF="definitions.html">Definitions</A><br>
|
||||
<A HREF="converter.html"><code>converter<></code> function object</A><br>
|
||||
<A HREF="requirements.html">Type Requirements and User-defined-types support</A><br>
|
||||
<A HREF="bounds.html"><code>bounds<></code> traits class</A><br>
|
||||
<A HREF="conversion_traits.html"><code>conversion_traits<></code> traits class</A><br>
|
||||
<A HREF="converter_policies.html">Numeric Converter Policy Classes</A><br>
|
||||
<A HREF="numeric_cast.html">Improved numeric_cast<></A><br>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
<H2><A NAME="Overview"></A>Overview</H2>
|
||||
<P>The Boost Numeric Conversion library is a collection of tools to describe and perform
|
||||
conversions between values of different <a href="definitions.html#numtypes">numeric types</a>.</p>
|
||||
<p>The library includes a special alternative for a subset of <code>std::numeric_limits<></code>,
|
||||
the <A HREF="bounds.html"><code>bounds<></code></A> traits class, which provides
|
||||
a consistent way to obtain the <a href="definitions.html#range">boundary</a> values for the
|
||||
<a href="definitions.html#range">range</a> of a numeric type.</p>
|
||||
<p>It also includes a set of <A HREF="conversion_traits.html">trait classes</A> which
|
||||
describes the compile-time properties of a conversion from a source to a target
|
||||
numeric type. Both <a href="definitions.html#stdtypes">arithmetic</a> and <a href="definitions.html#numtypes">user-defined
|
||||
numeric types</a> can be used.</p>
|
||||
<p>A policy-based <A HREF="converter.html">converter</A> object which uses <code>conversion_traits</code>
|
||||
to select an optimized implementation is supplied.
|
||||
Such implementation uses an optimal range checking code suitable for the source/target combination.<br>
|
||||
The converter's out-of-range behavior can be customized via an <A HREF="converter_policies.html#oh">OverflowHandler</A>
|
||||
policy.<br>
|
||||
For floating-point to integral conversions, the rounding mode can be selected via
|
||||
the <A HREF="converter_policies.html#f2i">Float2IntRounder</A> policy.<br>
|
||||
A custom low-level conversion routine (for UDTs for instance) can be passed
|
||||
via a <A HREF="converter_policies.html#rawc">RawConverter</A> policy.<br>
|
||||
The optimized automatic range-checking logic can be overridden via a <A HREF="converter_policies.html#rc">UserRangeChecker</A>
|
||||
policy.</p>
|
||||
<hr>
|
||||
<H2><A NAME="Ack"></A>History and Acknowledgments</H2>
|
||||
<p>Pre-formal review:</p>
|
||||
<blockquote>
|
||||
<p>Kevlin Henney, with help from David Abrahams and Beman Dawes, originally contributed
|
||||
the previous version of numeric_cast<> which already presented the idea of a runtime range check.<br>
|
||||
Later, Eric Ford, Kevin Lynch and the author spotted some genericity problems
|
||||
with that numeric_cast<> which prevented it from being used in a generic
|
||||
layer of math functions.<br>
|
||||
An improved numeric_cast<> which properly handled all combinations of arithmetic types was presented.<br>
|
||||
David Abrahams and Beman Dawes acknowledged the need of an improved version
|
||||
of numeric_cast<> and supported the submission as originally laid out.
|
||||
Daryl Walker and Darin Adler made some important comments and proposed fixes
|
||||
to the original submission.</p>
|
||||
<p>Special thanks go to Björn Karlsoon who helped the author considerably. Having
|
||||
found the problems with numeric_cast<> himself, he revised very carefully
|
||||
the original submission and spot a subtle bug in the range checking implementation.
|
||||
He also wrote part of this documentation and proof-read and corrected other
|
||||
parts. And most importantly: the features now presented here in this library
|
||||
evolved from the original submission as a result of the useful private communications
|
||||
between Björn and the author.</p>
|
||||
</blockquote>
|
||||
<p>Post-formal review:</p>
|
||||
<p>Guillaume Melquiond spoted some documentation and code issues, particularly about rounding conversions.<br>
|
||||
The following people contributed an important review of the design, documentation and code: Kevin Lynch, Thorsten Ottosen, Paul Bristow,
|
||||
Daryle Walker, Jhon Torjo, Eric Ford, Gennadiy Rozental.
|
||||
</p>
|
||||
<hr>
|
||||
<H2><A NAME="Ref"></A>Bibliography</H2>
|
||||
<ul>
|
||||
<li>Standard Documents:
|
||||
<ol>
|
||||
<li>ISO/IEC 14882:98 (C++98 Standard)</li>
|
||||
<li>ISO/IEC 9899:1999 (C99 Standard)</li>
|
||||
<li>ISO/IEC 10967-1 (Language Independent Arithmetic (LIA), Part I, 1994)</li>
|
||||
<li>ISO/IEC 2382-1:1993 (Information Technology - Vocabulary - Part I: Fundamental Terms)</li>
|
||||
<li>ANSI/IEEE 754-1985 [and IEC 60559:1989] (Binary floating-point)</li>
|
||||
<li>ANSI/IEEE 854-1988 (Radix Independent floating-point)</li>
|
||||
<li>ANSI X3/TR-1-82 (Dictionary for Information Processing Systems)</li>
|
||||
<li><a href="http://anubis.dkuug.dk/JTC1/SC22/WG14/www/docs/n753.htm">ISO/IEC JTC1/SC22/WG14/N753</a> C9X Revision Proposal: LIA-1 Binding: Rationale</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Papers:
|
||||
<ol>
|
||||
<li>David Goldberg <A href="http://citeseer.nj.nec.com/goldberg91what.html">
|
||||
What Every Computer Scientist Should Know About Floating-Point Arithmetic</A></li>
|
||||
<li><A href="http://www.cs.berkeley.edu/~wkahan/">Prof. William Kahan</A> papers on floating-point.</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ul>
|
||||
<HR>
|
||||
<P>Revised 23 June 2004</P>
|
||||
<p>© Copyright Fernando Luis Cacciola Carballal, 2000-2004</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</body>
|
||||
</HTML>
|
||||
@@ -0,0 +1,123 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../boost.css">
|
||||
<TITLE>Boost Numeric Conversion Library - numeric_cast</TITLE>
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
|
||||
<TABLE BORDER="0" CELLPADDING="7" CELLSPACING="0" WIDTH="100%"
|
||||
SUMMARY="header">
|
||||
<TR>
|
||||
<TH VALIGN="top" WIDTH="300">
|
||||
<H3><A HREF="../../../../index.htm"><IMG HEIGHT="86" WIDTH="277"
|
||||
ALT="C++ Boost" SRC="../../../../c++boost.gif" BORDER="0"></A></H3> </TH>
|
||||
<TH VALIGN="top">
|
||||
<H1 ALIGN="center">Boost Numeric Conversion Library</H1>
|
||||
<H1><A HREF="http://www.boost.org">Header </A><A
|
||||
HREF="../../../../boost/numeric_cast.hpp">boost/numeric_cast.hpp</A></H1> </TH>
|
||||
</TR>
|
||||
</TABLE><HR>
|
||||
<H2>Contents</H2>
|
||||
<UL>
|
||||
<LI><A HREF="#introduction">Introduction</A></LI>
|
||||
<LI><A HREF="#numeric_cast"><CODE>numeric_cast</CODE></A></LI>
|
||||
<LI><A HREF="#examples">Examples</A></LI>
|
||||
</UL> <HR>
|
||||
<H2><A NAME="introduction">Introduction</A></H2>
|
||||
<P>The lack of preservation of range makes conversions between numeric
|
||||
types error prone. This is true for both implicit conversions and explicit
|
||||
conversions (through static_cast). <A HREF="#numeric_cast"> numeric_cast</A>
|
||||
detects loss of range when a numeric type is converted, and throws an
|
||||
exception if the range cannot be preserved.</P>
|
||||
<P>There are several situations where conversions are unsafe: </P>
|
||||
<UL>
|
||||
<LI>Conversions from an integral type with a wider range than the target
|
||||
integral type.</LI>
|
||||
<LI> Conversions from unsigned to signed (and vice versa) integral
|
||||
types.</LI>
|
||||
<LI> Conversions from floating point types to integral types.</LI>
|
||||
</UL>
|
||||
<P>The C++ Standard does not specify the behavior when a numeric type is
|
||||
assigned a value that cannot be represented by the type, except for unsigned
|
||||
integral types [3.9.1.4], which must obey the laws of arithmetic modulo
|
||||
2<SUP>n</SUP> (this implies that the result will be reduced modulo the number
|
||||
that is one greater than the largest value that can be represented). The fact
|
||||
that the behavior for overflow is undefined for all conversions (except the
|
||||
aforementioned unsigned to unsigned) makes any code that may produce positive
|
||||
or negative overflows exposed to portability issues.</P>
|
||||
<P>numeric_cast adheres to the rules for implicit conversions mandated by
|
||||
the C++ Standard, such as truncating floating point types when converting to
|
||||
integral types. The implementation must guarantee that for a conversion to a
|
||||
type that can hold all possible values of the source type, there will be no
|
||||
runtime overhead. <BR> <BR> </P> <HR>
|
||||
<H2><A NAME="numeric_cast"><CODE>numeric_cast</CODE></A></H2>
|
||||
<BLOCKQUOTE>
|
||||
<PRE>template<typename Target, typename Source> inline
|
||||
typename boost::numeric::converter<Traget,Source>::result_type
|
||||
numeric_cast ( Source arg )
|
||||
{
|
||||
return boost::numeric::converter<Traget,Source>::convert(arg);
|
||||
}
|
||||
</PRE> </BLOCKQUOTE>
|
||||
<P>numeric_cast returns the result of converting a value of type Source to a value of type
|
||||
Target. If out-of-range is detected, an exception is thrown (see
|
||||
<A HREF="#bad_numeric_cast">bad_numeric_cast</A>, <A
|
||||
HREF="#positive_overflow">positive_overflow</A> and
|
||||
<A HREF="#negative_overflow">negative_overflow</A>). <BR> <BR> </P> <HR>
|
||||
<H2><A NAME="examples">Examples</A></H2>
|
||||
<P>The following example performs some typical conversions between numeric
|
||||
types: </P>
|
||||
<BLOCKQUOTE>
|
||||
<PRE>#include <boost/numeric_cast.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::numeric_cast;
|
||||
using boost::bad_numeric_cast;
|
||||
using boost::positive_overflow;
|
||||
using boost::negative_overflow;
|
||||
try {
|
||||
int i=42;
|
||||
short s=numeric_cast<short>(i);
|
||||
}
|
||||
catch(negative_overflow& e) {
|
||||
std::cout << e.what();
|
||||
}
|
||||
catch(positive_overflow& e) {
|
||||
std::cout << e.what();
|
||||
}
|
||||
|
||||
try {
|
||||
float f=-42.1234;
|
||||
// This will cause a boost::negative_underflow exception to be thrown
|
||||
unsigned int i=numeric_cast<unsigned int>(f);
|
||||
|
||||
double d=f+numeric_cast<double>(i);
|
||||
|
||||
unsigned long l=std::numeric_limits<unsigned long>::max();
|
||||
// This works, because unsigned integral types cannot cause overflow.
|
||||
unsigned char c=numeric_cast<unsigned char>(l);
|
||||
|
||||
unsigned short us=std::numeric_limits<unsigned short>::max();
|
||||
// This will cause an positive_overflow exception to be thrown
|
||||
short s=numeric_cast<short>(us);
|
||||
|
||||
}
|
||||
catch(bad_numeric_cast& e) {
|
||||
std::cout << e.what();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}</PRE> </BLOCKQUOTE> <BR> <BR> <HR>
|
||||
<HR>
|
||||
<P>Back to <A HREF="index.html">Numeric Conversion library index</A></P>
|
||||
<HR>
|
||||
<P>Revised 23 June 2004</P>
|
||||
<p>© Copyright Boost 1999</p>
|
||||
<p>© Copyright Fernando Luis Cacciola Carballal, 2000-2004</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -0,0 +1,116 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="../../../../boost.css">
|
||||
<TITLE>Boost Numeric Conversion Library - Type Requirements and User-defined-types support</TITLE>
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000ff" VLINK="#800080">
|
||||
<TABLE BORDER="0" CELLPADDING="7" CELLSPACING="0" WIDTH="100%"
|
||||
SUMMARY="header">
|
||||
<TR>
|
||||
<TH VALIGN="top" WIDTH="300">
|
||||
<H3><A HREF="../../../../index.htm"><IMG HEIGHT="86" WIDTH="277"
|
||||
ALT="C++ Boost" SRC="../../../../c++boost.gif" BORDER="0"></A></H3> </TH>
|
||||
<TH VALIGN="top">
|
||||
<H1 ALIGN="center">Boost Numeric Conversion Library</H1>
|
||||
<H1 ALIGN="center">Type Requirements<br>and<br>User-defined-types support</H1>
|
||||
</TH>
|
||||
</TR>
|
||||
</TABLE> <HR>
|
||||
<H2>Contents</H2>
|
||||
<DL CLASS="page-index">
|
||||
<DT><A HREF="#req">Type Requirements</A></DT>
|
||||
<DT><A HREF="#sem">UDT's special semantics</A></DT>
|
||||
<DT><A HREF="#hooks">Special Policies</A></DT>
|
||||
</DL>
|
||||
|
||||
|
||||
<HR>
|
||||
|
||||
<H2><A NAME="req"></A>Type Requirements</H2>
|
||||
<P>Both arithmetic (built-in) and user-defined numeric types require proper specialization of
|
||||
<CODE>std::numeric_limits<></CODE> (that is, with (in-class) integral constants).<br>
|
||||
The library uses <CODE>std::numeric_limits<T>::is_specialized</CODE> to detect whether
|
||||
the type is builtin or user defined, and <CODE>std::numeric_limits<T>::is_integer,
|
||||
std::numeric_limits<T>::is_signed</CODE>
|
||||
to detect whether the type is integer or floating point; and whether it is signed/unsigned.</P>
|
||||
<P>The default Float2IntRounder policies uses unqualified calls to functions <CODE>floor()
|
||||
and ceil()</CODE>; but the standard functions are introduced in scope by a
|
||||
using directive:</P>
|
||||
<PRE>using std::floor ; return floor(s); </PRE>
|
||||
<P>Therefore, for builtin arithmetic types, the std functions will be used.
|
||||
User defined types should provide overloaded versions of these functions in
|
||||
order to use the default rounder policies. If these overloads are defined within a user namespace
|
||||
argument dependent lookup (ADL) should find them, but if your compiler has a weak ADL
|
||||
you might need to put these functions some place else or write your own rounder policy.</P>
|
||||
<P>The default Trunc<> rounder policy needs to determine if the source value
|
||||
is positive or not, and for this it evaluates the expression "s < static_cast<S>(0)".
|
||||
Therefore, user defined types require a visible operator < in order to use
|
||||
the Trunc<> policy (the default).<br>
|
||||
</P>
|
||||
|
||||
<HR>
|
||||
<H2><A NAME="sem"></A>UDT's special semantics</H2>
|
||||
|
||||
<p><u>Conversion Traits</u></p>
|
||||
<p>If a User Defined Type is involved in a conversion, it is <i>assumed</i> that
|
||||
the UDT has <a href="definitions.html#range">wider range</a> than any built-in
|
||||
type, and consequently the values of some <code>converter_traits<></code>
|
||||
members are hardwired regardless of the reality. The following table summarizes
|
||||
this:</p>
|
||||
|
||||
<li>Target=UDT and Source=built-in
|
||||
<blockquote><code>subranged=false</code><br>
|
||||
<code>supertype=Target</code><br>
|
||||
<code>subtype=Source</code></blockquote>
|
||||
</li>
|
||||
|
||||
<li>Target=built-in and Source=UDT
|
||||
<blockquote><code>subranged=true</code><br>
|
||||
<code>supertype=Source</code><br>
|
||||
<code>subtype=Target</code></blockquote>
|
||||
</li>
|
||||
|
||||
<li>Target=UDT and Source=UDT
|
||||
<blockquote><code>subranged=false</code><br>
|
||||
<code>supertype=Target</code><br>
|
||||
<code>subtype=Source</code></blockquote>
|
||||
</li>
|
||||
<p>The Traits member <code>udt_mixture</code> can be used to detect whether a
|
||||
UDT is involved and to infer the validity of the other members as shown above.</p>
|
||||
<p><u>Range Checking</u></p>
|
||||
<p>Because User Defined Numeric Types might have peculiar ranges (such as an unbounded
|
||||
range), this library does not attempt to supply a meaningful range checking
|
||||
logic when UDTs are involved in a conversion. Therefore, if either Target or
|
||||
Source are not built-in types, the bundled range checking of the <code>converter<></code>
|
||||
function object is automatically disabled. However, it is possible to supply
|
||||
a user-defined range-checker. See <A HREF="#hooks">Special Policies</A></p>
|
||||
|
||||
<HR>
|
||||
<H2><A NAME="hooks"></A>Special Policies</H2>
|
||||
<p>There are two components of the <code>converter<></code> class that might
|
||||
require special behavior if User Defined Numeric Types are involved: the Range
|
||||
Checking and the Raw Conversion.</p>
|
||||
<p>When both Target and Source are built-in types, the converter class uses an
|
||||
<i>internal</i> range checking logic which is optimized and customized for the
|
||||
combined properties of the types.<br>
|
||||
However, this internal logic is disabled when either type is User Defined. In
|
||||
this case, the user can specify an <i>external</i> range checking policy which
|
||||
will be used in place of the internal code.
|
||||
See <a HREF="converter_policies.html#rc">UserRangeChecker</a> policy for details.</p>
|
||||
<p>The converter class performs the actual conversion using a Raw Converter policy.
|
||||
The default raw converter simply performs a <code>"static_cast<Target>(source)".</code><br>
|
||||
However, if the a UDT is involved, the static_cast might not work. In this case,
|
||||
the user can implement and pass a different raw converter policy.
|
||||
See <a HREF="converter_policies.html#rawc">RawConverter</a> policy for details </p>
|
||||
<HR>
|
||||
<P>Back to <A HREF="index.html">Numeric Conversion library index</A></P>
|
||||
<HR>
|
||||
<P>Revised 23 June 2004</P>
|
||||
<p>© Copyright Fernando Luis Cacciola Carballal, 2000-2004</p>
|
||||
<p> Use, modification, and distribution are subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
|
||||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -0,0 +1,24 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_BOUNDS_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_BOUNDS_12NOV2002_HPP
|
||||
|
||||
#include "boost/numeric/conversion/detail/bounds.hpp"
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
|
||||
template<class N>
|
||||
struct bounds : boundsdetail::get_impl<N>::type
|
||||
{} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
// © Copyright Boost.org 1999
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
//
|
||||
// Revision History
|
||||
//
|
||||
// 19 Nov 2001 Syntatic changes as suggested by Darin Adler (Fernando Cacciola)
|
||||
// 08 Nov 2001 Fixes to accommodate MSVC (Fernando Cacciola)
|
||||
// 04 Nov 2001 Fixes to accommodate gcc2.92 (Fernando Cacciola)
|
||||
// 30 Oct 2001 Some fixes suggested by Daryle Walker (Fernando Cacciola)
|
||||
// 25 Oct 2001 Initial boostification (Fernando Cacciola)
|
||||
// 23 Jan 2004 Inital add to cvs (post review)s
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_CAST_25OCT2001_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_CAST_25OCT2001_HPP
|
||||
|
||||
#include <boost/type.hpp>
|
||||
#include <boost/numeric/conversion/converter.hpp>
|
||||
|
||||
#ifndef BOOST_EXPLICIT_DEFAULT_TARGET
|
||||
# if defined(BOOST_MSVC) && BOOST_MSVC <= 1200 // 1200 = VC6
|
||||
# define BOOST_EXPLICIT_DEFAULT_TARGET , ::boost::type<Target>* = 0
|
||||
# else
|
||||
# define BOOST_EXPLICIT_DEFAULT_TARGET
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template<typename Target, typename Source>
|
||||
inline
|
||||
typename boost::numeric::converter<Target,Source>::result_type
|
||||
numeric_cast ( Source arg BOOST_EXPLICIT_DEFAULT_TARGET )
|
||||
{
|
||||
typedef boost::numeric::converter<Target,Source> Converter ;
|
||||
return Converter::convert(arg);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_CONVERSION_TRAITS_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_CONVERSION_TRAITS_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/numeric/conversion/detail/conversion_traits.hpp"
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
|
||||
template<class T, class S>
|
||||
struct conversion_traits : convdetail::get_conversion_traits<T,S>::type {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_CONVERTER_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_CONVERTER_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/numeric/conversion/conversion_traits.hpp"
|
||||
#include "boost/numeric/conversion/converter_policies.hpp"
|
||||
|
||||
#include "boost/numeric/conversion/detail/converter.hpp"
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
|
||||
template<class T,
|
||||
class S,
|
||||
class Traits = conversion_traits<T,S>,
|
||||
class OverflowHandler = def_overflow_handler,
|
||||
class Float2IntRounder = Trunc< BOOST_DEDUCED_TYPENAME Traits::source_type> ,
|
||||
class RawConverter = raw_converter<Traits>,
|
||||
class UserRangeChecker = UseInternalRangeChecker
|
||||
>
|
||||
struct converter : convdetail::get_converter_impl<Traits,
|
||||
OverflowHandler,
|
||||
Float2IntRounder,
|
||||
RawConverter,
|
||||
UserRangeChecker
|
||||
>::type
|
||||
{
|
||||
typedef Traits traits ;
|
||||
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
typedef typename Traits::result_type result_type ;
|
||||
|
||||
result_type operator() ( argument_type s ) const { return this->convert(s) ; }
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
template<class S,
|
||||
class OverflowHandler = def_overflow_handler,
|
||||
class Float2IntRounder = Trunc<S> ,
|
||||
class UserRangeChecker = UseInternalRangeChecker
|
||||
>
|
||||
struct make_converter_from
|
||||
{
|
||||
template<class T,
|
||||
class Traits = conversion_traits<T,S>,
|
||||
class RawConverter = raw_converter<Traits>
|
||||
>
|
||||
struct to
|
||||
{
|
||||
typedef converter<T,S,Traits,OverflowHandler,Float2IntRounder,RawConverter,UserRangeChecker> type ;
|
||||
} ;
|
||||
|
||||
} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_CONVERTER_POLICIES_FLC_12NOV2002_HPP
|
||||
|
||||
#include <typeinfo> // for std::bad_cast
|
||||
|
||||
#include "boost/compatibility/cpp_c_headers/cmath" // for std::floor and std::ceil
|
||||
|
||||
#include "boost/type_traits/is_arithmetic.hpp"
|
||||
|
||||
#include "boost/mpl/if.hpp"
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
|
||||
template<class S>
|
||||
struct Trunc
|
||||
{
|
||||
typedef S source_type ;
|
||||
|
||||
typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
|
||||
|
||||
static source_type nearbyint ( argument_type s )
|
||||
{
|
||||
using std::floor ;
|
||||
using std::ceil ;
|
||||
return s < static_cast<S>(0) ? ceil(s) : floor(s) ;
|
||||
}
|
||||
|
||||
typedef mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style ;
|
||||
} ;
|
||||
|
||||
template<class S>
|
||||
struct RoundEven
|
||||
{
|
||||
typedef S source_type ;
|
||||
|
||||
typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
|
||||
|
||||
static source_type nearbyint ( argument_type s )
|
||||
{
|
||||
// Algorithm contributed by Guillaume Melquiond
|
||||
|
||||
using std::floor ;
|
||||
using std::ceil ;
|
||||
|
||||
// only works inside the range not at the boundaries
|
||||
S a = floor(s);
|
||||
S b = ceil(s);
|
||||
|
||||
S c = (s - a) - (b - s); // the "good" subtraction
|
||||
|
||||
if ( c < static_cast<S>(0.0) )
|
||||
return a;
|
||||
else if ( c > static_cast<S>(0.0) )
|
||||
return b;
|
||||
else
|
||||
return 2 * floor(b / static_cast<S>(2.0)); // needs to behave sanely
|
||||
}
|
||||
|
||||
typedef mpl::integral_c< std::float_round_style, std::round_to_nearest> round_style ;
|
||||
} ;
|
||||
|
||||
template<class S>
|
||||
struct Ceil
|
||||
{
|
||||
typedef S source_type ;
|
||||
|
||||
typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
|
||||
|
||||
static source_type nearbyint ( argument_type s )
|
||||
{
|
||||
using std::ceil ;
|
||||
return ceil(s) ;
|
||||
}
|
||||
|
||||
typedef mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style ;
|
||||
} ;
|
||||
|
||||
template<class S>
|
||||
struct Floor
|
||||
{
|
||||
typedef S source_type ;
|
||||
|
||||
typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
|
||||
|
||||
static source_type nearbyint ( argument_type s )
|
||||
{
|
||||
using std::floor ;
|
||||
return floor(s) ;
|
||||
}
|
||||
|
||||
typedef mpl::integral_c< std::float_round_style, std::round_toward_neg_infinity> round_style ;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum range_check_result
|
||||
{
|
||||
cInRange = 0 ,
|
||||
cNegOverflow = 1 ,
|
||||
cPosOverflow = 2
|
||||
} ;
|
||||
|
||||
class bad_numeric_conversion : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char * what() const throw()
|
||||
{ return "bad numeric conversion: overflow"; }
|
||||
};
|
||||
|
||||
class negative_overflow : public bad_numeric_conversion
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char * what() const throw()
|
||||
{ return "bad numeric conversion: negative overflow"; }
|
||||
};
|
||||
class positive_overflow : public bad_numeric_conversion
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char * what() const throw()
|
||||
{ return "bad numeric conversion: positive overflow"; }
|
||||
};
|
||||
|
||||
struct def_overflow_handler
|
||||
{
|
||||
void operator() ( range_check_result r ) // throw(negative_overflow,positive_overflow)
|
||||
{
|
||||
if ( r == cNegOverflow )
|
||||
throw negative_overflow() ;
|
||||
else if ( r == cPosOverflow )
|
||||
throw positive_overflow() ;
|
||||
}
|
||||
} ;
|
||||
|
||||
struct silent_overflow_handler
|
||||
{
|
||||
void operator() ( range_check_result ) {} // throw()
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class Traits>
|
||||
struct raw_converter
|
||||
{
|
||||
typedef typename Traits::result_type result_type ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static result_type low_level_convert ( argument_type s ) { return static_cast<result_type>(s) ; }
|
||||
} ;
|
||||
|
||||
struct UseInternalRangeChecker {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_BOUNDS_DETAIL_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_BOUNDS_DETAIL_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/limits.hpp"
|
||||
#include "boost/config.hpp"
|
||||
#include "boost/mpl/if.hpp"
|
||||
|
||||
namespace boost { namespace numeric { namespace boundsdetail
|
||||
{
|
||||
template<class N>
|
||||
class Integral
|
||||
{
|
||||
typedef std::numeric_limits<N> limits ;
|
||||
|
||||
public :
|
||||
|
||||
static N lowest () { return limits::min BOOST_PREVENT_MACRO_SUBSTITUTION (); }
|
||||
static N highest () { return limits::max BOOST_PREVENT_MACRO_SUBSTITUTION (); }
|
||||
static N smallest() { return static_cast<N>(1); }
|
||||
} ;
|
||||
|
||||
template<class N>
|
||||
class Float
|
||||
{
|
||||
typedef std::numeric_limits<N> limits ;
|
||||
|
||||
public :
|
||||
|
||||
static N lowest () { return static_cast<N>(-limits::max BOOST_PREVENT_MACRO_SUBSTITUTION ()) ; }
|
||||
static N highest () { return limits::max BOOST_PREVENT_MACRO_SUBSTITUTION (); }
|
||||
static N smallest() { return limits::min BOOST_PREVENT_MACRO_SUBSTITUTION (); }
|
||||
} ;
|
||||
|
||||
template<class N>
|
||||
struct get_impl
|
||||
{
|
||||
typedef mpl::bool_< ::std::numeric_limits<N>::is_integer > is_int ;
|
||||
|
||||
typedef Integral<N> impl_int ;
|
||||
typedef Float <N> impl_float ;
|
||||
|
||||
typedef typename mpl::if_<is_int,impl_int,impl_float>::type type ;
|
||||
} ;
|
||||
|
||||
} } } // namespace boost::numeric::boundsdetail.
|
||||
|
||||
#endif
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,97 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_DETAIL_CONVERSION_TRAITS_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_DETAIL_CONVERSION_TRAITS_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/type_traits/is_arithmetic.hpp"
|
||||
#include "boost/type_traits/is_same.hpp"
|
||||
#include "boost/type_traits/remove_cv.hpp"
|
||||
|
||||
#include "boost/numeric/conversion/detail/meta.hpp"
|
||||
#include "boost/numeric/conversion/detail/int_float_mixture.hpp"
|
||||
#include "boost/numeric/conversion/detail/sign_mixture.hpp"
|
||||
#include "boost/numeric/conversion/detail/udt_builtin_mixture.hpp"
|
||||
#include "boost/numeric/conversion/detail/is_subranged.hpp"
|
||||
|
||||
namespace boost { namespace numeric { namespace convdetail
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Implementation of the Conversion Traits for T != S
|
||||
//
|
||||
// This is a VISIBLE base class of the user-level conversion_traits<> class.
|
||||
//-------------------------------------------------------------------
|
||||
template<class T,class S>
|
||||
struct non_trivial_traits_impl
|
||||
{
|
||||
typedef typename get_int_float_mixture <T,S>::type int_float_mixture ;
|
||||
typedef typename get_sign_mixture <T,S>::type sign_mixture ;
|
||||
typedef typename get_udt_builtin_mixture <T,S>::type udt_builtin_mixture ;
|
||||
|
||||
typedef typename get_is_subranged<T,S>::type subranged ;
|
||||
|
||||
typedef mpl::false_ trivial ;
|
||||
|
||||
typedef T target_type ;
|
||||
typedef S source_type ;
|
||||
typedef T result_type ;
|
||||
|
||||
typedef typename mpl::if_< is_arithmetic<S>, S, S const&>::type argument_type ;
|
||||
|
||||
typedef typename mpl::if_<subranged,S,T>::type supertype ;
|
||||
typedef typename mpl::if_<subranged,T,S>::type subtype ;
|
||||
} ;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Implementation of the Conversion Traits for T == S
|
||||
//
|
||||
// This is a VISIBLE base class of the user-level conversion_traits<> class.
|
||||
//-------------------------------------------------------------------
|
||||
template<class N>
|
||||
struct trivial_traits_impl
|
||||
{
|
||||
typedef typename get_int_float_mixture <N,N>::type int_float_mixture ;
|
||||
typedef typename get_sign_mixture <N,N>::type sign_mixture ;
|
||||
typedef typename get_udt_builtin_mixture<N,N>::type udt_builtin_mixture ;
|
||||
|
||||
typedef mpl::false_ subranged ;
|
||||
typedef mpl::true_ trivial ;
|
||||
|
||||
typedef N target_type ;
|
||||
typedef N source_type ;
|
||||
typedef N const& result_type ;
|
||||
typedef N const& argument_type ;
|
||||
|
||||
typedef N supertype ;
|
||||
typedef N subtype ;
|
||||
|
||||
} ;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Top level implementation selector.
|
||||
//-------------------------------------------------------------------
|
||||
template<class T, class S>
|
||||
struct get_conversion_traits
|
||||
{
|
||||
typedef typename remove_cv<T>::type target_type ;
|
||||
typedef typename remove_cv<S>::type source_type ;
|
||||
|
||||
typedef typename is_same<target_type,source_type>::type is_trivial ;
|
||||
|
||||
typedef trivial_traits_impl <target_type> trivial_imp ;
|
||||
typedef non_trivial_traits_impl<target_type,source_type> non_trivial_imp ;
|
||||
|
||||
typedef typename mpl::if_<is_trivial,trivial_imp,non_trivial_imp>::type type ;
|
||||
} ;
|
||||
|
||||
} } } // namespace boost::numeric::convdetail
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,600 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_DETAIL_CONVERTER_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_DETAIL_CONVERTER_FLC_12NOV2002_HPP
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "boost/numeric/conversion/detail/meta.hpp"
|
||||
#include "boost/numeric/conversion/detail/conversion_traits.hpp"
|
||||
#include "boost/numeric/conversion/bounds.hpp"
|
||||
|
||||
#include "boost/type_traits/is_same.hpp"
|
||||
|
||||
namespace boost { namespace numeric { namespace convdetail
|
||||
{
|
||||
// Integral Constants representing rounding modes
|
||||
typedef mpl::integral_c<std::float_round_style, std::round_toward_zero> round2zero_c ;
|
||||
typedef mpl::integral_c<std::float_round_style, std::round_to_nearest> round2nearest_c ;
|
||||
typedef mpl::integral_c<std::float_round_style, std::round_toward_infinity> round2inf_c ;
|
||||
typedef mpl::integral_c<std::float_round_style, std::round_toward_neg_infinity> round2neg_inf_c ;
|
||||
|
||||
// Metafunction:
|
||||
//
|
||||
// for_round_style<RoundStyle,RoundToZero,RoundToNearest,RoundToInf,RoundToNegInf>::type
|
||||
//
|
||||
// {RoundStyle} Integral Constant specifying a round style as declared above.
|
||||
// {RoundToZero,RoundToNearest,RoundToInf,RoundToNegInf} arbitrary types.
|
||||
//
|
||||
// Selects one of the 4 types according to the value of RoundStyle.
|
||||
//
|
||||
template<class RoundStyle,class RoundToZero,class RoundToNearest,class RoundToInf,class RoundToNegInf>
|
||||
struct for_round_style
|
||||
{
|
||||
typedef ct_switch4<RoundStyle
|
||||
, round2zero_c, round2nearest_c, round2inf_c // round2neg_inf_c
|
||||
, RoundToZero , RoundToNearest , RoundToInf , RoundToNegInf
|
||||
> selector ;
|
||||
|
||||
typedef typename selector::type type ;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Range Checking Logic.
|
||||
//
|
||||
// The range checking logic is built up by combining 1 or 2 predicates.
|
||||
// Each predicate is encapsulated in a template class and exposes
|
||||
// the static member function 'apply'.
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Because a particular logic can combine either 1 or two predicates, the following
|
||||
// tags are used to allow the predicate applier to receive 2 preds, but optimize away
|
||||
// one of them if it is 'non-applicable'
|
||||
struct non_applicable { typedef mpl::false_ do_apply ; } ;
|
||||
struct applicable { typedef mpl::true_ do_apply ; } ;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Range Checking Logic implementations.
|
||||
//
|
||||
// The following classes, collectivelly named 'Predicates', are instantiated within
|
||||
// the corresponding range checkers.
|
||||
// Their static member function 'apply' is called to perform the actual range checking logic.
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// s < Lowest(T) ? cNegOverflow : cInRange
|
||||
//
|
||||
template<class Traits>
|
||||
struct LT_LoT : applicable
|
||||
{
|
||||
typedef typename Traits::target_type T ;
|
||||
typedef typename Traits::source_type S ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static range_check_result apply ( argument_type s )
|
||||
{
|
||||
return s < static_cast<S>(bounds<T>::lowest()) ? cNegOverflow : cInRange ;
|
||||
}
|
||||
} ;
|
||||
|
||||
// s < 0 ? cNegOverflow : cInRange
|
||||
//
|
||||
template<class Traits>
|
||||
struct LT_Zero : applicable
|
||||
{
|
||||
typedef typename Traits::source_type S ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static range_check_result apply ( argument_type s )
|
||||
{
|
||||
return s < static_cast<S>(0) ? cNegOverflow : cInRange ;
|
||||
}
|
||||
} ;
|
||||
|
||||
// s <= Lowest(T)-1 ? cNegOverflow : cInRange
|
||||
//
|
||||
template<class Traits>
|
||||
struct LE_PrevLoT : applicable
|
||||
{
|
||||
typedef typename Traits::target_type T ;
|
||||
typedef typename Traits::source_type S ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static range_check_result apply ( argument_type s )
|
||||
{
|
||||
return s <= static_cast<S>(bounds<T>::lowest()) - static_cast<S>(1.0)
|
||||
? cNegOverflow : cInRange ;
|
||||
}
|
||||
} ;
|
||||
|
||||
// s < Lowest(T)-0.5 ? cNegOverflow : cInRange
|
||||
//
|
||||
template<class Traits>
|
||||
struct LT_HalfPrevLoT : applicable
|
||||
{
|
||||
typedef typename Traits::target_type T ;
|
||||
typedef typename Traits::source_type S ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static range_check_result apply ( argument_type s )
|
||||
{
|
||||
return s < static_cast<S>(bounds<T>::lowest()) - static_cast<S>(0.5)
|
||||
? cNegOverflow : cInRange ;
|
||||
}
|
||||
} ;
|
||||
|
||||
// s > Highest(T) ? cPosOverflow : cInRange
|
||||
//
|
||||
template<class Traits>
|
||||
struct GT_HiT : applicable
|
||||
{
|
||||
typedef typename Traits::target_type T ;
|
||||
typedef typename Traits::source_type S ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static range_check_result apply ( argument_type s )
|
||||
{
|
||||
return s > static_cast<S>(bounds<T>::highest())
|
||||
? cPosOverflow : cInRange ;
|
||||
}
|
||||
} ;
|
||||
|
||||
// s >= Lowest(T) + 1 ? cPosOverflow : cInRange
|
||||
//
|
||||
template<class Traits>
|
||||
struct GE_SuccHiT : applicable
|
||||
{
|
||||
typedef typename Traits::target_type T ;
|
||||
typedef typename Traits::source_type S ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static range_check_result apply ( argument_type s )
|
||||
{
|
||||
return s >= static_cast<S>(bounds<T>::highest()) + static_cast<S>(1.0)
|
||||
? cPosOverflow : cInRange ;
|
||||
}
|
||||
} ;
|
||||
|
||||
// s >= Lowest(T) + 0.5 ? cPosgOverflow : cInRange
|
||||
//
|
||||
template<class Traits>
|
||||
struct GT_HalfSuccHiT : applicable
|
||||
{
|
||||
typedef typename Traits::target_type T ;
|
||||
typedef typename Traits::source_type S ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static range_check_result apply ( argument_type s )
|
||||
{
|
||||
return s >= static_cast<S>(bounds<T>::highest()) + static_cast<S>(0.5)
|
||||
? cPosOverflow : cInRange ;
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Predicate Combiner.
|
||||
//
|
||||
// This helper classes are used to possibly combine the range checking logic
|
||||
// individually performed by the predicates
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Applies both predicates: first 'PredA', and if it equals 'cInRange', 'PredB'
|
||||
template<class PredA, class PredB>
|
||||
struct applyBoth
|
||||
{
|
||||
typedef typename PredA::argument_type argument_type ;
|
||||
|
||||
static range_check_result apply ( argument_type s )
|
||||
{
|
||||
range_check_result r = PredA::apply(s) ;
|
||||
if ( r == cInRange )
|
||||
r = PredB::apply(s);
|
||||
return r ;
|
||||
}
|
||||
} ;
|
||||
|
||||
template<class PredA, class PredB>
|
||||
struct combine
|
||||
{
|
||||
typedef applyBoth<PredA,PredB> Both ;
|
||||
typedef void None ;
|
||||
|
||||
typedef typename PredA::do_apply do_applyA ;
|
||||
typedef typename PredB::do_apply do_applyB ;
|
||||
|
||||
typedef typename for_both<do_applyA, do_applyB, Both, PredA, PredB, None>::type type ;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Range Checker classes.
|
||||
//
|
||||
// The following classes are VISIBLE base classes of the user-level converter<> class.
|
||||
// They supply the optimized 'out_of_range()' and 'validate_range()' static member functions
|
||||
// visible in the user interface.
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Dummy range checker.
|
||||
template<class Traits>
|
||||
struct dummy_range_checker
|
||||
{
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static range_check_result out_of_range ( argument_type ) { return cInRange ; }
|
||||
static void validate_range ( argument_type ) {}
|
||||
} ;
|
||||
|
||||
// Generic range checker.
|
||||
//
|
||||
// All the range checking logic for all possible combinations of source and target
|
||||
// can be arranged in terms of one or two predicates, which test overflow on both neg/pos 'sides'
|
||||
// of the ranges.
|
||||
//
|
||||
// These predicates are given here as IsNegOverflow and IsPosOverflow.
|
||||
//
|
||||
template<class Traits, class IsNegOverflow, class IsPosOverflow, class OverflowHandler>
|
||||
struct generic_range_checker
|
||||
{
|
||||
typedef OverflowHandler overflow_handler ;
|
||||
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
static range_check_result out_of_range ( argument_type s )
|
||||
{
|
||||
typedef typename combine<IsNegOverflow,IsPosOverflow>::type Predicate ;
|
||||
|
||||
return Predicate::apply(s);
|
||||
}
|
||||
|
||||
static void validate_range ( argument_type s )
|
||||
{ OverflowHandler()( out_of_range(s) ) ; }
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Selectors for the optimized Range Checker class.
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<class Traits,class OverflowHandler>
|
||||
struct GetRC_Sig2Sig_or_Unsig2Unsig
|
||||
{
|
||||
typedef dummy_range_checker<Traits> Dummy ;
|
||||
|
||||
typedef LT_LoT<Traits> Pred1 ;
|
||||
typedef GT_HiT<Traits> Pred2 ;
|
||||
|
||||
typedef generic_range_checker<Traits,Pred1,Pred2,OverflowHandler> Normal ;
|
||||
|
||||
typedef typename Traits::subranged subranged ;
|
||||
|
||||
typedef typename mpl::if_<subranged,Normal,Dummy>::type type ;
|
||||
} ;
|
||||
|
||||
template<class Traits, class OverflowHandler>
|
||||
struct GetRC_Sig2Unsig
|
||||
{
|
||||
typedef LT_Zero<Traits> Pred1 ;
|
||||
typedef GT_HiT <Traits> Pred2 ;
|
||||
|
||||
typedef generic_range_checker<Traits,Pred1,Pred2,OverflowHandler> ChoiceA ;
|
||||
|
||||
typedef generic_range_checker<Traits,Pred1,non_applicable,OverflowHandler> ChoiceB ;
|
||||
|
||||
typedef typename Traits::target_type T ;
|
||||
typedef typename Traits::source_type S ;
|
||||
|
||||
typedef typename subranged_Unsig2Sig<S,T>::type oposite_subranged ;
|
||||
|
||||
typedef typename mpl::not_<oposite_subranged>::type positively_subranged ;
|
||||
|
||||
typedef typename mpl::if_<positively_subranged,ChoiceA,ChoiceB>::type type ;
|
||||
} ;
|
||||
|
||||
template<class Traits, class OverflowHandler>
|
||||
struct GetRC_Unsig2Sig
|
||||
{
|
||||
typedef GT_HiT<Traits> Pred1 ;
|
||||
|
||||
typedef generic_range_checker<Traits,non_applicable,Pred1,OverflowHandler> type ;
|
||||
} ;
|
||||
|
||||
template<class Traits,class OverflowHandler>
|
||||
struct GetRC_Int2Int
|
||||
{
|
||||
typedef GetRC_Sig2Sig_or_Unsig2Unsig<Traits,OverflowHandler> Sig2SigQ ;
|
||||
typedef GetRC_Sig2Unsig <Traits,OverflowHandler> Sig2UnsigQ ;
|
||||
typedef GetRC_Unsig2Sig <Traits,OverflowHandler> Unsig2SigQ ;
|
||||
typedef Sig2SigQ Unsig2UnsigQ ;
|
||||
|
||||
typedef typename Traits::sign_mixture sign_mixture ;
|
||||
|
||||
typedef typename
|
||||
for_sign_mixture<sign_mixture,Sig2SigQ,Sig2UnsigQ,Unsig2SigQ,Unsig2UnsigQ>::type
|
||||
selector ;
|
||||
|
||||
typedef typename selector::type type ;
|
||||
} ;
|
||||
|
||||
template<class Traits>
|
||||
struct GetRC_Int2Float
|
||||
{
|
||||
typedef dummy_range_checker<Traits> type ;
|
||||
} ;
|
||||
|
||||
template<class Traits, class OverflowHandler, class Float2IntRounder>
|
||||
struct GetRC_Float2Int
|
||||
{
|
||||
typedef LE_PrevLoT <Traits> Pred1 ;
|
||||
typedef GE_SuccHiT <Traits> Pred2 ;
|
||||
typedef LT_HalfPrevLoT<Traits> Pred3 ;
|
||||
typedef GT_HalfSuccHiT<Traits> Pred4 ;
|
||||
typedef GT_HiT <Traits> Pred5 ;
|
||||
typedef LT_LoT <Traits> Pred6 ;
|
||||
|
||||
typedef generic_range_checker<Traits,Pred1,Pred2,OverflowHandler> ToZero ;
|
||||
typedef generic_range_checker<Traits,Pred3,Pred4,OverflowHandler> ToNearest ;
|
||||
typedef generic_range_checker<Traits,Pred1,Pred5,OverflowHandler> ToInf ;
|
||||
typedef generic_range_checker<Traits,Pred6,Pred2,OverflowHandler> ToNegInf ;
|
||||
|
||||
typedef typename Float2IntRounder::round_style round_style ;
|
||||
|
||||
typedef typename for_round_style<round_style,ToZero,ToNearest,ToInf,ToNegInf>::type type ;
|
||||
} ;
|
||||
|
||||
template<class Traits, class OverflowHandler>
|
||||
struct GetRC_Float2Float
|
||||
{
|
||||
typedef dummy_range_checker<Traits> Dummy ;
|
||||
|
||||
typedef LT_LoT<Traits> Pred1 ;
|
||||
typedef GT_HiT<Traits> Pred2 ;
|
||||
|
||||
typedef generic_range_checker<Traits,Pred1,Pred2,OverflowHandler> Normal ;
|
||||
|
||||
typedef typename Traits::subranged subranged ;
|
||||
|
||||
typedef typename mpl::if_<subranged,Normal,Dummy>::type type ;
|
||||
} ;
|
||||
|
||||
template<class Traits, class OverflowHandler, class Float2IntRounder>
|
||||
struct GetRC_BuiltIn2BuiltIn
|
||||
{
|
||||
typedef GetRC_Int2Int<Traits,OverflowHandler> Int2IntQ ;
|
||||
typedef GetRC_Int2Float<Traits> Int2FloatQ ;
|
||||
typedef GetRC_Float2Int<Traits,OverflowHandler,Float2IntRounder> Float2IntQ ;
|
||||
typedef GetRC_Float2Float<Traits,OverflowHandler> Float2FloatQ ;
|
||||
|
||||
typedef typename Traits::int_float_mixture int_float_mixture ;
|
||||
|
||||
typedef typename for_int_float_mixture<int_float_mixture, Int2IntQ, Int2FloatQ, Float2IntQ, Float2FloatQ>::type selector ;
|
||||
|
||||
typedef typename selector::type type ;
|
||||
} ;
|
||||
|
||||
template<class Traits, class OverflowHandler, class Float2IntRounder>
|
||||
struct GetRC
|
||||
{
|
||||
typedef GetRC_BuiltIn2BuiltIn<Traits,OverflowHandler,Float2IntRounder> BuiltIn2BuiltInQ ;
|
||||
|
||||
typedef dummy_range_checker<Traits> Dummy ;
|
||||
|
||||
typedef mpl::identity<Dummy> DummyQ ;
|
||||
|
||||
typedef typename Traits::udt_builtin_mixture udt_builtin_mixture ;
|
||||
|
||||
typedef typename for_udt_builtin_mixture<udt_builtin_mixture,BuiltIn2BuiltInQ,DummyQ,DummyQ,DummyQ>::type selector ;
|
||||
|
||||
typedef typename selector::type type ;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Converter classes.
|
||||
//
|
||||
// The following classes are VISIBLE base classes of the user-level converter<> class.
|
||||
// They supply the optimized 'nearbyint()' and 'convert()' static member functions
|
||||
// visible in the user interface.
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// Trivial Converter : used when (cv-unqualified) T == (cv-unqualified) S
|
||||
//
|
||||
template<class Traits>
|
||||
struct trivial_converter_impl : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type
|
||||
,BOOST_DEDUCED_TYPENAME Traits::result_type
|
||||
>
|
||||
,public dummy_range_checker<Traits>
|
||||
{
|
||||
typedef Traits traits ;
|
||||
|
||||
typedef typename Traits::source_type source_type ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
typedef typename Traits::result_type result_type ;
|
||||
|
||||
static result_type low_level_convert ( argument_type s ) { return s ; }
|
||||
static source_type nearbyint ( argument_type s ) { return s ; }
|
||||
static result_type convert ( argument_type s ) { return s ; }
|
||||
} ;
|
||||
|
||||
|
||||
//
|
||||
// Rounding Converter : used for float to integral conversions.
|
||||
//
|
||||
template<class Traits,class RangeChecker,class RawConverter,class Float2IntRounder>
|
||||
struct rounding_converter : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type
|
||||
,BOOST_DEDUCED_TYPENAME Traits::result_type
|
||||
>
|
||||
,public RangeChecker
|
||||
,public Float2IntRounder
|
||||
,public RawConverter
|
||||
{
|
||||
typedef RangeChecker RangeCheckerBase ;
|
||||
typedef Float2IntRounder Float2IntRounderBase ;
|
||||
typedef RawConverter RawConverterBase ;
|
||||
|
||||
typedef Traits traits ;
|
||||
|
||||
typedef typename Traits::source_type source_type ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
typedef typename Traits::result_type result_type ;
|
||||
|
||||
static result_type convert ( argument_type s )
|
||||
{
|
||||
RangeCheckerBase::validate_range(s);
|
||||
source_type s1 = Float2IntRounderBase::nearbyint(s);
|
||||
return RawConverterBase::low_level_convert(s1);
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
//
|
||||
// Non-Rounding Converter : used for all other conversions.
|
||||
//
|
||||
template<class Traits,class RangeChecker,class RawConverter>
|
||||
struct non_rounding_converter : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type
|
||||
,BOOST_DEDUCED_TYPENAME Traits::result_type
|
||||
>
|
||||
,public RangeChecker
|
||||
,public RawConverter
|
||||
{
|
||||
typedef RangeChecker RangeCheckerBase ;
|
||||
typedef RawConverter RawConverterBase ;
|
||||
|
||||
typedef Traits traits ;
|
||||
|
||||
typedef typename Traits::source_type source_type ;
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
typedef typename Traits::result_type result_type ;
|
||||
|
||||
static source_type nearbyint ( argument_type s ) { return s ; }
|
||||
|
||||
static result_type convert ( argument_type s )
|
||||
{
|
||||
RangeCheckerBase::validate_range(s);
|
||||
return RawConverterBase::low_level_convert(s);
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Selectors for the optimized Converter class.
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<class Traits,class OverflowHandler,class Float2IntRounder,class RawConverter, class UserRangeChecker>
|
||||
struct get_non_trivial_converter
|
||||
{
|
||||
typedef GetRC<Traits,OverflowHandler,Float2IntRounder> InternalRangeCheckerQ ;
|
||||
|
||||
typedef is_same<UserRangeChecker,UseInternalRangeChecker> use_internal_RC ;
|
||||
|
||||
typedef mpl::identity<UserRangeChecker> UserRangeCheckerQ ;
|
||||
|
||||
typedef typename
|
||||
mpl::apply_if<use_internal_RC,InternalRangeCheckerQ,UserRangeCheckerQ>::type
|
||||
RangeChecker ;
|
||||
|
||||
typedef non_rounding_converter<Traits,RangeChecker,RawConverter> NonRounding ;
|
||||
typedef rounding_converter<Traits,RangeChecker,RawConverter,Float2IntRounder> Rounding ;
|
||||
|
||||
typedef mpl::identity<NonRounding> NonRoundingQ ;
|
||||
typedef mpl::identity<Rounding> RoundingQ ;
|
||||
|
||||
typedef typename Traits::int_float_mixture int_float_mixture ;
|
||||
|
||||
typedef typename
|
||||
for_int_float_mixture<int_float_mixture, NonRoundingQ, NonRoundingQ, RoundingQ, NonRoundingQ>::type
|
||||
selector ;
|
||||
|
||||
typedef typename selector::type type ;
|
||||
} ;
|
||||
|
||||
template< class Traits
|
||||
,class OverflowHandler
|
||||
,class Float2IntRounder
|
||||
,class RawConverter
|
||||
,class UserRangeChecker
|
||||
>
|
||||
struct get_converter_impl
|
||||
{
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT( 0x0561 ) )
|
||||
// bcc55 prefers sometimes template parameters to be explicit local types.
|
||||
// (notice that is is illegal to reuse the names like this)
|
||||
typedef Traits Traits ;
|
||||
typedef OverflowHandler OverflowHandler ;
|
||||
typedef Float2IntRounder Float2IntRounder ;
|
||||
typedef RawConverter RawConverter ;
|
||||
typedef UserRangeChecker UserRangeChecker ;
|
||||
#endif
|
||||
|
||||
typedef trivial_converter_impl<Traits> Trivial ;
|
||||
typedef mpl::identity <Trivial> TrivialQ ;
|
||||
|
||||
typedef get_non_trivial_converter< Traits
|
||||
,OverflowHandler
|
||||
,Float2IntRounder
|
||||
,RawConverter
|
||||
,UserRangeChecker
|
||||
> NonTrivialQ ;
|
||||
|
||||
typedef typename Traits::trivial trivial ;
|
||||
|
||||
typedef typename mpl::apply_if<trivial,TrivialQ,NonTrivialQ>::type type ;
|
||||
} ;
|
||||
|
||||
} } } // namespace boost::numeric::convdetail
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_DETAIL_INT_FLOAT_MIXTURE_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_DETAIL_INT_FLOAT_MIXTURE_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/config.hpp"
|
||||
#include "boost/limits.hpp"
|
||||
|
||||
#include "boost/numeric/conversion/int_float_mixture_enum.hpp"
|
||||
#include "boost/numeric/conversion/detail/meta.hpp"
|
||||
|
||||
namespace boost { namespace numeric { namespace convdetail
|
||||
{
|
||||
// Integral Constants for 'IntFloatMixture'
|
||||
typedef mpl::integral_c<int_float_mixture_enum, integral_to_integral> int2int_c ;
|
||||
typedef mpl::integral_c<int_float_mixture_enum, integral_to_float> int2float_c ;
|
||||
typedef mpl::integral_c<int_float_mixture_enum, float_to_integral> float2int_c ;
|
||||
typedef mpl::integral_c<int_float_mixture_enum, float_to_float> float2float_c ;
|
||||
|
||||
// Metafunction:
|
||||
//
|
||||
// get_int_float_mixture<T,S>::type
|
||||
//
|
||||
// Selects the appropriate Int-Float Mixture Integral Constant for the combination T,S.
|
||||
//
|
||||
template<class T,class S>
|
||||
struct get_int_float_mixture
|
||||
{
|
||||
typedef mpl::bool_< ::std::numeric_limits<S>::is_integer > S_int ;
|
||||
typedef mpl::bool_< ::std::numeric_limits<T>::is_integer > T_int ;
|
||||
|
||||
typedef typename
|
||||
for_both<S_int, T_int, int2int_c, int2float_c, float2int_c, float2float_c>::type
|
||||
type ;
|
||||
} ;
|
||||
|
||||
// Metafunction:
|
||||
//
|
||||
// for_int_float_mixture<Mixture,int_int,int_float,float_int,float_float>::type
|
||||
//
|
||||
// {Mixture} is one of the Integral Constants for Mixture, declared above.
|
||||
// {int_int,int_float,float_int,float_float} are aribtrary types. (not metafunctions)
|
||||
//
|
||||
// According to the value of 'IntFloatMixture', selects the corresponding type.
|
||||
//
|
||||
template<class IntFloatMixture, class Int2Int, class Int2Float, class Float2Int, class Float2Float>
|
||||
struct for_int_float_mixture
|
||||
{
|
||||
typedef typename
|
||||
ct_switch4<IntFloatMixture
|
||||
,int2int_c, int2float_c, float2int_c // default
|
||||
,Int2Int , Int2Float , Float2Int , Float2Float
|
||||
>::type
|
||||
type ;
|
||||
} ;
|
||||
|
||||
} } } // namespace boost::numeric::convdetail
|
||||
|
||||
#endif
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_DETAIL_IS_SUBRANGED_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_DETAIL_IS_SUBRANGED_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/config.hpp"
|
||||
#include "boost/limits.hpp"
|
||||
|
||||
#include "boost/mpl/int.hpp"
|
||||
#include "boost/mpl/multiplies.hpp"
|
||||
#include "boost/mpl/less.hpp"
|
||||
#include "boost/mpl/equal_to.hpp"
|
||||
|
||||
#include "boost/type_traits/is_same.hpp"
|
||||
|
||||
#include "boost/numeric/conversion/detail/meta.hpp"
|
||||
#include "boost/numeric/conversion/detail/int_float_mixture.hpp"
|
||||
#include "boost/numeric/conversion/detail/sign_mixture.hpp"
|
||||
#include "boost/numeric/conversion/detail/udt_builtin_mixture.hpp"
|
||||
|
||||
namespace boost { namespace numeric { namespace convdetail
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
// Implementations of the compile time predicate "T is subranged"
|
||||
//---------------------------------------------------------------
|
||||
|
||||
// for integral to integral conversions
|
||||
template<class T,class S>
|
||||
struct subranged_Sig2Unsig
|
||||
{
|
||||
// Signed to unsigned conversions are 'subranged' because of possible loose
|
||||
// of negative values.
|
||||
typedef mpl::true_ type ;
|
||||
} ;
|
||||
|
||||
// for unsigned integral to signed integral conversions
|
||||
template<class T,class S>
|
||||
struct subranged_Unsig2Sig
|
||||
{
|
||||
// IMPORTANT NOTE:
|
||||
//
|
||||
// This code assumes that signed/unsigned integral values are represented
|
||||
// such that:
|
||||
//
|
||||
// numeric_limits<signed T>::digits + 1 == numeric_limits<unsigned T>::digits
|
||||
//
|
||||
// The '+1' is required since numeric_limits<>::digits gives 1 bit less for signed integral types.
|
||||
//
|
||||
// This fact is used by the following logic:
|
||||
//
|
||||
// if ( (numeric_limits<T>::digits+1) < (2*numeric_limits<S>::digits) )
|
||||
// then the conversion is subranged.
|
||||
//
|
||||
|
||||
typedef mpl::int_< ::std::numeric_limits<S>::digits > S_digits ;
|
||||
typedef mpl::int_< ::std::numeric_limits<T>::digits > T_digits ;
|
||||
|
||||
// T is signed, so take digits+1
|
||||
typedef typename T_digits::next u_T_digits ;
|
||||
|
||||
typedef mpl::int_<2> Two ;
|
||||
|
||||
typedef typename mpl::multiplies<S_digits,Two>::type S_digits_times_2 ;
|
||||
|
||||
typedef typename mpl::less<u_T_digits,S_digits_times_2>::type type ;
|
||||
} ;
|
||||
|
||||
// for integral to integral conversions of the same sign.
|
||||
template<class T,class S>
|
||||
struct subranged_SameSign
|
||||
{
|
||||
// An integral conversion of the same sign is subranged if digits(T) < digits(S).
|
||||
|
||||
typedef mpl::int_< ::std::numeric_limits<S>::digits > S_digits ;
|
||||
typedef mpl::int_< ::std::numeric_limits<T>::digits > T_digits ;
|
||||
|
||||
typedef typename mpl::less<T_digits,S_digits>::type type ;
|
||||
} ;
|
||||
|
||||
// for integral to float conversions
|
||||
template<class T,class S>
|
||||
struct subranged_Int2Float
|
||||
{
|
||||
typedef mpl::false_ type ;
|
||||
} ;
|
||||
|
||||
// for float to integral conversions
|
||||
template<class T,class S>
|
||||
struct subranged_Float2Int
|
||||
{
|
||||
typedef mpl::true_ type ;
|
||||
} ;
|
||||
|
||||
// for float to float conversions
|
||||
template<class T,class S>
|
||||
struct subranged_Float2Float
|
||||
{
|
||||
// If both T and S are floats,
|
||||
// compare exponent bits and if they match, mantisa bits.
|
||||
|
||||
typedef mpl::int_< ::std::numeric_limits<S>::digits > S_mantisa ;
|
||||
typedef mpl::int_< ::std::numeric_limits<T>::digits > T_mantisa ;
|
||||
|
||||
typedef mpl::int_< ::std::numeric_limits<S>::max_exponent > S_exponent ;
|
||||
typedef mpl::int_< ::std::numeric_limits<T>::max_exponent > T_exponent ;
|
||||
|
||||
typedef typename mpl::less<T_exponent,S_exponent>::type T_smaller_exponent ;
|
||||
|
||||
typedef typename mpl::equal_to<T_exponent,S_exponent>::type equal_exponents ;
|
||||
|
||||
typedef mpl::less<T_mantisa,S_mantisa> T_smaller_mantisa ;
|
||||
|
||||
typedef mpl::apply_if<equal_exponents,T_smaller_mantisa,mpl::false_> not_bigger_exponent_case ;
|
||||
|
||||
typedef typename
|
||||
mpl::apply_if<T_smaller_exponent,mpl::true_,not_bigger_exponent_case>::type
|
||||
type ;
|
||||
} ;
|
||||
|
||||
// for Udt to built-in conversions
|
||||
template<class T,class S>
|
||||
struct subranged_Udt2BuiltIn
|
||||
{
|
||||
typedef mpl::true_ type ;
|
||||
} ;
|
||||
|
||||
// for built-in to Udt conversions
|
||||
template<class T,class S>
|
||||
struct subranged_BuiltIn2Udt
|
||||
{
|
||||
typedef mpl::false_ type ;
|
||||
} ;
|
||||
|
||||
// for Udt to Udt conversions
|
||||
template<class T,class S>
|
||||
struct subranged_Udt2Udt
|
||||
{
|
||||
typedef mpl::false_ type ;
|
||||
} ;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Selectors for the implementations of the subranged predicate
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
template<class T,class S>
|
||||
struct get_subranged_Int2Int
|
||||
{
|
||||
typedef subranged_SameSign<T,S> Sig2Sig ;
|
||||
typedef subranged_Sig2Unsig<T,S> Sig2Unsig ;
|
||||
typedef subranged_Unsig2Sig<T,S> Unsig2Sig ;
|
||||
typedef Sig2Sig Unsig2Unsig ;
|
||||
|
||||
typedef typename get_sign_mixture<T,S>::type sign_mixture ;
|
||||
|
||||
typedef typename
|
||||
for_sign_mixture<sign_mixture, Sig2Sig, Sig2Unsig, Unsig2Sig, Unsig2Unsig>::type
|
||||
type ;
|
||||
} ;
|
||||
|
||||
template<class T,class S>
|
||||
struct get_subranged_BuiltIn2BuiltIn
|
||||
{
|
||||
typedef get_subranged_Int2Int<T,S> Int2IntQ ;
|
||||
|
||||
typedef subranged_Int2Float <T,S> Int2Float ;
|
||||
typedef subranged_Float2Int <T,S> Float2Int ;
|
||||
typedef subranged_Float2Float<T,S> Float2Float ;
|
||||
|
||||
typedef mpl::identity<Int2Float > Int2FloatQ ;
|
||||
typedef mpl::identity<Float2Int > Float2IntQ ;
|
||||
typedef mpl::identity<Float2Float> Float2FloatQ ;
|
||||
|
||||
typedef typename get_int_float_mixture<T,S>::type int_float_mixture ;
|
||||
|
||||
typedef for_int_float_mixture<int_float_mixture, Int2IntQ, Int2FloatQ, Float2IntQ, Float2FloatQ> for_ ;
|
||||
|
||||
typedef typename for_::type selected ;
|
||||
|
||||
typedef typename selected::type type ;
|
||||
} ;
|
||||
|
||||
template<class T,class S>
|
||||
struct get_subranged
|
||||
{
|
||||
typedef get_subranged_BuiltIn2BuiltIn<T,S> BuiltIn2BuiltInQ ;
|
||||
|
||||
typedef subranged_BuiltIn2Udt<T,S> BuiltIn2Udt ;
|
||||
typedef subranged_Udt2BuiltIn<T,S> Udt2BuiltIn ;
|
||||
typedef subranged_Udt2Udt<T,S> Udt2Udt ;
|
||||
|
||||
typedef mpl::identity<BuiltIn2Udt> BuiltIn2UdtQ ;
|
||||
typedef mpl::identity<Udt2BuiltIn> Udt2BuiltInQ ;
|
||||
typedef mpl::identity<Udt2Udt > Udt2UdtQ ;
|
||||
|
||||
typedef typename get_udt_builtin_mixture<T,S>::type udt_builtin_mixture ;
|
||||
|
||||
typedef typename
|
||||
for_udt_builtin_mixture<udt_builtin_mixture, BuiltIn2BuiltInQ, BuiltIn2UdtQ, Udt2BuiltInQ, Udt2UdtQ>::type
|
||||
selected ;
|
||||
|
||||
typedef typename selected::type selected2 ;
|
||||
|
||||
typedef typename selected2::type type ;
|
||||
} ;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Top level implementation selector.
|
||||
//-------------------------------------------------------------------
|
||||
template<class T, class S>
|
||||
struct get_is_subranged
|
||||
{
|
||||
typedef get_subranged<T,S> non_trivial_case ;
|
||||
typedef mpl::identity<mpl::false_> trivial_case ;
|
||||
|
||||
typedef is_same<T,S> is_trivial ;
|
||||
|
||||
typedef typename mpl::if_<is_trivial,trivial_case,non_trivial_case>::type selected ;
|
||||
|
||||
typedef typename selected::type type ;
|
||||
} ;
|
||||
|
||||
} } } // namespace boost::numeric::convdetail
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_DETAIL_META_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_DETAIL_META_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/type_traits/remove_cv.hpp"
|
||||
|
||||
#include "boost/mpl/if.hpp"
|
||||
#include "boost/mpl/apply_if.hpp"
|
||||
#include "boost/mpl/equal_to.hpp"
|
||||
#include "boost/mpl/not.hpp"
|
||||
#include "boost/mpl/and.hpp"
|
||||
#include "boost/mpl/identity.hpp"
|
||||
|
||||
namespace boost { namespace numeric { namespace convdetail
|
||||
{
|
||||
template<
|
||||
typename BOOST_MPL_AUX_VOID_SPEC_PARAM(T1)
|
||||
, typename BOOST_MPL_AUX_VOID_SPEC_PARAM(T2)
|
||||
>
|
||||
struct equal_to
|
||||
{
|
||||
#if !defined(__BORLANDC__)
|
||||
|
||||
enum { x = ( BOOST_MPL_AUX_VALUE_WKND(T1)::value == BOOST_MPL_AUX_VALUE_WKND(T2)::value ) };
|
||||
|
||||
BOOST_STATIC_CONSTANT(bool, value = x);
|
||||
|
||||
typedef mpl::bool_<value> type;
|
||||
|
||||
#else
|
||||
|
||||
BOOST_STATIC_CONSTANT(bool, value = (
|
||||
BOOST_MPL_AUX_VALUE_WKND(T1)::value
|
||||
== BOOST_MPL_AUX_VALUE_WKND(T2)::value
|
||||
));
|
||||
|
||||
typedef mpl::bool_<(
|
||||
BOOST_MPL_AUX_VALUE_WKND(T1)::value
|
||||
== BOOST_MPL_AUX_VALUE_WKND(T2)::value
|
||||
)> type;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Metafunction:
|
||||
//
|
||||
// ct_switch4<Value,Case0Val,Case1Val,Case2Val,Case0Type,Case1Type,Case2Type,DefaultType>::type
|
||||
//
|
||||
// {Value,Case(X)Val} are Integral Constants (such as: mpl::int_<>)
|
||||
// {Case(X)Type,DefaultType} are arbitrary types. (not metafunctions)
|
||||
//
|
||||
// Returns Case(X)Type if Val==Case(X)Val; DefaultType otherwise.
|
||||
//
|
||||
template<class Value,
|
||||
class Case0Val,
|
||||
class Case1Val,
|
||||
class Case2Val,
|
||||
class Case0Type,
|
||||
class Case1Type,
|
||||
class Case2Type,
|
||||
class DefaultType
|
||||
>
|
||||
struct ct_switch4
|
||||
{
|
||||
typedef mpl::identity<Case0Type> Case0TypeQ ;
|
||||
typedef mpl::identity<Case1Type> Case1TypeQ ;
|
||||
|
||||
typedef equal_to<Value,Case0Val> is_case0 ;
|
||||
typedef equal_to<Value,Case1Val> is_case1 ;
|
||||
typedef equal_to<Value,Case2Val> is_case2 ;
|
||||
|
||||
typedef mpl::if_<is_case2,Case2Type,DefaultType> choose_2_3Q ;
|
||||
typedef mpl::apply_if<is_case1,Case1TypeQ,choose_2_3Q> choose_1_2_3Q ;
|
||||
|
||||
typedef typename
|
||||
mpl::apply_if<is_case0,Case0TypeQ,choose_1_2_3Q>::type
|
||||
type ;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
// Metafunction:
|
||||
//
|
||||
// for_both<expr0,expr1,TT,TF,FT,FF>::type
|
||||
//
|
||||
// {exp0,expr1} are Boolean Integral Constants
|
||||
// {TT,TF,FT,FF} are aribtrary types. (not metafunctions)
|
||||
//
|
||||
// According to the combined boolean value of 'expr0 && expr1', selects the corresponding type.
|
||||
//
|
||||
template<class expr0, class expr1, class TT, class TF, class FT, class FF>
|
||||
struct for_both
|
||||
{
|
||||
typedef mpl::identity<TF> TF_Q ;
|
||||
typedef mpl::identity<TT> TT_Q ;
|
||||
|
||||
typedef typename mpl::not_<expr0>::type not_expr0 ;
|
||||
typedef typename mpl::not_<expr1>::type not_expr1 ;
|
||||
|
||||
typedef typename mpl::and_<expr0,expr1>::type caseTT ;
|
||||
typedef typename mpl::and_<expr0,not_expr1>::type caseTF ;
|
||||
typedef typename mpl::and_<not_expr0,expr1>::type caseFT ;
|
||||
|
||||
typedef mpl::if_<caseFT,FT,FF> choose_FT_FF_Q ;
|
||||
typedef mpl::apply_if<caseTF,TF_Q,choose_FT_FF_Q> choose_TF_FT_FF_Q ;
|
||||
|
||||
typedef typename mpl::apply_if<caseTT,TT_Q,choose_TF_FT_FF_Q>::type type ;
|
||||
} ;
|
||||
|
||||
} } } // namespace boost::numeric::convdetail
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_DETAIL_SIGN_MIXTURE_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_DETAIL_SIGN_MIXTURE_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/config.hpp"
|
||||
#include "boost/limits.hpp"
|
||||
|
||||
#include "boost/numeric/conversion/sign_mixture_enum.hpp"
|
||||
#include "boost/numeric/conversion/detail/meta.hpp"
|
||||
|
||||
namespace boost { namespace numeric { namespace convdetail
|
||||
{
|
||||
// Integral Constants for 'SignMixture'
|
||||
typedef mpl::integral_c<sign_mixture_enum, unsigned_to_unsigned> unsig2unsig_c ;
|
||||
typedef mpl::integral_c<sign_mixture_enum, signed_to_signed> sig2sig_c ;
|
||||
typedef mpl::integral_c<sign_mixture_enum, signed_to_unsigned> sig2unsig_c ;
|
||||
typedef mpl::integral_c<sign_mixture_enum, unsigned_to_signed> unsig2sig_c ;
|
||||
|
||||
// Metafunction:
|
||||
//
|
||||
// get_sign_mixture<T,S>::type
|
||||
//
|
||||
// Selects the appropriate SignMixture Integral Constant for the combination T,S.
|
||||
//
|
||||
template<class T,class S>
|
||||
struct get_sign_mixture
|
||||
{
|
||||
typedef mpl::bool_< ::std::numeric_limits<S>::is_signed > S_signed ;
|
||||
typedef mpl::bool_< ::std::numeric_limits<T>::is_signed > T_signed ;
|
||||
|
||||
typedef typename
|
||||
for_both<S_signed, T_signed, sig2sig_c, sig2unsig_c, unsig2sig_c, unsig2unsig_c>::type
|
||||
type ;
|
||||
} ;
|
||||
|
||||
// Metafunction:
|
||||
//
|
||||
// for_sign_mixture<SignMixture,Sig2Sig,Sig2Unsig,Unsig2Sig,Unsig2Unsig>::type
|
||||
//
|
||||
// {SignMixture} is one of the Integral Constants for SignMixture, declared above.
|
||||
// {Sig2Sig,Sig2Unsig,Unsig2Sig,Unsig2Unsig} are aribtrary types. (not metafunctions)
|
||||
//
|
||||
// According to the value of 'SignMixture', selects the corresponding type.
|
||||
//
|
||||
template<class SignMixture, class Sig2Sig, class Sig2Unsig, class Unsig2Sig, class Unsig2Unsig>
|
||||
struct for_sign_mixture
|
||||
{
|
||||
typedef typename
|
||||
ct_switch4<SignMixture
|
||||
, sig2sig_c, sig2unsig_c, unsig2sig_c // default
|
||||
, Sig2Sig , Sig2Unsig , Unsig2Sig , Unsig2Unsig
|
||||
>::type
|
||||
type ;
|
||||
} ;
|
||||
|
||||
} } } // namespace boost::numeric::convdetail
|
||||
|
||||
#endif
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_DETAIL_UDT_BUILTIN_MIXTURE_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_DETAIL_UDT_BUILTIN_MIXTURE_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/type_traits/is_arithmetic.hpp"
|
||||
|
||||
#include "boost/numeric/conversion/udt_builtin_mixture_enum.hpp"
|
||||
#include "boost/numeric/conversion/detail/meta.hpp"
|
||||
|
||||
namespace boost { namespace numeric { namespace convdetail
|
||||
{
|
||||
// Integral Constants for 'UdtMixture'
|
||||
typedef mpl::integral_c<udt_builtin_mixture_enum, builtin_to_builtin> builtin2builtin_c ;
|
||||
typedef mpl::integral_c<udt_builtin_mixture_enum, builtin_to_udt> builtin2udt_c ;
|
||||
typedef mpl::integral_c<udt_builtin_mixture_enum, udt_to_builtin> udt2builtin_c ;
|
||||
typedef mpl::integral_c<udt_builtin_mixture_enum, udt_to_udt> udt2udt_c ;
|
||||
|
||||
// Metafunction:
|
||||
//
|
||||
// for_udt_mixture<UdtMixture,BuiltIn2BuiltIn,BuiltIn2Udt,Udt2BuiltIn,Udt2Udt>::type
|
||||
//
|
||||
// {UdtMixture} is one of the Integral Constants for UdMixture, declared above.
|
||||
// {BuiltIn2BuiltIn,BuiltIn2Udt,Udt2BuiltIn,Udt2Udt} are aribtrary types. (not metafunctions)
|
||||
//
|
||||
// According to the value of 'UdtMixture', selects the corresponding type.
|
||||
//
|
||||
template<class UdtMixture, class BuiltIn2BuiltIn, class BuiltIn2Udt, class Udt2BuiltIn, class Udt2Udt>
|
||||
struct for_udt_builtin_mixture
|
||||
{
|
||||
typedef typename
|
||||
ct_switch4<UdtMixture
|
||||
, builtin2builtin_c, builtin2udt_c, udt2builtin_c // default
|
||||
, BuiltIn2BuiltIn , BuiltIn2Udt , Udt2BuiltIn , Udt2Udt
|
||||
>::type
|
||||
type ;
|
||||
} ;
|
||||
|
||||
// Metafunction:
|
||||
//
|
||||
// get_udt_mixture<T,S>::type
|
||||
//
|
||||
// Selects the appropriate UdtMixture Integral Constant for the combination T,S.
|
||||
//
|
||||
template<class T,class S>
|
||||
struct get_udt_builtin_mixture
|
||||
{
|
||||
typedef is_arithmetic<S> S_builtin ;
|
||||
typedef is_arithmetic<T> T_builtin ;
|
||||
|
||||
typedef typename
|
||||
for_both<S_builtin, T_builtin, builtin2builtin_c, builtin2udt_c, udt2builtin_c, udt2udt_c>::type
|
||||
type ;
|
||||
} ;
|
||||
|
||||
} } } // namespace boost::numeric::convdetail
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_INT_FLOAT_MIXTURE_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_INT_FLOAT_MIXTURE_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/numeric/conversion/detail/int_float_mixture.hpp"
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
|
||||
template<class T, class S>
|
||||
struct int_float_mixture
|
||||
: convdetail::get_int_float_mixture< BOOST_DEDUCED_TYPENAME remove_cv<T>::type
|
||||
,BOOST_DEDUCED_TYPENAME remove_cv<S>::type
|
||||
>::type {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_INT_FLOAT_MIXTURE_ENUM_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_INT_FLOAT_MIXTURE_ENUM_FLC_12NOV2002_HPP
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
enum int_float_mixture_enum
|
||||
{
|
||||
integral_to_integral
|
||||
,integral_to_float
|
||||
,float_to_integral
|
||||
,float_to_float
|
||||
} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_IS_SUBRANGED_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_IS_SUBRANGED_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/numeric/conversion/detail/is_subranged.hpp"
|
||||
|
||||
namespace boost { namespace numeric {
|
||||
|
||||
template<class T, class S>
|
||||
struct is_subranged
|
||||
: convdetail::get_is_subranged< BOOST_DEDUCED_TYPENAME remove_cv<T>::type
|
||||
,BOOST_DEDUCED_TYPENAME remove_cv<S>::type
|
||||
>::type {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_SIGN_MIXTURE_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_SIGN_MIXTURE_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/numeric/conversion/detail/sign_mixture.hpp"
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
|
||||
template<class T, class S>
|
||||
struct sign_mixture
|
||||
: convdetail::get_sign_mixture< BOOST_DEDUCED_TYPENAME remove_cv<T>::type
|
||||
,BOOST_DEDUCED_TYPENAME remove_cv<S>::type
|
||||
>::type {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_SIGN_MIXTURE_ENUM_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_SIGN_MIXTURE_ENUM_FLC_12NOV2002_HPP
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
enum sign_mixture_enum
|
||||
{
|
||||
unsigned_to_unsigned
|
||||
,signed_to_signed
|
||||
,signed_to_unsigned
|
||||
,unsigned_to_signed
|
||||
} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_UDT_BUILTIN_MIXTURE_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_UDT_BUILTIN_MIXTURE_FLC_12NOV2002_HPP
|
||||
|
||||
#include "boost/numeric/conversion/detail/udt_builtin_mixture.hpp"
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
|
||||
template<class T, class S>
|
||||
struct udt_builtin_mixture
|
||||
: convdetail::get_udt_builtin_mixture< BOOST_DEDUCED_TYPENAME remove_cv<T>::type
|
||||
,BOOST_DEDUCED_TYPENAME remove_cv<S>::type
|
||||
>::type {} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#ifndef BOOST_NUMERIC_CONVERSION_UDT_BUILTIN_MIXTURE_ENUM_FLC_12NOV2002_HPP
|
||||
#define BOOST_NUMERIC_CONVERSION_UDT_BUILTIN_MIXTURE_ENUM_FLC_12NOV2002_HPP
|
||||
|
||||
namespace boost { namespace numeric
|
||||
{
|
||||
enum udt_builtin_mixture_enum
|
||||
{
|
||||
builtin_to_builtin
|
||||
,builtin_to_udt
|
||||
,udt_to_builtin
|
||||
,udt_to_udt
|
||||
} ;
|
||||
|
||||
} } // namespace boost::numeric
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Boost Numeric Conversion Library test Jamfile
|
||||
|
||||
subproject libs/numeric/conversion/test ;
|
||||
|
||||
# bring in rules for testing
|
||||
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
|
||||
include testing.jam ;
|
||||
|
||||
# Make tests run by default.
|
||||
DEPENDS all : test ;
|
||||
|
||||
{
|
||||
# look in BOOST_ROOT for sources first, just in this Jamfile
|
||||
local SEARCH_SOURCE = $(BOOST_ROOT) $(SEARCH_SOURCE) ;
|
||||
|
||||
test-suite numeric_conversion :
|
||||
[ run libs/numeric/conversion/test/bounds_test.cpp ]
|
||||
[ run libs/numeric/conversion/test/traits_test.cpp ]
|
||||
[ run libs/numeric/conversion/test/converter_test.cpp ]
|
||||
[ run libs/numeric/conversion/test/udt_support_test.cpp ]
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#include<typeinfo>
|
||||
#include<iostream>
|
||||
#include<iomanip>
|
||||
|
||||
#include "boost/numeric/conversion/bounds.hpp"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
#include "test_helpers.cpp"
|
||||
|
||||
using namespace std ;
|
||||
using namespace boost ;
|
||||
using namespace numeric ;
|
||||
|
||||
// Test the fields of boost::numeric::bounds<> against the expected values.
|
||||
//
|
||||
template<class T>
|
||||
void test_bounds( T expected_lowest, T expected_highest, T expected_smallest )
|
||||
{
|
||||
T lowest = bounds<T>::lowest () ;
|
||||
T highest = bounds<T>::highest () ;
|
||||
T smallest = bounds<T>::smallest() ;
|
||||
|
||||
BOOST_CHECK_MESSAGE ( lowest == expected_lowest,
|
||||
"bounds<" << typeid(T).name() << ">::lowest() = " << printable(lowest) << ". Expected " << printable(expected_lowest)
|
||||
) ;
|
||||
|
||||
BOOST_CHECK_MESSAGE ( highest == expected_highest,
|
||||
"bounds<" << typeid(T).name() << ">::highest() = " << printable(highest) << ". Expected " << printable(expected_highest)
|
||||
) ;
|
||||
|
||||
BOOST_CHECK_MESSAGE ( smallest == expected_smallest,
|
||||
"bounds<" << typeid(T).name() << ">::smallest() = " << printable(smallest) << ". Expected " << printable(expected_smallest)
|
||||
) ;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void test_bounds_integer( MATCH_FNTPL_ARG(T) )
|
||||
{
|
||||
test_bounds( numeric_limits<T>::min BOOST_PREVENT_MACRO_SUBSTITUTION()
|
||||
, numeric_limits<T>::max BOOST_PREVENT_MACRO_SUBSTITUTION()
|
||||
, static_cast<T>(1)
|
||||
) ;
|
||||
}
|
||||
template<class T>
|
||||
void test_bounds_float( MATCH_FNTPL_ARG(T))
|
||||
{
|
||||
test_bounds( -numeric_limits<T>::max BOOST_PREVENT_MACRO_SUBSTITUTION ()
|
||||
, numeric_limits<T>::max BOOST_PREVENT_MACRO_SUBSTITUTION ()
|
||||
, numeric_limits<T>::min BOOST_PREVENT_MACRO_SUBSTITUTION ()
|
||||
) ;
|
||||
}
|
||||
|
||||
void test_bounds_integers()
|
||||
{
|
||||
test_bounds_integer( SET_FNTPL_ARG(unsigned char) ) ;
|
||||
test_bounds_integer( SET_FNTPL_ARG(signed char) ) ;
|
||||
test_bounds_integer( SET_FNTPL_ARG(char) ) ;
|
||||
test_bounds_integer( SET_FNTPL_ARG(unsigned short) ) ;
|
||||
test_bounds_integer( SET_FNTPL_ARG(short) ) ;
|
||||
test_bounds_integer( SET_FNTPL_ARG(unsigned int) ) ;
|
||||
test_bounds_integer( SET_FNTPL_ARG(int) ) ;
|
||||
test_bounds_integer( SET_FNTPL_ARG(unsigned long) ) ;
|
||||
test_bounds_integer( SET_FNTPL_ARG(long) ) ;
|
||||
}
|
||||
|
||||
void test_bounds_floats()
|
||||
{
|
||||
test_bounds_float( SET_FNTPL_ARG(float) );
|
||||
test_bounds_float( SET_FNTPL_ARG(double) );
|
||||
test_bounds_float( SET_FNTPL_ARG(long double) );
|
||||
}
|
||||
|
||||
void test_bounds()
|
||||
{
|
||||
test_bounds_integers() ;
|
||||
test_bounds_floats () ;
|
||||
}
|
||||
|
||||
|
||||
int test_main( int, char * [] )
|
||||
{
|
||||
cout << setprecision( std::numeric_limits<long double>::digits10 ) ;
|
||||
|
||||
test_bounds();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,522 @@
|
||||
// © Copyright Fernando Luis Cacciola Carballal 2000-2004
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See library home page at http://www.boost.org/libs/numeric/conversion
|
||||
//
|
||||
// Contact the author at: fernando_cacciola@hotmail.com
|
||||
//
|
||||
#include<cstdlib>
|
||||
#include<iostream>
|
||||
#include<iomanip>
|
||||
#include<string>
|
||||
#include<typeinfo>
|
||||
#include<vector>
|
||||
#include<algorithm>
|
||||
|
||||
#include "boost/config.hpp"
|
||||
#include "boost/cstdint.hpp"
|
||||
#include "boost/utility.hpp"
|
||||
|
||||
//
|
||||
// Borland 5.5 lacks the following math overloads
|
||||
//
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, <= 0x551)
|
||||
namespace std
|
||||
{
|
||||
|
||||
inline float ceil (float x) { return std::ceil ( static_cast<double>(x)); }
|
||||
inline float floor (float x) { return std::floor ( static_cast<double>(x)); }
|
||||
inline long double ceil (long double x) { return std::ceill (x); }
|
||||
inline long double floor (long double x) { return std::floorl(x); }
|
||||
|
||||
} // namespace std
|
||||
#endif
|
||||
|
||||
#include "boost/numeric/conversion/converter.hpp"
|
||||
#include "boost/numeric/conversion/cast.hpp"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
#include "test_helpers.cpp"
|
||||
#include "test_helpers2.cpp"
|
||||
#include "test_helpers3.cpp"
|
||||
|
||||
#include "boost/mpl/alias.hpp"
|
||||
|
||||
using std::cout ;
|
||||
|
||||
// A generic 'abs' function.
|
||||
template<class N> inline N absG ( N v )
|
||||
{
|
||||
return v < static_cast<N>(0) ? static_cast<N>(-v) : v ;
|
||||
}
|
||||
template<> inline unsigned char absG<unsigned char> ( unsigned char v ) { return v ; }
|
||||
template<> inline unsigned short absG<unsigned short> ( unsigned short v ) { return v ; }
|
||||
template<> inline unsigned int absG<unsigned int> ( unsigned int v ) { return v ; }
|
||||
template<> inline unsigned long absG<unsigned long> ( unsigned long v ) { return v ; }
|
||||
|
||||
template<class T> inline void unused_variable ( T const& ) {}
|
||||
//
|
||||
// The following function excersizes specific conversions that cover
|
||||
// usual and boundary cases for each relevant combination.
|
||||
//
|
||||
void test_conversions()
|
||||
{
|
||||
using namespace boost ;
|
||||
using namespace numeric ;
|
||||
|
||||
// To help the test found possible bugs a random numbers are used.
|
||||
using std::rand ;
|
||||
|
||||
boost::int16_t v16 ;
|
||||
boost::uint16_t uv16 ;
|
||||
boost::int32_t v32 ;
|
||||
boost::uint32_t uv32 ;
|
||||
|
||||
volatile float fv ; // avoid this to be cached internally in some fpu register
|
||||
volatile double dv ; // avoid this to be cached internally in some fpu register
|
||||
|
||||
//
|
||||
// sample (representative) conversions:
|
||||
//
|
||||
cout << "Testing representative conversions\n";
|
||||
|
||||
// integral to integral
|
||||
|
||||
// signed to signed
|
||||
|
||||
// not subranged
|
||||
v16 = static_cast<boost::int16_t>(rand());
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,boost::int16_t,v16,v16);
|
||||
|
||||
// subranged
|
||||
v16 = static_cast<boost::int16_t>(rand());
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(boost::int16_t,boost::int32_t,v16,v16);
|
||||
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int16_t,boost::int32_t,bounds<boost::int16_t>::highest() + boost::int32_t(1) ) ;
|
||||
TEST_NEG_OVERFLOW_CONVERSION_DEF(boost::int16_t,boost::int32_t,bounds<boost::int16_t>::lowest() - boost::int32_t(1) ) ;
|
||||
|
||||
// signed to unsigned
|
||||
|
||||
// subranged
|
||||
v32 = absG(static_cast<boost::int32_t>(rand()));
|
||||
v16 = absG(static_cast<boost::int16_t>(rand()));
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(boost::uint32_t,boost::int32_t,v32,v32);
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(boost::uint16_t,boost::int32_t,v16,v16);
|
||||
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::uint16_t,boost::int32_t,bounds<boost::uint16_t>::highest() + boost::int32_t(1) ) ;
|
||||
TEST_NEG_OVERFLOW_CONVERSION_DEF(boost::uint32_t,boost::int32_t,boost::int32_t(-1) ) ;
|
||||
|
||||
// unsigned to signed
|
||||
|
||||
// not subranged
|
||||
v32 = absG(static_cast<boost::int32_t>(rand()));
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,boost::uint32_t,v32,v32);
|
||||
|
||||
// subranged
|
||||
v16 = absG(static_cast<boost::int16_t>(rand()));
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(boost::int16_t,boost::uint32_t,v16,v16);
|
||||
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int32_t,boost::uint32_t,bounds<boost::uint32_t>::highest() ) ;
|
||||
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int16_t,boost::uint32_t,bounds<boost::uint32_t>::highest() ) ;
|
||||
|
||||
// unsigned to unsigned
|
||||
|
||||
// not subranged
|
||||
uv16 = static_cast<boost::uint16_t>(rand());
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(boost::uint32_t,boost::uint16_t,uv16,uv16);
|
||||
|
||||
// subranged
|
||||
uv16 = static_cast<boost::uint16_t>(rand());
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(boost::uint16_t,boost::uint32_t,uv16,uv16);
|
||||
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::uint16_t,boost::uint32_t,bounds<boost::uint32_t>::highest() ) ;
|
||||
|
||||
// integral to float
|
||||
|
||||
// from signed integral
|
||||
v32 = static_cast<boost::int32_t>(rand());
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(double,boost::int32_t,v32,v32);
|
||||
|
||||
// from uint32_tegral
|
||||
uv32 = static_cast<boost::uint32_t>(rand());
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(double,boost::uint32_t,uv32,uv32);
|
||||
|
||||
// float to integral
|
||||
|
||||
// to signed integral
|
||||
v32 = static_cast<boost::int32_t>(rand());
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,double,v32,v32);
|
||||
|
||||
dv = static_cast<double>(bounds<boost::uint32_t>::highest()) + 1.0 ;
|
||||
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int32_t,double,dv) ;
|
||||
TEST_NEG_OVERFLOW_CONVERSION_DEF(boost::int32_t,double,-dv) ;
|
||||
|
||||
// float to float
|
||||
|
||||
// not subranged
|
||||
fv = static_cast<float>(rand()) / static_cast<float>(3) ;
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(double,float,fv,fv);
|
||||
|
||||
|
||||
// subranged
|
||||
fv = static_cast<float>(rand()) / static_cast<float>(3) ;
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(float,double,fv,fv);
|
||||
TEST_POS_OVERFLOW_CONVERSION_DEF(float,double,bounds<double>::highest()) ;
|
||||
TEST_NEG_OVERFLOW_CONVERSION_DEF(float,double,bounds<double>::lowest ()) ;
|
||||
}
|
||||
|
||||
// Custom OverflowHandler
|
||||
struct custom_overflow_handler
|
||||
{
|
||||
void operator() ( boost::numeric::range_check_result r )
|
||||
{
|
||||
if ( r == boost::numeric::cNegOverflow )
|
||||
cout << "negative_overflow detected!\n" ;
|
||||
else if ( r == boost::numeric::cPosOverflow )
|
||||
cout << "positive_overflow detected!\n" ;
|
||||
}
|
||||
} ;
|
||||
|
||||
template<class T, class S,class OverflowHandler>
|
||||
void test_overflow_handler( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S), MATCH_FNTPL_ARG(OverflowHandler),
|
||||
PostCondition pos,
|
||||
PostCondition neg
|
||||
)
|
||||
{
|
||||
typedef boost::numeric::conversion_traits<T,S> traits ;
|
||||
typedef boost::numeric::converter<T,S,traits,OverflowHandler> converter ;
|
||||
|
||||
static const S psrc = boost::numeric::bounds<S>::highest();
|
||||
static const S nsrc = boost::numeric::bounds<S>::lowest ();
|
||||
|
||||
static const T pres = static_cast<T>(psrc);
|
||||
static const T nres = static_cast<T>(nsrc);
|
||||
|
||||
test_conv_base ( ConversionInstance<converter>(pres,psrc,pos) ) ;
|
||||
test_conv_base ( ConversionInstance<converter>(nres,nsrc,neg) ) ;
|
||||
}
|
||||
|
||||
template<class T, class S>
|
||||
void test_overflow_handlers( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S) )
|
||||
{
|
||||
cout << "Testing Silent Overflow Handler policy\n";
|
||||
|
||||
test_overflow_handler( SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(S),
|
||||
SET_FNTPL_ARG(boost::numeric::silent_overflow_handler),
|
||||
c_converted,
|
||||
c_converted
|
||||
) ;
|
||||
|
||||
cout << "Testing Default Overflow Handler policy\n";
|
||||
|
||||
test_overflow_handler( SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(S),
|
||||
SET_FNTPL_ARG(boost::numeric::def_overflow_handler),
|
||||
c_pos_overflow,
|
||||
c_neg_overflow
|
||||
) ;
|
||||
|
||||
cout << "Testing Custom (User-Defined) Overflow Handler policy\n";
|
||||
|
||||
test_overflow_handler( SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(S),
|
||||
SET_FNTPL_ARG(custom_overflow_handler),
|
||||
c_converted,
|
||||
c_converted
|
||||
) ;
|
||||
}
|
||||
|
||||
// For a given float-type number 'n' of integer value (n.0), check the conversions
|
||||
// within the range [n-1,n+1] taking values at: (n-1,n-0.5,n,n+0.5,n+1).
|
||||
// For each sampled value there is an expected result and a PostCondition according to the
|
||||
// specified round_style.
|
||||
//
|
||||
template<class T, class S, class Float2IntRounder>
|
||||
void test_rounding_conversion ( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(Float2IntRounder),
|
||||
S s,
|
||||
PostCondition resl1,
|
||||
PostCondition resl0,
|
||||
PostCondition res,
|
||||
PostCondition resr0,
|
||||
PostCondition resr1
|
||||
)
|
||||
{
|
||||
typedef boost::numeric::conversion_traits<T,S> Traits ;
|
||||
|
||||
typedef boost::numeric::converter<T,S, Traits, boost::numeric::def_overflow_handler,Float2IntRounder>
|
||||
Converter ;
|
||||
|
||||
S sl1 = s - static_cast<S>(1);
|
||||
S sl0 = s - static_cast<S>(0.5);
|
||||
S sr0 = s + static_cast<S>(0.5);
|
||||
S sr1 = s + static_cast<S>(1);
|
||||
|
||||
T tl1 = static_cast<T>( Converter::nearbyint(sl1) );
|
||||
T tl0 = static_cast<T>( Converter::nearbyint(sl0) );
|
||||
T t = static_cast<T>( Converter::nearbyint(s) );
|
||||
T tr0 = static_cast<T>( Converter::nearbyint(sr0) );
|
||||
T tr1 = static_cast<T>( Converter::nearbyint(sr1) );
|
||||
|
||||
test_conv_base ( ConversionInstance<Converter>(tl1,sl1,resl1) ) ;
|
||||
test_conv_base ( ConversionInstance<Converter>(tl0,sl0,resl0) ) ;
|
||||
test_conv_base ( ConversionInstance<Converter>(t,s,res) ) ;
|
||||
test_conv_base ( ConversionInstance<Converter>(tr0,sr0,resr0) ) ;
|
||||
test_conv_base ( ConversionInstance<Converter>(tr1,sr1,resr1) ) ;
|
||||
}
|
||||
|
||||
|
||||
template<class T,class S>
|
||||
void test_round_style( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S) )
|
||||
{
|
||||
S min = boost::numeric::bounds<T>::lowest();
|
||||
S max = boost::numeric::bounds<T>::highest();
|
||||
|
||||
cout << "Testing 'Trunc' Float2IntRounder policy\n";
|
||||
|
||||
test_rounding_conversion(SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(boost::numeric::Trunc<S>),
|
||||
min,
|
||||
c_neg_overflow,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted
|
||||
) ;
|
||||
|
||||
test_rounding_conversion(SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(boost::numeric::Trunc<S>),
|
||||
max,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_pos_overflow
|
||||
) ;
|
||||
|
||||
cout << "Testing 'RoundEven' Float2IntRounder policy\n";
|
||||
|
||||
test_rounding_conversion(SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(boost::numeric::RoundEven<S>),
|
||||
min,
|
||||
c_neg_overflow,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted
|
||||
) ;
|
||||
|
||||
test_rounding_conversion(SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(boost::numeric::RoundEven<S>),
|
||||
max,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_pos_overflow,
|
||||
c_pos_overflow
|
||||
) ;
|
||||
|
||||
cout << "Testing 'Ceil' Float2IntRounder policy\n";
|
||||
|
||||
test_rounding_conversion(SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(boost::numeric::Ceil<S>),
|
||||
min,
|
||||
c_neg_overflow,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted
|
||||
) ;
|
||||
|
||||
test_rounding_conversion(SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(boost::numeric::Ceil<S>),
|
||||
max,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_pos_overflow,
|
||||
c_pos_overflow
|
||||
) ;
|
||||
|
||||
cout << "Testing 'Floor' Float2IntRounder policy\n" ;
|
||||
|
||||
test_rounding_conversion(SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(boost::numeric::Floor<S>),
|
||||
min,
|
||||
c_neg_overflow,
|
||||
c_neg_overflow,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted
|
||||
) ;
|
||||
|
||||
test_rounding_conversion(SET_FNTPL_ARG(T),
|
||||
SET_FNTPL_ARG(boost::numeric::Floor<S>),
|
||||
max,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_converted,
|
||||
c_pos_overflow
|
||||
) ;
|
||||
|
||||
}
|
||||
|
||||
int double_to_int ( double n ) { return static_cast<int>(n) ; }
|
||||
|
||||
void test_converter_as_function_object()
|
||||
{
|
||||
cout << "Testing converter as function object.\n";
|
||||
|
||||
// Create a sample sequence of double values.
|
||||
std::vector<double> S ;
|
||||
for ( int i = 0 ; i < 10 ; ++ i )
|
||||
S.push_back( i * ( 18.0 / 19.0 ) );
|
||||
|
||||
// Create a sequence of int values from 's' using the standard conversion.
|
||||
std::vector<int> W ;
|
||||
std::transform(S.begin(),S.end(),std::back_inserter(W),double_to_int);
|
||||
|
||||
// Create a sequence of int values from s using a default numeric::converter
|
||||
std::vector<int> I ;
|
||||
std::transform(S.begin(),
|
||||
S.end(),
|
||||
std::back_inserter(I),
|
||||
boost::numeric::converter<int,double>()
|
||||
) ;
|
||||
|
||||
// Match 'w' and 'i' which should be equal.
|
||||
bool double_to_int_OK = std::equal(W.begin(),W.end(),I.begin()) ;
|
||||
BOOST_CHECK_MESSAGE(double_to_int_OK, "converter (int,double) as function object");
|
||||
|
||||
// Create a sequence of double values from s using a default numeric::converter (which should be the trivial conv).
|
||||
std::vector<double> D ;
|
||||
std::transform(S.begin(),
|
||||
S.end(),
|
||||
std::back_inserter(D),
|
||||
boost::numeric::converter<double,double>()
|
||||
) ;
|
||||
|
||||
// Match 's' and 'd' which should be equal.
|
||||
bool double_to_double_OK = std::equal(S.begin(),S.end(),D.begin()) ;
|
||||
BOOST_CHECK_MESSAGE(double_to_double_OK, "converter (double,double) as function object");
|
||||
}
|
||||
|
||||
#define UNOPTIMIZED volatile
|
||||
|
||||
void test_optimizations()
|
||||
{
|
||||
using namespace boost;
|
||||
using namespace numeric;
|
||||
|
||||
float fv0 = 18.0f / 19.0f ;
|
||||
|
||||
// This code deosn't produce any output.
|
||||
// It is intended to show the optimization of numeric::converter<> by manual inspection
|
||||
// of the generated code.
|
||||
// Each test shows first the equivalent hand-coded version.
|
||||
// The numeric_cast<> code should be the same if full compiler optimization/inlining is used.
|
||||
|
||||
//---------------------------------
|
||||
// trivial conversion.
|
||||
//
|
||||
// equivalent code:
|
||||
UNOPTIMIZED float fv1a = fv0 ;
|
||||
|
||||
float fv1b = numeric_cast<float>(fv0);
|
||||
unused_variable(fv1a);
|
||||
unused_variable(fv1b);
|
||||
//
|
||||
//---------------------------------
|
||||
|
||||
//---------------------------------
|
||||
// nonsubranged conversion.
|
||||
//
|
||||
// equivalent code:
|
||||
UNOPTIMIZED double dv1a = static_cast<double>(fv0);
|
||||
|
||||
double dv1b = numeric_cast<double>(fv0);
|
||||
unused_variable(dv1a);
|
||||
unused_variable(dv1b);
|
||||
//
|
||||
//---------------------------------
|
||||
|
||||
//------------------------------------------------------
|
||||
// subranged conversion with both-sided range checking.
|
||||
//
|
||||
|
||||
// equivalent code:
|
||||
|
||||
{
|
||||
double const& s = dv1b ;
|
||||
// range checking
|
||||
range_check_result r = s < static_cast<double>(bounds<float>::lowest())
|
||||
? cNegOverflow : cInRange ;
|
||||
if ( r == cInRange )
|
||||
{
|
||||
r = s > static_cast<double>(bounds<float>::highest()) ? cPosOverflow : cInRange ;
|
||||
}
|
||||
if ( r == cNegOverflow )
|
||||
throw negative_overflow() ;
|
||||
else if ( r == cPosOverflow )
|
||||
throw positive_overflow() ;
|
||||
// conversion
|
||||
UNOPTIMIZED float fv2a = static_cast<float>(s);
|
||||
unused_variable(fv2a);
|
||||
}
|
||||
|
||||
float fv2b = numeric_cast<float>(dv1b);
|
||||
unused_variable(fv2b);
|
||||
//
|
||||
//---------------------------------
|
||||
|
||||
|
||||
//---------------------------------
|
||||
// subranged rounding conversion
|
||||
//
|
||||
// equivalent code:
|
||||
|
||||
{
|
||||
double const& s = dv1b ;
|
||||
// range checking
|
||||
range_check_result r = s <= static_cast<double>(bounds<int>::lowest()) - static_cast<double>(1.0)
|
||||
? cNegOverflow : cInRange ;
|
||||
if ( r == cInRange )
|
||||
{
|
||||
r = s >= static_cast<double>(bounds<int>::highest()) + static_cast<double>(1.0)
|
||||
? cPosOverflow : cInRange ;
|
||||
}
|
||||
if ( r == cNegOverflow )
|
||||
throw negative_overflow() ;
|
||||
else if ( r == cPosOverflow )
|
||||
throw positive_overflow() ;
|
||||
// rounding
|
||||
using std::floor ;
|
||||
double s1 = floor(dv1b + 0.5);
|
||||
|
||||
// conversion
|
||||
UNOPTIMIZED int iv1a = static_cast<int>(s1);
|
||||
unused_variable(iv1a);
|
||||
}
|
||||
|
||||
int iv1b = numeric_cast<int>(dv1b);
|
||||
unused_variable(iv1b);
|
||||
//
|
||||
//---------------------------------
|
||||
}
|
||||
|
||||
int test_main( int, char* argv[] )
|
||||
{
|
||||
std::cout << std::setprecision( std::numeric_limits<long double>::digits10 ) ;
|
||||
|
||||
test_conversions();
|
||||
test_overflow_handlers( SET_FNTPL_ARG(boost::int16_t), SET_FNTPL_ARG(boost::int32_t));
|
||||
test_round_style (SET_FNTPL_ARG(boost::int32_t), SET_FNTPL_ARG(double) ) ;
|
||||
test_converter_as_function_object();
|
||||
test_optimizations() ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
//
|
||||
// This material is provided "as is", with absolutely no warranty expressed
|
||||
// or implied. Any use is at your own risk.
|
||||
//
|
||||
// Permission to use or copy this software for any purpose is hereby granted
|
||||
// without fee, provided the above notices are retained on all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted,
|
||||
// provided the above notices are retained, and a notice that the code was
|
||||
// modified is included with the above copyright notice.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// NOTE: This file is intended to be used ONLY by the test files
|
||||
// from the Numeric Conversions Library
|
||||
//
|
||||
//
|
||||
#include "boost/compatibility/cpp_c_headers/cmath"
|
||||
|
||||
#include "boost/limits.hpp"
|
||||
#include "boost/utility.hpp"
|
||||
|
||||
#include "boost/test/included/test_exec_monitor.hpp"
|
||||
|
||||
// Convenience macros to help with compilers which don't parse
|
||||
// explicit template function instantiations (MSVC6)
|
||||
#define MATCH_FNTPL_ARG(t) t const*
|
||||
#define SET_FNTPL_ARG(t) (static_cast< t const* >(0))
|
||||
|
||||
//
|
||||
// *Minimal* example of a User Defined Numeric Type
|
||||
//
|
||||
//
|
||||
namespace MyUDT
|
||||
{
|
||||
|
||||
template<class T>
|
||||
struct UDT
|
||||
{
|
||||
typedef T builtin_type ;
|
||||
|
||||
UDT ( T v_ ) : v (v_) {}
|
||||
|
||||
T to_builtin() const { return v ; }
|
||||
|
||||
friend bool operator == ( UDT const& lhs, UDT const& rhs )
|
||||
{ return lhs.to_builtin() == rhs.to_builtin() ; }
|
||||
|
||||
// NOTE: This operator is *required* by the Numeric Conversion Library
|
||||
// if Turnc<> is used as the Float2IntRounder policy.
|
||||
friend bool operator < ( UDT const& lhs, UDT const& rhs )
|
||||
{ return lhs.to_builtin() < rhs.to_builtin() ; }
|
||||
|
||||
friend std::ostream& operator << ( std::ostream& os, UDT const& n )
|
||||
{ return os << n.to_builtin() ; }
|
||||
|
||||
T v ;
|
||||
} ;
|
||||
|
||||
typedef UDT<int> MyInt ;
|
||||
typedef UDT<double> MyFloat ;
|
||||
|
||||
//
|
||||
// The Float2IntRounder policies *require* a visible 'ceil' or 'floor' math function
|
||||
// with standard semantics.
|
||||
// In a conformant compiler, ADL can pick these functions even if they are defined
|
||||
// within a user namespace, as below.
|
||||
//
|
||||
inline MyInt ceil ( MyInt const& x ) { return x ; }
|
||||
inline MyInt floor ( MyInt const& x ) { return x ; }
|
||||
|
||||
inline MyFloat floor ( MyFloat const& x )
|
||||
{
|
||||
return MyFloat ( std::floor(x.to_builtin()) ) ;
|
||||
}
|
||||
|
||||
inline MyFloat ceil ( MyFloat const& x )
|
||||
{
|
||||
return MyFloat ( std::ceil(x.to_builtin()) ) ;
|
||||
}
|
||||
|
||||
} // namespace MyUDT
|
||||
|
||||
|
||||
//
|
||||
// The Numeric Conversion Library *requires* User Defined Numeric Types
|
||||
// to properly specialize std::numeric_limits<>
|
||||
//
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<>
|
||||
class numeric_limits<MyUDT::MyInt> : public numeric_limits<int>
|
||||
{
|
||||
public :
|
||||
|
||||
BOOST_STATIC_CONSTANT(bool, is_specialized = false);
|
||||
} ;
|
||||
|
||||
template<>
|
||||
class numeric_limits<MyUDT::MyFloat> : public numeric_limits<double>
|
||||
{
|
||||
public :
|
||||
|
||||
BOOST_STATIC_CONSTANT(bool, is_specialized = false);
|
||||
} ;
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The functions floor and ceil defined within namespace MyUDT
|
||||
// should be found by koenig loopkup, but some compilers don't do it right
|
||||
// so we inyect them into namespace std so ordinary overload resolution
|
||||
// can found them.
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || defined(__BORLANDC__) || defined(__GNUC__)
|
||||
namespace std {
|
||||
using MyUDT::floor ;
|
||||
using MyUDT::ceil ;
|
||||
} // namespace std
|
||||
#endif
|
||||
|
||||
|
||||
std::string to_string( bool arg )
|
||||
{
|
||||
return arg ? "true" : "false" ;
|
||||
}
|
||||
|
||||
std::string to_string( ... ) { throw std::runtime_error("to_string() called with wrong type!") ; }
|
||||
|
||||
//
|
||||
// This is used to print 'char' values as numbers instead of characters.
|
||||
//
|
||||
template<class T> struct printable_number_type { typedef T type ; } ;
|
||||
template<> struct printable_number_type<signed char> { typedef int type ; } ;
|
||||
template<> struct printable_number_type<unsigned char> { typedef unsigned type ; } ;
|
||||
template<> struct printable_number_type<char> { typedef int type ; } ;
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
typename printable_number_type<T>::type
|
||||
printable( T n ) { return n ; }
|
||||
|
||||
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
//
|
||||
// This material is provided "as is", with absolutely no warranty expressed
|
||||
// or implied. Any use is at your own risk.
|
||||
//
|
||||
// Permission to use or copy this software for any purpose is hereby granted
|
||||
// without fee, provided the above notices are retained on all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted,
|
||||
// provided the above notices are retained, and a notice that the code was
|
||||
// modified is included with the above copyright notice.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// NOTE: This file is intended to be used ONLY by the test files
|
||||
// from the Numeric Conversions Library
|
||||
//
|
||||
|
||||
//
|
||||
// The following 'to_string' helpers are provided to give readable names
|
||||
// to the various enums used by the library.
|
||||
// NOTE: specializations of boost::lexical_cast<> were not used since some compilers had
|
||||
// trouble dealing with such specializations for different enumerations.
|
||||
//
|
||||
#ifdef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
std::string to_string ( int arg )
|
||||
{
|
||||
return MAKESTR(arg);
|
||||
}
|
||||
#else
|
||||
std::string to_string ( boost::numeric::int_float_mixture_enum arg )
|
||||
{
|
||||
switch ( arg )
|
||||
{
|
||||
case boost::numeric::integral_to_integral : return "integral_to_integral" ;
|
||||
case boost::numeric::integral_to_float : return "integral_to_float" ;
|
||||
case boost::numeric::float_to_integral : return "float_to_integral" ;
|
||||
case boost::numeric::float_to_float : return "float_to_float" ;
|
||||
}
|
||||
return "(Unknown result!)" ;
|
||||
}
|
||||
|
||||
|
||||
std::string to_string ( boost::numeric::sign_mixture_enum arg )
|
||||
{
|
||||
switch ( arg )
|
||||
{
|
||||
case boost::numeric::unsigned_to_unsigned : return "unsigned_to_unsigned" ;
|
||||
case boost::numeric::signed_to_signed : return "signed_to_signed" ;
|
||||
case boost::numeric::signed_to_unsigned : return "signed_to_unsigned" ;
|
||||
case boost::numeric::unsigned_to_signed : return "unsigned_to_signed" ;
|
||||
}
|
||||
return "(Unknown result!)" ;
|
||||
}
|
||||
|
||||
std::string to_string ( boost::numeric::udt_builtin_mixture_enum arg )
|
||||
{
|
||||
switch ( arg )
|
||||
{
|
||||
case boost::numeric::builtin_to_builtin : return "builtin_to_builtin" ;
|
||||
case boost::numeric::builtin_to_udt : return "builtin_to_udt" ;
|
||||
case boost::numeric::udt_to_builtin : return "udt_to_builtin" ;
|
||||
case boost::numeric::udt_to_udt : return "udt_to_udt" ;
|
||||
}
|
||||
return "(Unknown result!)" ;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
// (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
//
|
||||
// This material is provided "as is", with absolutely no warranty expressed
|
||||
// or implied. Any use is at your own risk.
|
||||
//
|
||||
// Permission to use or copy this software for any purpose is hereby granted
|
||||
// without fee, provided the above notices are retained on all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted,
|
||||
// provided the above notices are retained, and a notice that the code was
|
||||
// modified is included with the above copyright notice.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// NOTE: This file is intended to be used ONLY by the test files
|
||||
// from the Numeric Conversions Library
|
||||
//
|
||||
|
||||
// The conversion test is performed using a class whose instances encapsulate
|
||||
// a particular specific conversion defnied explicitely.
|
||||
// A ConversionInstance object includes the source type, the target type,
|
||||
// the source value and the expected result, including possible exceptions.
|
||||
//
|
||||
|
||||
enum PostCondition { c_converted, c_overflow, c_neg_overflow, c_pos_overflow } ;
|
||||
|
||||
template<class Converter>
|
||||
struct ConversionInstance : boost::noncopyable
|
||||
{
|
||||
typedef Converter converter ;
|
||||
|
||||
typedef typename Converter::argument_type argument_type ;
|
||||
typedef typename Converter::result_type result_type ;
|
||||
|
||||
ConversionInstance ( result_type a_result, argument_type a_source, PostCondition a_post)
|
||||
:
|
||||
source(a_source),
|
||||
result(a_result),
|
||||
post(a_post)
|
||||
{}
|
||||
|
||||
std::string to_string() const
|
||||
{
|
||||
return std::string("converter<")
|
||||
+ typeid( typename Converter::traits::target_type).name()
|
||||
+ std::string(",")
|
||||
+ typeid( typename Converter::traits::source_type).name()
|
||||
+ std::string(">::convert(") ;
|
||||
}
|
||||
|
||||
argument_type source ;
|
||||
result_type result ;
|
||||
PostCondition post ;
|
||||
} ;
|
||||
|
||||
//
|
||||
// Main conversion test point.
|
||||
// Exercises a specific conversion described by 'conv'.
|
||||
//
|
||||
template<class Instance>
|
||||
void test_conv_base( Instance const& conv )
|
||||
{
|
||||
typedef typename Instance::argument_type argument_type ;
|
||||
typedef typename Instance::result_type result_type ;
|
||||
|
||||
argument_type source = conv.source ;
|
||||
|
||||
try
|
||||
{
|
||||
result_type result = Instance::converter::convert(source);
|
||||
|
||||
if ( conv.post == c_converted )
|
||||
{
|
||||
BOOST_CHECK_MESSAGE( result == conv.result,
|
||||
conv.to_string() << printable(source) << ")= " << printable(result) << ". Expected:" << printable(conv.result)
|
||||
) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ERROR( conv.to_string() << printable(source) << ") = " << printable(result)
|
||||
<< ". Expected:" << ( conv.post == c_neg_overflow ? " negative_overflow" : "positive_overflow" )
|
||||
) ;
|
||||
}
|
||||
}
|
||||
catch ( boost::numeric::negative_overflow const& )
|
||||
{
|
||||
if ( conv.post == c_neg_overflow )
|
||||
{
|
||||
BOOST_CHECK_MESSAGE( true, conv.to_string() << printable(source) << ") = negative_overflow, as expected" ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ERROR( conv.to_string() << printable(source) << ") = negative_overflow. Expected:" << printable(conv.result) ) ;
|
||||
}
|
||||
}
|
||||
catch ( boost::numeric::positive_overflow const& )
|
||||
{
|
||||
if ( conv.post == c_pos_overflow )
|
||||
{
|
||||
BOOST_CHECK_MESSAGE( true, conv.to_string() << printable(source) << ") = positive_overflow, as expected" ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ERROR( conv.to_string() << printable(source) << ") = positive_overflow. Expected:" << printable(conv.result) ) ;
|
||||
}
|
||||
}
|
||||
catch ( boost::numeric::bad_numeric_conversion const& )
|
||||
{
|
||||
if ( conv.post == c_overflow )
|
||||
{
|
||||
BOOST_CHECK_MESSAGE( true, conv.to_string() << printable(source) << ") = bad_numeric_conversion, as expected" ) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ERROR( conv.to_string() << printable(source) << ") = bad_numeric_cast. Expected:" << printable(conv.result) ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define TEST_SUCCEEDING_CONVERSION(Conv,typeT,typeS,valueT,valueS) \
|
||||
test_conv_base( ConversionInstance< Conv >(valueT, valueS, c_converted ) )
|
||||
|
||||
#define TEST_POS_OVERFLOW_CONVERSION(Conv,typeT,typeS,valueS) \
|
||||
test_conv_base( ConversionInstance< Conv >( static_cast< typeT >(0), valueS, c_pos_overflow ) )
|
||||
|
||||
#define TEST_NEG_OVERFLOW_CONVERSION(Conv,typeT,typeS,valueS) \
|
||||
test_conv_base( ConversionInstance< Conv >( static_cast< typeT >(0), valueS, c_neg_overflow ) )
|
||||
|
||||
#define DEF_CONVERTER(T,S) boost::numeric::converter< T , S >
|
||||
|
||||
#define TEST_SUCCEEDING_CONVERSION_DEF(typeT,typeS,valueT,valueS) \
|
||||
TEST_SUCCEEDING_CONVERSION( DEF_CONVERTER(typeT,typeS), typeT, typeS, valueT, valueS )
|
||||
|
||||
#define TEST_POS_OVERFLOW_CONVERSION_DEF(typeT,typeS,valueS) \
|
||||
TEST_POS_OVERFLOW_CONVERSION( DEF_CONVERTER(typeT,typeS), typeT, typeS, valueS )
|
||||
|
||||
#define TEST_NEG_OVERFLOW_CONVERSION_DEF(typeT,typeS,valueS) \
|
||||
TEST_NEG_OVERFLOW_CONVERSION( DEF_CONVERTER(typeT,typeS), typeT, typeS, valueS )
|
||||
|
||||
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
// (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
//
|
||||
// This material is provided "as is", with absolutely no warranty expressed
|
||||
// or implied. Any use is at your own risk.
|
||||
//
|
||||
// Permission to use or copy this software for any purpose is hereby granted
|
||||
// without fee, provided the above notices are retained on all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted,
|
||||
// provided the above notices are retained, and a notice that the code was
|
||||
// modified is included with the above copyright notice.
|
||||
//
|
||||
//
|
||||
#include<iostream>
|
||||
#include<iomanip>
|
||||
#include<string>
|
||||
#include<typeinfo>
|
||||
#include<vector>
|
||||
#include<algorithm>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
|
||||
#include <boost/numeric/conversion/conversion_traits.hpp>
|
||||
#include <boost/numeric/conversion/int_float_mixture.hpp>
|
||||
#include <boost/numeric/conversion/sign_mixture.hpp>
|
||||
#include <boost/numeric/conversion/udt_builtin_mixture.hpp>
|
||||
#include <boost/numeric/conversion/is_subranged.hpp>
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
#include "test_helpers.cpp"
|
||||
#include "test_helpers2.cpp"
|
||||
|
||||
using namespace std ;
|
||||
using namespace boost ;
|
||||
using namespace numeric;
|
||||
using namespace MyUDT ;
|
||||
|
||||
// These helpers are used by generate_expected_traits<T,S>.
|
||||
// Unlike the similar helpers in the implementation, they are specialized by extension.
|
||||
//
|
||||
template<class T, class S> struct my_is_subranged ;
|
||||
template<class T, class S> struct my_is_trivial ;
|
||||
template<class T, class S> struct my_int_float_mixture ;
|
||||
template<class T, class S> struct my_sign_mixture ;
|
||||
template<class T, class S> struct my_udt_builtin_mixture ;
|
||||
|
||||
// This macro is used to define the properties of each conversion between
|
||||
// the builtin arithmetric types
|
||||
//
|
||||
// It defines the specialization of the helper traits used by 'generate_expected_traits'
|
||||
//
|
||||
#define DEFINE_CONVERSION(Target,Source,Trivial,Mixture,SignMixture,UdtMixture,SubRanged) \
|
||||
\
|
||||
template<> struct my_is_subranged<Target,Source> \
|
||||
{ typedef mpl::bool_< (SubRanged) > type ; } ; \
|
||||
\
|
||||
template<> struct my_is_trivial<Target,Source> \
|
||||
{ typedef mpl::bool_< (Trivial) > type ; } ; \
|
||||
\
|
||||
template<> struct my_int_float_mixture<Target,Source> \
|
||||
{ typedef mpl::integral_c<boost::numeric::int_float_mixture_enum, (Mixture) > type ; } ; \
|
||||
\
|
||||
template<> struct my_sign_mixture<Target,Source> \
|
||||
{ typedef mpl::integral_c<boost::numeric::sign_mixture_enum, (SignMixture) > type ; } ; \
|
||||
\
|
||||
template<> struct my_udt_builtin_mixture<Target,Source> \
|
||||
{ typedef mpl::integral_c<boost::numeric::udt_builtin_mixture_enum, (UdtMixture) > type ; }
|
||||
|
||||
|
||||
#define cSubRanged true
|
||||
#define cTrivial true
|
||||
|
||||
// The following test assumes a specific relation between the sizes of the types being used;
|
||||
// therefore, use specific fixed-width types instead built-in types directly.
|
||||
|
||||
// NOTE --> TARGET,SOURCE
|
||||
//
|
||||
DEFINE_CONVERSION(boost::uint8_t , boost::uint8_t, cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(float , boost::uint8_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(double , boost::uint8_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(long double , boost::uint8_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(MyInt , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_udt , !cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , boost::uint8_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_udt , !cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , boost::int8_t, cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(float , boost::int8_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(double , boost::int8_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(long double , boost::int8_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(MyInt , boost::int8_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , boost::int8_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , boost::uint16_t, cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(float , boost::uint16_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(double , boost::uint16_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(long double , boost::uint16_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(MyInt , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_udt , !cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , boost::uint16_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_udt , !cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , boost::int16_t, cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(float , boost::int16_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(double , boost::int16_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(long double , boost::int16_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(MyInt , boost::int16_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , boost::int16_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , boost::uint32_t, cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(float , boost::uint32_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(double , boost::uint32_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(long double , boost::uint32_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(MyInt , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_udt , !cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , boost::uint32_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_udt , !cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , boost::int32_t, cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(float , boost::int32_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(double , boost::int32_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(long double , boost::int32_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(MyInt , boost::int32_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , boost::int32_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , float, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , float, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , float, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , float, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , float, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , float, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(float , float, cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(double , float, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(float) > sizeof(double) ) );
|
||||
DEFINE_CONVERSION(long double , float, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(float) > sizeof(long double) ) );
|
||||
DEFINE_CONVERSION(MyInt , float, !cTrivial, float_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , float, !cTrivial, float_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(float , double, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(double) > sizeof(float) ) );
|
||||
DEFINE_CONVERSION(double , double, cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(long double , double, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(double) > sizeof(long double) ) );
|
||||
DEFINE_CONVERSION(MyInt , double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , double, !cTrivial, float_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , long double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , long double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , long double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , long double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , long double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , long double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
|
||||
DEFINE_CONVERSION(float , long double, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(long double) > sizeof(float) ) );
|
||||
DEFINE_CONVERSION(double , long double, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(long double) > sizeof(double) ) );
|
||||
DEFINE_CONVERSION(long double , long double, cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
|
||||
DEFINE_CONVERSION(MyInt , long double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , long double, !cTrivial, float_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , MyInt, !cTrivial, integral_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , MyInt, !cTrivial, integral_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , MyInt, !cTrivial, integral_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , MyInt, !cTrivial, integral_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , MyInt, !cTrivial, integral_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , MyInt, !cTrivial, integral_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(float , MyInt, !cTrivial, integral_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(double , MyInt, !cTrivial, integral_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(long double , MyInt, !cTrivial, integral_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(MyInt , MyInt, cTrivial, integral_to_integral, signed_to_signed , udt_to_udt ,!cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , MyInt, !cTrivial, integral_to_float , signed_to_signed , udt_to_udt ,!cSubRanged );
|
||||
|
||||
DEFINE_CONVERSION(boost::uint8_t , MyFloat, !cTrivial, float_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int8_t , MyFloat, !cTrivial, float_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint16_t , MyFloat, !cTrivial, float_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int16_t , MyFloat, !cTrivial, float_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::uint32_t , MyFloat, !cTrivial, float_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(boost::int32_t , MyFloat, !cTrivial, float_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(float , MyFloat, !cTrivial, float_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(double , MyFloat, !cTrivial, float_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(long double , MyFloat, !cTrivial, float_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
|
||||
DEFINE_CONVERSION(MyInt , MyFloat, !cTrivial, float_to_integral, signed_to_signed , udt_to_udt ,!cSubRanged );
|
||||
DEFINE_CONVERSION(MyFloat , MyFloat, cTrivial, float_to_float , signed_to_signed , udt_to_udt ,!cSubRanged );
|
||||
|
||||
//
|
||||
// The test is performed by comparing each field of
|
||||
// boost::numeric::conversion_traits<T,S>
|
||||
// with the fields of
|
||||
// expected_traits<T,S>
|
||||
// which is a traits class constructed explicitely for each combination
|
||||
// of the built-in arithmetic types.
|
||||
//
|
||||
template<class T,
|
||||
class S,
|
||||
class Supertype,
|
||||
class Subtype,
|
||||
class Subranged,
|
||||
class Trivial
|
||||
>
|
||||
struct expected_traits
|
||||
{
|
||||
typedef typename my_int_float_mixture <T,S>::type int_float_mixture ;
|
||||
typedef typename my_sign_mixture <T,S>::type sign_mixture ;
|
||||
typedef typename my_udt_builtin_mixture <T,S>::type udt_builtin_mixture ;
|
||||
|
||||
typedef Subranged subranged ;
|
||||
typedef Trivial trivial ;
|
||||
typedef Supertype supertype ;
|
||||
typedef Subtype subtype ;
|
||||
} ;
|
||||
|
||||
// This is used by the test engine to generate a expected_traits from T and S.
|
||||
//
|
||||
template<class T, class S>
|
||||
struct generate_expected_traits
|
||||
{
|
||||
typedef expected_traits<T, S, T, S, mpl::false_, mpl::true_ > trivial ;
|
||||
typedef expected_traits<T, S, S, T, mpl::true_ , mpl::false_ > subranged ;
|
||||
typedef expected_traits<T, S, T, S, mpl::false_, mpl::false_ > non_subranged ;
|
||||
|
||||
typedef typename my_is_subranged<T,S>::type IsSubranged ;
|
||||
typedef typename my_is_trivial <T,S>::type IsTrivial ;
|
||||
|
||||
typedef typename mpl::if_<IsSubranged,subranged,non_subranged>::type non_trivial ;
|
||||
|
||||
typedef typename mpl::if_<IsTrivial,trivial,non_trivial>::type type ;
|
||||
} ;
|
||||
|
||||
// This macro generates the code that compares a non-type field
|
||||
// in boost::numeric::conversion_traits<> with its corresponding field
|
||||
// in expected_traits<>
|
||||
//
|
||||
#define TEST_VALUE_FIELD(Name) \
|
||||
BOOST_CHECK_MESSAGE ( ( traits::Name::value == expected::Name::value ) , \
|
||||
"conversion_traits<" << typeid(T).name() << "," << typeid(S).name() \
|
||||
<< ">::" << #Name << " = " << to_string(traits::Name::value) \
|
||||
<< ". Expected: " << to_string(expected::Name::value) \
|
||||
) ;
|
||||
|
||||
// This macro generates the code that compares a type field
|
||||
// in numeric::conversion_traits<> with its corresponding field
|
||||
// in expected_traits<>
|
||||
//
|
||||
#define TEST_TYPE_FIELD(Name) \
|
||||
BOOST_CHECK_MESSAGE ( ( typeid(traits::Name) == typeid(expected::Name) ) , \
|
||||
"conversion_traits<" << typeid(T).name() << "," << typeid(S).name() \
|
||||
<< ">::" << #Name << " = " << typeid(traits::Name).name() \
|
||||
<< ". Expected: " << typeid(expected::Name).name() \
|
||||
) ;
|
||||
|
||||
//
|
||||
// Test core.
|
||||
// Compares each field of boost::numeric::conversion_traits<T,S>
|
||||
// with the corresponding field of expected_traits<T,S>
|
||||
//
|
||||
template<class T, class S>
|
||||
void test_traits_base( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S) )
|
||||
{
|
||||
typedef boost::numeric::conversion_traits<T,S> traits ;
|
||||
typedef typename generate_expected_traits<T,S>::type expected ;
|
||||
|
||||
TEST_VALUE_FIELD(int_float_mixture) ;
|
||||
TEST_VALUE_FIELD(sign_mixture) ;
|
||||
TEST_VALUE_FIELD(udt_builtin_mixture) ;
|
||||
TEST_VALUE_FIELD(subranged) ;
|
||||
TEST_VALUE_FIELD(trivial) ;
|
||||
TEST_TYPE_FIELD (supertype) ;
|
||||
TEST_TYPE_FIELD (subtype) ;
|
||||
}
|
||||
|
||||
|
||||
template<class S>
|
||||
void test_traits_from( MATCH_FNTPL_ARG(S) )
|
||||
{
|
||||
test_traits_base( SET_FNTPL_ARG(boost::uint8_t) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(boost::int8_t) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(boost::uint16_t) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(boost::int16_t) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(boost::uint32_t) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(boost::int32_t) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(float) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(double) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(long double) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(MyInt) ,SET_FNTPL_ARG(S) );
|
||||
test_traits_base( SET_FNTPL_ARG(MyFloat) ,SET_FNTPL_ARG(S) );
|
||||
}
|
||||
|
||||
void test_traits()
|
||||
{
|
||||
test_traits_from( SET_FNTPL_ARG(boost::uint8_t) );
|
||||
test_traits_from( SET_FNTPL_ARG(boost::int8_t) );
|
||||
test_traits_from( SET_FNTPL_ARG(boost::uint16_t) );
|
||||
test_traits_from( SET_FNTPL_ARG(boost::int16_t) );
|
||||
test_traits_from( SET_FNTPL_ARG(boost::uint32_t) );
|
||||
test_traits_from( SET_FNTPL_ARG(boost::int32_t) );
|
||||
test_traits_from( SET_FNTPL_ARG(float) );
|
||||
test_traits_from( SET_FNTPL_ARG(double) );
|
||||
test_traits_from( SET_FNTPL_ARG(long double) );
|
||||
test_traits_from( SET_FNTPL_ARG(MyInt) );
|
||||
test_traits_from( SET_FNTPL_ARG(MyFloat) );
|
||||
}
|
||||
|
||||
int test_main( int, char * [])
|
||||
{
|
||||
std::cout << std::setprecision( std::numeric_limits<long double>::digits10 ) ;
|
||||
|
||||
test_traits();
|
||||
|
||||
return 0;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
// (C) 2003, Fernando Luis Cacciola Carballal.
|
||||
//
|
||||
// This material is provided "as is", with absolutely no warranty expressed
|
||||
// or implied. Any use is at your own risk.
|
||||
//
|
||||
// Permission to use or copy this software for any purpose is hereby granted
|
||||
// without fee, provided the above notices are retained on all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted,
|
||||
// provided the above notices are retained, and a notice that the code was
|
||||
// modified is included with the above copyright notice.
|
||||
//
|
||||
//
|
||||
#include<iostream>
|
||||
#include<iomanip>
|
||||
#include<string>
|
||||
#include<typeinfo>
|
||||
#include<vector>
|
||||
#include<algorithm>
|
||||
|
||||
#include "boost/numeric/conversion/converter.hpp"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
#include "test_helpers.cpp"
|
||||
#include "test_helpers2.cpp"
|
||||
#include "test_helpers3.cpp"
|
||||
|
||||
using namespace std ;
|
||||
using namespace boost ;
|
||||
using namespace numeric ;
|
||||
using namespace MyUDT ;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// These are the typical steps that are required to install support for
|
||||
// conversions from/to UDT which need special treatment.
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//
|
||||
// (1) Instantiate specific convesions traits.
|
||||
// This step is only for convenience.
|
||||
// These traits instances are required in order to define the specializations
|
||||
// that follow (and which *are required* to make the library work with MyInt and MyFloat)
|
||||
//
|
||||
namespace MyUDT {
|
||||
|
||||
typedef conversion_traits<double , MyFloat> MyFloat_to_double_Traits;
|
||||
typedef conversion_traits<int , MyFloat> MyFloat_to_int_Traits;
|
||||
typedef conversion_traits<MyInt , MyFloat> MyFloat_to_MyInt_Traits;
|
||||
typedef conversion_traits<int , MyInt > MyInt_to_int_Traits;
|
||||
typedef conversion_traits<MyFloat, MyInt > MyInt_to_MyFloat_Traits;
|
||||
typedef conversion_traits<MyInt , double > double_to_MyInt_Traits;
|
||||
|
||||
} // namespace MyUDT
|
||||
|
||||
|
||||
//
|
||||
// (2) Define suitable raw converters.
|
||||
//
|
||||
// Our sample UDTs don't support implicit conversions.
|
||||
// Therefore, the default raw_converter<> doesn't work,
|
||||
// and we need to define our own.
|
||||
//
|
||||
// There are two ways of doing this:
|
||||
//
|
||||
// (a) One is to simply specialize boost::numeric::raw_converter<> directly.
|
||||
// This way, the default converter will work out of the box, which means, for instance,
|
||||
// that numeric_cast<> can be used with these UDTs.
|
||||
//
|
||||
// (b) Define a user class with the appropriate interface and supply it explicitely
|
||||
// as a policy to a converter instance.
|
||||
//
|
||||
// This test uses chice (a).
|
||||
//
|
||||
namespace boost {
|
||||
|
||||
namespace numeric {
|
||||
|
||||
template<>
|
||||
struct raw_converter<MyUDT::MyFloat_to_double_Traits>
|
||||
{
|
||||
static double low_level_convert ( MyUDT::MyFloat const& s )
|
||||
{ return s.to_builtin() ; }
|
||||
} ;
|
||||
|
||||
template<>
|
||||
struct raw_converter<MyUDT::MyFloat_to_int_Traits>
|
||||
{
|
||||
static int low_level_convert ( MyUDT::MyFloat const& s )
|
||||
{ return static_cast<int>( s.to_builtin() ) ; }
|
||||
} ;
|
||||
|
||||
template<>
|
||||
struct raw_converter<MyUDT::MyFloat_to_MyInt_Traits>
|
||||
{
|
||||
static MyUDT::MyInt low_level_convert ( MyUDT::MyFloat const& s )
|
||||
{ return MyUDT::MyInt( static_cast<int>(s.to_builtin()) ) ; }
|
||||
} ;
|
||||
|
||||
template<>
|
||||
struct raw_converter<MyUDT::MyInt_to_int_Traits>
|
||||
{
|
||||
static int low_level_convert ( MyUDT::MyInt const& s ) { return s.to_builtin() ; }
|
||||
} ;
|
||||
|
||||
template<>
|
||||
struct raw_converter<MyUDT::MyInt_to_MyFloat_Traits>
|
||||
{
|
||||
static MyUDT::MyFloat low_level_convert ( MyUDT::MyInt const& s )
|
||||
{
|
||||
return MyUDT::MyFloat( static_cast<double>(s.to_builtin()) ) ;
|
||||
}
|
||||
} ;
|
||||
|
||||
template<>
|
||||
struct raw_converter<MyUDT::double_to_MyInt_Traits>
|
||||
{
|
||||
static MyUDT::MyInt low_level_convert ( double s )
|
||||
{ return MyUDT::MyInt( static_cast<int>(s) ) ; }
|
||||
} ;
|
||||
|
||||
} // namespace numeric
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
|
||||
//
|
||||
// (3) Define suitable range checkers
|
||||
//
|
||||
// By default, if a UDT is involved in a conversion, internal range checking is disabled.
|
||||
// This is so because a UDT type can have any sort of range, even unbounded, thus
|
||||
// the library doesn't attempt to automatically figure out the appropriate range checking logic.
|
||||
// (as it does when builtin types are involved)
|
||||
// However, this situation is a bit unsufficient in practice, specially from doing narrowing (subranged)
|
||||
// conversions from UDTs.
|
||||
// The library provides a rudimentary hook to help this out: The user can plug in his own
|
||||
// range checker to the converter instance.
|
||||
//
|
||||
// This test shows how to define and use a custom range checker.
|
||||
//
|
||||
|
||||
namespace MyUDT {
|
||||
|
||||
//
|
||||
// The following are metaprogramming tools to allow us the implement the
|
||||
// MyCustomRangeChecker generically, for either builtin or UDT types.
|
||||
//
|
||||
|
||||
// get_builtin_type<N>::type extracts the built-in type of our UDT's
|
||||
//
|
||||
template<class N> struct get_builtin_type { typedef N type ; } ;
|
||||
template<> struct get_builtin_type<MyInt> { typedef int type ; } ;
|
||||
template<> struct get_builtin_type<MyFloat> { typedef double type ; } ;
|
||||
|
||||
// U extract_builtin ( T s ) returns 's' converted to the corresponding built-in type U.
|
||||
//
|
||||
template<class N>
|
||||
struct extract_builtin
|
||||
{
|
||||
static N apply ( N n ) { return n ; }
|
||||
} ;
|
||||
template<>
|
||||
struct extract_builtin<MyInt>
|
||||
{
|
||||
static int apply ( MyInt const& n ) { return n.to_builtin() ; }
|
||||
} ;
|
||||
template<>
|
||||
struct extract_builtin<MyFloat>
|
||||
{
|
||||
static double apply ( MyFloat const& n ) { return n.to_builtin() ; }
|
||||
} ;
|
||||
|
||||
template<class Traits>
|
||||
struct MyCustomRangeChecker
|
||||
{
|
||||
typedef typename Traits::argument_type argument_type ;
|
||||
|
||||
// This custom range checker uses the fact that our 'fake' UDT are merely wrappers
|
||||
// around builtin types; so it just forward the logic to the correspoding range
|
||||
// checkers for the wrapped builtin types.
|
||||
//
|
||||
typedef typename Traits::source_type S ;
|
||||
typedef typename Traits::target_type T ;
|
||||
|
||||
// NOTE: S and/or T can be either UDT or builtin types.
|
||||
|
||||
typedef typename get_builtin_type<S>::type builtinS ;
|
||||
typedef typename get_builtin_type<T>::type builtinT ;
|
||||
|
||||
// NOTE: The internal range checker used by default is *built* when you instantiate
|
||||
// a converter<> with a given Traits according to the properties of the involved types.
|
||||
// Currently, there is no way to instantiate this range checker as a separate class.
|
||||
// However, you can see it as part of the interface of the converter
|
||||
// (since the converter inherits from it)
|
||||
// Therefore, here we instantiate a converter corresponding to the builtin types to access
|
||||
// their associated builtin range checker.
|
||||
//
|
||||
typedef boost::numeric::converter<builtinT,builtinS> InternalConverter ;
|
||||
|
||||
static range_check_result out_of_range ( argument_type s )
|
||||
{
|
||||
return InternalConverter::out_of_range( extract_builtin<S>::apply(s) );
|
||||
}
|
||||
|
||||
static void validate_range ( argument_type s )
|
||||
{
|
||||
return InternalConverter::validate_range( extract_builtin<S>::apply(s) );
|
||||
}
|
||||
} ;
|
||||
|
||||
} // namespace MyUDT
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Test here
|
||||
//
|
||||
|
||||
void test_udt_conversions_with_defaults()
|
||||
{
|
||||
cout << "Testing UDT conversion with default policies\n" ;
|
||||
|
||||
// MyInt <--> int
|
||||
|
||||
int mibv = rand();
|
||||
MyInt miv(mibv);
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(MyInt,int,miv,mibv);
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(int,MyInt,mibv,miv);
|
||||
|
||||
// MyFloat <--> double
|
||||
|
||||
double mfbv = static_cast<double>(rand()) / 3.0 ;
|
||||
MyFloat mfv (mfbv);
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(MyFloat,double,mfv,mfbv);
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(double,MyFloat,mfbv,mfv);
|
||||
|
||||
// MyInt <--> MyFloat
|
||||
|
||||
MyInt miv2 ( static_cast<int>(mfbv) );
|
||||
MyFloat miv2F ( static_cast<int>(mfbv) );
|
||||
MyFloat mfv2 ( static_cast<double>(mibv) );
|
||||
MyInt mfv2I ( static_cast<double>(mibv) );
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(MyFloat,MyInt,miv2F,miv2);
|
||||
TEST_SUCCEEDING_CONVERSION_DEF(MyInt,MyFloat,mfv2I,mfv2);
|
||||
}
|
||||
|
||||
template<class T, class S>
|
||||
struct GenerateCustomConverter
|
||||
{
|
||||
typedef conversion_traits<T,S> Traits;
|
||||
|
||||
typedef def_overflow_handler OverflowHandler ;
|
||||
typedef Trunc<S> Float2IntRounder ;
|
||||
typedef raw_converter<Traits> RawConverter ;
|
||||
typedef MyCustomRangeChecker<Traits> RangeChecker ;
|
||||
|
||||
typedef converter<T,S,Traits,OverflowHandler,Float2IntRounder,RawConverter,RangeChecker> type ;
|
||||
} ;
|
||||
|
||||
void test_udt_conversions_with_custom_range_checking()
|
||||
{
|
||||
cout << "Testing UDT conversions with custom range checker\n" ;
|
||||
|
||||
int mibv = rand();
|
||||
MyFloat mfv ( static_cast<double>(mibv) );
|
||||
|
||||
typedef GenerateCustomConverter<MyFloat,int>::type int_to_MyFloat_Conv ;
|
||||
|
||||
TEST_SUCCEEDING_CONVERSION( int_to_MyFloat_Conv, MyFloat, int, mfv, mibv );
|
||||
|
||||
int mibv2 = rand();
|
||||
MyInt miv (mibv2);
|
||||
MyFloat mfv2 ( static_cast<double>(mibv2) );
|
||||
|
||||
typedef GenerateCustomConverter<MyFloat,MyInt>::type MyInt_to_MyFloat_Conv ;
|
||||
|
||||
TEST_SUCCEEDING_CONVERSION( MyInt_to_MyFloat_Conv, MyFloat, MyInt, mfv2, miv );
|
||||
|
||||
double mfbv = bounds<double>::highest();
|
||||
typedef GenerateCustomConverter<MyInt,double>::type double_to_MyInt_Conv ;
|
||||
|
||||
TEST_POS_OVERFLOW_CONVERSION( double_to_MyInt_Conv, MyInt, double, mfbv );
|
||||
|
||||
MyFloat mfv3 ( bounds<double>::lowest() ) ;
|
||||
typedef GenerateCustomConverter<int,MyFloat>::type MyFloat_to_int_Conv ;
|
||||
|
||||
TEST_NEG_OVERFLOW_CONVERSION( MyFloat_to_int_Conv, int, MyFloat, mfv3 );
|
||||
}
|
||||
|
||||
|
||||
int test_main( int, char* [] )
|
||||
{
|
||||
cout << setprecision( numeric_limits<long double>::digits10 ) ;
|
||||
|
||||
test_udt_conversions_with_defaults();
|
||||
test_udt_conversions_with_custom_range_checking();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user