Myself Added

[SVN r23175]
This commit is contained in:
Fernando Cacciola
2004-06-24 12:01:42 +00:00
commit be7ce8a2c8
37 changed files with 5465 additions and 0 deletions
+96
View File
@@ -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
View File
@@ -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&ltN&gt</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&lt;T&gt;::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&lt;&gt; 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&lt;N&gt;</CODE></A></H2>
<BLOCKQUOTE>
<PRE>template&lt;class N&gt;
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&lt;T&gt;::min() when T is an integral type, and to
-numeric_limits&lt;T&gt;::max() when T is a floating point type. </P>
<PRE>highest()</PRE>
<P>Returns the maximum finite value, equivalent to
numeric_limits&lt;T&gt;::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&lt;&gt; and the
equivalent code using numeric_limits: </P>
<BLOCKQUOTE>
<PRE>#include &lt;iostream&gt;
#include &lt;boost/numeric/conversion/bounds.hpp&gt;
#include &lt;boost/limits.hpp&gt;
int main() {
std::cout &lt;&lt; "numeric::bounds versus numeric_limits example.\n";
std::cout &lt;&lt; "The maximum value for float:\n";
std::cout &lt;&lt; boost::numeric::bounds&lt;float&gt;::highest() &lt;&lt; "\n";
std::cout &lt;&lt; std::numeric_limits&lt;float&gt;::max() &lt;&lt; "\n";
std::cout &lt;&lt; "The minimum value for float:\n";
std::cout &lt;&lt; boost::numeric::bounds&lt;float&gt;::lowest() &lt;&lt; "\n";
std::cout &lt;&lt; -std::numeric_limits&lt;float&gt;::max() &lt;&lt; "\n";
std::cout &lt;&lt; "The smallest positive value for float:\n";
std::cout &lt;&lt; boost::numeric::bounds&lt;float&gt;::smallest() &lt;&lt; "\n";
std::cout &lt;&lt; std::numeric_limits&lt;float&gt;::min() &lt;&lt; "\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>
+334
View File
@@ -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&lt;T,S&gt;</CODE></A></LI>
<LI><A HREF="#sm"><CODE>template class boost::numeric::sign_mixture&lt;T,S&gt;</CODE></A></LI>
<LI><A HREF="#ubm"><CODE>template class boost::numeric::udt_builtin_mixture&lt;T,S&gt;</CODE></A></LI>
<LI><A HREF="#isr"><CODE>template class boost::numeric::is_subranged&lt;T,S&gt;</CODE></A></LI>
<LI><A HREF="#nct"><CODE>template class boost::numeric::conversion_traits&lt;T,S&gt;</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&lt;&gt;</CODE></A></H2>
<PRE>namespace boost { namespace numeric {
template &lt;class T, class S&gt;
struct int_float_mixture : mpl::integral_c&lt;int_float_mixture_enum, <i>impl-def-value</i>&gt; {} ;
} } // 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&lt;&gt;</CODE></A></H2>
<PRE>namespace boost { namespace numeric {
template &lt;class T, class S&gt;
struct sign_mixture : mpl::integral_c&lt;sign_mixture_enum, <i>impl-def-value</i>&gt; {} ;
} } // 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&lt;&gt;</CODE></A></H2>
<PRE>namespace boost { namespace numeric {
template &lt;class T, class S&gt;
struct udt_builtin_mixture : mpl::integral_c&lt;udt_builtin__mixture_enum, <i>impl-def-value</i>&gt; {} ;
} } // 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&lt;&gt;</CODE></A></H2>
<PRE>namespace boost { namespace numeric {
template &lt;class T, class S&gt;
struct is_subranged : mpl::bool_&lt;<i>impl-def-value</i>&gt; {} ;
} } // 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&lt;&gt;</CODE></A></H2>
<PRE>namespace boost { namespace numeric {
template &lt;class T, class S&gt;
struct numeric_conversion_traits
{
mpl::integral_c&lt;int_float_mixture_enum , ...&gt; int_float_mixture ;
mpl::integral_c&lt;sign_mixture_enum , ...&gt; sign_mixture;
mpl::integral_c&lt;udt_builtin_mixture_enum, ...&gt; udt_builtin_mixture ;
mpl::bool_&lt;...&gt; subranged ;
mpl::bool_&lt;...&gt; 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>&nbsp;<CODE><B>int_float_mixture</B></CODE>&nbsp;</TD>
<TD>
<P>Same as given by the traits class <A HREF="#ifm"><CODE>int_float_mixture</CODE></A></P>
</TD>
</TR>
<TR>
<TD>&nbsp;<CODE><B>sign_mixture</B></CODE>&nbsp;</TD>
<TD>
<P>Same as given by the traits class <A HREF="#sm"><CODE>sign_mixture</CODE></A></P>
</TD>
</TR>
<TR>
<TD>&nbsp;<CODE><B>udt_builtin_mixture</B></CODE>&nbsp;</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>&nbsp;<CODE> <B>subranged</B></CODE>&nbsp;</TD>
<TD>
<P>Same as given by <A HREF="#isr"><CODE>is_subranged</CODE></A></P>
</TD>
</TR>
<TR>
<TD>&nbsp;<CODE> <B>trivial</B></CODE>&nbsp;</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>&nbsp;<CODE><B>target_type</B></CODE>&nbsp;</TD>
<TD>
<P>The template parameter <CODE>T</CODE><EM> without cv-qualifications</EM></P>
</TD>
</TR>
<TR>
<TD>&nbsp;<CODE><B>source_type</B></CODE>&nbsp;</TD>
<TD>
<P>The template parameter <CODE>S</CODE><EM> without cv-qualifications</EM></P>
</TD>
</TR>
<TR>
<TD>&nbsp;<CODE><B>argument_type</B></CODE>&nbsp;</TD>
<TD>
<P>This type is either <CODE>source_type</CODE> or <CODE>source_type
const&amp;</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&amp;</CODE>. </P>
</TD>
</TR>
<TR>
<TD>&nbsp;<CODE><B>result_type</B></CODE></TD>
<TD>
<P>This type is either <CODE>target_type</CODE> or <CODE>target_type
const&amp;</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&amp;</CODE>, otherwise,
it is <CODE>target_type</CODE>.</P>
</TD>
</TR>
<TR>
<TD height="37">&nbsp;<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>&nbsp;<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 &lt;boost/numeric/conversion_traits.hpp&gt;
int main() {
// A trivial conversion.
typedef boost::numeric::conversion_traits&lt;short,short&gt; Short2Short_Traits ;
assert ( Short2Short_Traits::trivial::value ) ;
// A subranged conversion.
typedef boost::numeric::conversion_traits&lt;double,unsigned int&gt; 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&lt;short, unsigned short&gt;::subranged::value
&amp;&amp; boost::numeric::conversion_traits&lt;unsigned short, short&gt;::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>
+268
View File
@@ -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&lt;class T,
class S,
class Traits, = conversion_traits&lt;T,S&gt;
class OverflowHandler = def_overflow_handler,
class Float2IntRounder = Trunc&lt; typename Traits::source_type &gt;,
class RawConverter = raw_converter&lt;Traits&gt;,
class UserRangeChecker = UseInternalRangeChecker
&gt;
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&lt;&gt;</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>&nbsp;<CODE>Traits</CODE>&nbsp;</TD>
<TD>&nbsp;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>&nbsp;<A HREF="converter_policies.html#oh"><CODE>OverflowHandler</CODE></A>&nbsp;</TD>
<TD>&nbsp;<B>Stateless Policy</B> called to administrate the result of the
range checking.<br>
&nbsp;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>&nbsp;<A HREF="converter_policies.html#f2i"><CODE>Float2IntRounder</CODE></A>&nbsp;</TD>
<TD>&nbsp;<B>Stateless Policy</B> which specifies the rounding mode used for
float to integral conversions.<br>
&nbsp;It supplies the <CODE>nearbyint()</CODE> static member function exposed
by the converter.</TD>
</TR>
<TR>
<TD>&nbsp;<A HREF="converter_policies.html#rawc"><CODE>RawConverter</CODE></A>&nbsp;</TD>
<TD>&nbsp;<B>Stateless Policy</B> which is used to perform the actual conversion.
<br>
&nbsp;It supplies the<CODE> low_level_convert()</CODE> static member function
exposed by the converter.</TD>
</TR>
<TR>
<TD>&nbsp;<A HREF="converter_policies.html#rangecheck"><CODE>UserRangeChecker</CODE></A>&nbsp;</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&lt;&gt;::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>&quot;converter&lt;&gt;::operator() const&quot; just calls <CODE>convert()</CODE></P>
</BLOCKQUOTE>
<P><CODE>static range_check_result numeric_converter&lt;&gt;::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-&gt;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&lt;&gt;::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&lt;&gt;::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&lt;&gt;::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 &quot;static_cast&lt;S&gt;(n)&quot; (S denotes the Source
type).<br>
&quot;NONE&quot; indicates that for this case there is no range checking.</P>
<Pre>&nbsp; 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 &lt; 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 &lt;boost/numeric/conversion/converter.hpp&gt;
int main() {
typedef boost::numeric::converter&lt;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&lt;double&gt;::highest();
int z = Double2Int::convert(m); // By default throws positive_overflow()
}
catch ( boost::numeric::positive_overflow const&amp; )
{
}
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>
+306
View File
@@ -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&lt;T&gt;</CODE></A> (Default Policy)</LI>
<LI>class <A HREF="#round"><CODE>RoundEven&lt;T&gt;</CODE></A></LI>
<LI>class <A HREF="#ceil"><CODE>Ceil&lt;T&gt;</CODE></A></LI>
<LI>class <A HREF="#floor"><CODE>Floor&lt;T&gt;</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&lt;&gt;::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 &quot;bad numeric conversion: overflow&quot;; }
};
class <a name="negovr">negative_overflow</a> : public bad_numeric_conversion
{
public:
virtual const char *what() const // throw()
{ return &quot;bad numeric conversion: negative overflow&quot;; }
};
class <a name="posovr">positive_overflow</a> : public bad_numeric_conversion
{
public:
virtual const char *what() const // throw()
{ return &quot;bad numeric conversion: positive overflow&quot;; }
};
} }
</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>&quot;nearbyint()&quot;</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&lt;class S&gt;
struct YourFloat2IntRounderPolicy
{
typedef S source_type ;
typedef <I>{S or S const&amp;}</I> argument_type ;
static source_type nearbyint ( argument_type s ) { ... }
typedef mpl::integral_c&lt;std::float_round_style,std::<i>round_...</i>&gt; 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&lt;&gt;. 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&lt;class S&gt;
struct Trunc
{
static source_type nearbyint ( argument_type s )
{
using std::floor ;
using std::ceil ;
return s >= static_cast&lt;S&gt;(0) ? floor(s) : ceil(s) ;
}
typedef mpl::integral_c&lt;std::float_round_style,std::round_toward_zero&gt; round_style ;
} ;
</PRE>
<PRE> <A NAME="round"></A>template&lt;class S&gt;
struct RoundEven
{
static source_type nearbyint ( argument_type s )
{
return <i>impl-defined-value</i> ;
}
typedef mpl::integral_c&lt;std::float_round_style,std::round_to_nearest&gt; round_style ;
} ;
</PRE>
<PRE> <A NAME="ceil"></A>template&lt;class S&gt;
struct Ceil
{
static source_type nearbyint ( argument_type s )
{<br> using std::ceil ;<br> return ceil(s) ;<br> }
typedef mpl::integral_c&lt;std::float_round_style,std::round_toward_infinity&gt; round_style ;
} ;
</PRE>
<PRE> <A NAME="floor"></A>template&lt;class S&gt;
struct Floor
{
static source_type nearbyint ( argument_type s )
{<br> using std::floor ;<br> return floor(s) ;<br> }
typedef mpl::integral_c&lt;std::float_round_style,std::round_toward_neg_infinity&gt; 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>&quot;low_level_convert()&quot;</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&lt;class Traits&gt;
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>&lt;impl defined&gt;</I> ; }
} ;
</PRE>
<P>This policy is mostly provided as a hook for user defined types which don't
support <CODE>static_cast&lt;&gt;</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&lt;class Traits&gt;
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&lt;result_type&gt;(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>&quot;validate_range()&quot;</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&lt;class Traits&gt;
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>
+471
View File
@@ -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> (&sect;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 (&sect;1.8) and has a type (&sect;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 (&sect;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 (&sect;3.9/4). For
<u>POD</u> types (&sect;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 &pi;).<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 &pi; 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> (&sect;3.9.1). The following
subsets of the fundamental types are intended to represent <i>numbers</i>:</p>
<li><u>signed integer types</u> (&sect;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> (&sect;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> (&sect;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> (&sect;3.9.1/7):<br>
<blockquote>
<code>{{signed integers},{unsigned integers}, bool, char and wchar_t}</code>
</blockquote>
</li>
<li><u>arithmetic types</u> (&sect;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 &sect;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&lt;&gt; numeric_limits&lt;MyInt&gt; { ... } ;
}
// 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&lt;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 &lt;&lt;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 &lt; abt(l)</code> or <code>V &gt; 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 &lt; abt(l)</code>, the <b>overflow is negative</b>.<br>
If <code>V &gt; abt(h)</code>, the <b>overflow is positive</b>.
</p>
<p>If <code>V &ge; abt(l)</code> and <code>V &le; 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) &le; V &le; 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 &lt; -2.0, nor for x &gt; +2.0.
</p>
<hr>
<h2><A NAME="stdconv">Standard (numeric) Conversions</A></h2>
<P>The C++ language defines <u>Standard Conversions</u> (&sect;4) some of which are
conversions between arithmetic types.<br>
These are <u>Integral promotions</u> (&sect;4.5), <u>Integral conversions</u> (&sect;4.7),
<u>Floating point promotions</u> (&sect;4.6), <u>Floating point conversions</u> (&sect;4.8)
and <u>Floating-integral conversions</u> (&sect;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 &sect;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-&gt;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) &amp; 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-&gt;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 (&sect;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
View File
@@ -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>
&nbsp;&nbsp;&nbsp; <a href="#Overview">Overview</a><br>
&nbsp;&nbsp;&nbsp; <a href="#Ack">History and Acknowledgments</a><br>
&nbsp;&nbsp;&nbsp; <a href="#Ref">Bibliography</a><br>
</td>
<td width="50%"><font size="4">Other Documents</font><br><br>
&nbsp;&nbsp;&nbsp; <A HREF="definitions.html">Definitions</A><br>
&nbsp;&nbsp;&nbsp; <A HREF="converter.html"><code>converter&lt;&gt;</code> function object</A><br>
&nbsp;&nbsp;&nbsp; <A HREF="requirements.html">Type Requirements and User-defined-types support</A><br>
&nbsp;&nbsp;&nbsp; <A HREF="bounds.html"><code>bounds&lt;&gt;</code> traits class</A><br>
&nbsp;&nbsp;&nbsp; <A HREF="conversion_traits.html"><code>conversion_traits&lt;&gt;</code> traits class</A><br>
&nbsp;&nbsp;&nbsp; <A HREF="converter_policies.html">Numeric Converter Policy Classes</A><br>
&nbsp;&nbsp;&nbsp; <A HREF="numeric_cast.html">Improved numeric_cast&lt;&gt;</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&lt;&gt;</code>,
the <A HREF="bounds.html"><code>bounds&lt;&gt;</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&lt;&gt; 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&lt;&gt; which prevented it from being used in a generic
layer of math functions.<br>
An improved numeric_cast&lt;&gt; 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&lt;&gt; 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&lt;&gt; 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>
+123
View File
@@ -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&lt;typename Target, typename Source&gt; inline
typename boost::numeric::converter&lt;Traget,Source&gt;::result_type
numeric_cast ( Source arg )
{
return boost::numeric::converter&lt;Traget,Source&gt;::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 &lt;boost/numeric_cast.hpp&gt;
#include &lt;iostream&gt;
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&lt;short&gt;(i);
}
catch(negative_overflow&amp; e) {
std::cout &lt;&lt; e.what();
}
catch(positive_overflow&amp; e) {
std::cout &lt;&lt; e.what();
}
try {
float f=-42.1234;
// This will cause a boost::negative_underflow exception to be thrown
unsigned int i=numeric_cast&lt;unsigned int&gt;(f);
double d=f+numeric_cast&lt;double&gt;(i);
unsigned long l=std::numeric_limits&lt;unsigned long&gt;::max();
// This works, because unsigned integral types cannot cause overflow.
unsigned char c=numeric_cast&lt;unsigned char&gt;(l);
unsigned short us=std::numeric_limits&lt;unsigned short&gt;::max();
// This will cause an positive_overflow exception to be thrown
short s=numeric_cast&lt;short&gt;(us);
}
catch(bad_numeric_cast&amp; e) {
std::cout &lt;&lt; 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>
+116
View File
@@ -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&lt;T&gt;::is_specialized</CODE> to detect whether
the type is builtin or user defined, and <CODE>std::numeric_limits&lt;T&gt;::is_integer,
std::numeric_limits&lt;T&gt;::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&lt;&gt; rounder policy needs to determine if the source value
is positive or not, and for this it evaluates the expression &quot;s &lt; static_cast&lt;S&gt;(0)&quot;.
Therefore, user defined types require a visible operator &lt; 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&lt;&gt;</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&lt;&gt;</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&lt;&gt;</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>&quot;static_cast&lt;Target&gt;(source)&quot;.</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
+48
View File
@@ -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
+22
View File
@@ -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 ]
;
}
+101
View File
@@ -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;
}
+522
View File
@@ -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;
}
//---------------------------------------------------------------------------
+149
View File
@@ -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 ; }
//
///////////////////////////////////////////////////////////////////////////////////////////////
+71
View File
@@ -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
//
///////////////////////////////////////////////////////////////////////////////////////////////
+144
View File
@@ -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 )
//
///////////////////////////////////////////////////////////////////////////////////////////////
+341
View File
@@ -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;
}
//---------------------------------------------------------------------------
+314
View File
@@ -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;
}