123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.1//EN"
- "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
- <section id="safe_numerics.safe">
- <title>safe<T, PP, EP></title>
- <?dbhtml stop-chunking?>
- <section>
- <title>Description</title>
- <para>A <code>safe<T, PP , EP></code> can be used anywhere a type T
- can be used. Any expression which uses this type is guaranteed to return
- an arithmetically correct value or to trap in some way.</para>
- </section>
- <section>
- <title>Model of</title>
- <para><link linkend="safe_numerics.numeric">Integer</link></para>
- <para><link
- linkend="safe_numerics.safe_numeric_concept">SafeNumeric</link></para>
- <para>This type inherits all the notation, associated types and template
- parameters and valid expressions of <link
- linkend="safe_numerics.safe_numeric_concept">SafeNumeric</link> types. The
- following specify additional features of this type.</para>
- </section>
- <section>
- <title>Notation</title>
- <informaltable>
- <tgroup cols="2">
- <colspec align="left" colwidth="1*"/>
- <colspec align="left" colwidth="10*"/>
- <thead>
- <row>
- <entry align="left">Symbol</entry>
- <entry align="left">Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><code>T</code></entry>
- <entry>Underlying type from which a safe type is being
- derived</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section>
- <title>Associated Types</title>
- <informaltable>
- <tgroup cols="2">
- <colspec align="left" colwidth="1*"/>
- <colspec align="left" colwidth="10*"/>
- <tbody>
- <row>
- <entry><code>PP</code></entry>
- <entry>A type which specifies the result type of an expression
- using safe types.</entry>
- </row>
- <row>
- <entry><code>EP</code></entry>
- <entry>A type containing members which are called when a correct
- result cannot be returned</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </section>
- <section>
- <title>Template Parameters</title>
- <informaltable>
- <tgroup cols="3">
- <colspec colwidth="1*"/>
- <colspec align="left" colwidth="3*"/>
- <colspec align="left" colwidth="7*"/>
- <thead>
- <row>
- <entry align="left">Parameter</entry>
- <entry align="left">Type Requirements</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><code>T</code></entry>
- <entry><ulink
- url="http://en.cppreference.com/w/cpp/types/is_integral">Integer<T></ulink></entry>
- <entry><para>The underlying type. Currently only integer types are
- supported</para></entry>
- </row>
- <row>
- <entry><code>PP</code></entry>
- <entry><link linkend="safe_numerics.numeric"><link
- linkend="safe_numerics.promotion_policy">PromotionPolicy<PP></link></link></entry>
- <entry><para>Optional promotion policy. Default value is <link
- linkend="safe_numerics.promotion_policies.native"><code>boost::numeric::native</code></link></para></entry>
- </row>
- <row>
- <entry><code>EP</code></entry>
- <entry><link linkend="safe_numerics.numeric"><link
- linkend="safe_numerics.exception_policy">Exception
- Policy<EP></link></link></entry>
- <entry><para>Optional exception policy. Default value is <link
- linkend="safe_numerics.exception_policies.default_exception_policy"><code>boost::numeric::default_exception_policy</code></link></para></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- <para>See examples below.</para>
- </section>
- <section>
- <title>Valid Expressions</title>
- <para>Implements all expressions and only those expressions defined by the
- <link
- linkend="safe_numerics.safe_numeric_concept">SafeNumeric</link><T>
- type requirements. Note that all these expressions are
- <code>constexpr</code>. Thus, the result type of such an expression will
- be another safe type. The actual type of the result of such an expression
- will depend upon the specific promotion policy template parameter.</para>
- <para>When a binary operand is applied to two instances of safe<T, PP,
- EP>on of the following must be true:<itemizedlist>
- <listitem>
- <para>The promotion policies of the two operands must be the same or
- one of them must be void</para>
- </listitem>
- <listitem>
- <para>The exception policies of the two operands must be the same or
- one of them must be void</para>
- </listitem>
- </itemizedlist>If either of the above is not true, a compile error will
- result.</para>
- </section>
- <section>
- <title>Examples of use</title>
- <para>The most common usage would be safe<T> which uses the default
- promotion and exception policies. This type is meant to be a "drop-in"
- replacement of the intrinsic integer types. That is, expressions involving
- these types will be evaluated into result types which reflect the standard
- rules for evaluation of C++ expressions. Should it occur that such
- evaluation cannot return a correct result, an exception will be
- thrown.</para>
- <para>There are two aspects of the operation of this type which can be
- customized with a policy. The first is the result type of an arithmetic
- operation. C++ defines the rules which define this result type in terms of
- the constituent types of the operation. Here we refer to these rules as
- "type promotion" rules. These rules will sometimes result in a type which
- cannot hold the actual arithmetic result of the operation. This is the
- main motivation for making this library in the first place. One way to
- deal with this problem is to substitute our own type promotion rules for
- the C++ ones.</para>
- <section id="safe_numerics.drop_in_replacement">
- <title>As a Drop-in replacement for standard integer types.</title>
- <para>The following program will throw an exception and emit an error
- message at runtime if any of several events result in an incorrect
- arithmetic result. Behavior of this program could vary according to the
- machine architecture in question.</para>
- <para><programlisting>#include <exception>
- #include <iostream>
- #include <safe_integer.hpp>
- void f(){
- using namespace boost::numeric;
- safe<int> j;
- try {
- safe<int> i;
- std::cin >> i; // could overflow !
- j = i * i; // could overflow
- }
- catch(std::exception & e){
- std::cout << e.what() << std::endl;
- }
- std::cout << j;
- }</programlisting>The term "drop-in replacement" reveals the aspiration of
- this library. In most cases, this aspiration is realized. In the
- following example, the normal implicit conversions function the same for
- safe integers as they do for built-in integers. <programlisting><xi:include
- href="../../example/example16.cpp" parse="text"
- xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>When
- the <code>safe<long></code> is implicitly converted to an
- <code>int</code> when calling <code>f</code>, the value is checked to be
- sure that it is within the legal range of an int and will invoke an
- exception if it cannot. We can easily verify this by altering the
- exception handling policy in the above example to
- <code>loose_trap_policy</code>. This will invoke a compile time error on
- any conversion might invoke a runtime exception.</para>
- <para><programlisting><xi:include href="../../example/example17.cpp"
- parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting></para>
- <para>But this raises it's own questions. We can see that in this
- example, the program can never fail:</para>
- <itemizedlist>
- <listitem>
- <para>The value 97 is assigned to y</para>
- </listitem>
- <listitem>
- <para>y is converted to an int</para>
- </listitem>
- <listitem>
- <para>and used as an argument to f</para>
- </listitem>
- </itemizedlist>
- <para>The conversion can never fail because the value of 97 can always
- fit into an int. But the library code can't detect this and emits the
- checking code even though it's not necessary.</para>
- <para>This can be addressed by using a <link
- linkend="safe_numerics.safe_literal"><code>safe_literal</code></link>. A
- safe literal can contain one and only one value. All the functions in
- this library are marked <code>constexpr</code>. So it can be determined
- at compile time that conversion to an <code>int</code> can never fail
- and no runtime checking code need be emitted. Making this small change
- will permit the above example to run with zero runtime overhead while
- guaranteeing that no error can ever occur.</para>
- <programlisting><xi:include href="../../example/example18.cpp"
- parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>
- <para>With this trivial example, such efforts would hardly be deemed
- necessary. But in a more complex case, perhaps including compile time
- arithmetic expressions, it could be much more difficult to verify that
- the constant is valid and/or no checking code is needed. And there is
- also possibility that over the life time of the application, the compile
- time constants might change, thus rendering any ad hoc analyse obsolete.
- Using <link
- linkend="safe_numerics.safe_literal"><code>safe_literal</code></link>
- will future-proof your code against well-meaning, but code-breaking
- updates.</para>
- </section>
- <section>
- <title>Adjust type promotion rules.</title>
- <para>Another way to avoid arithmetic errors like overflow is to promote
- types to larger sizes before doing the arithmetic.</para>
- <para>Stepping back, we can see that many of the cases of invalid
- arithmetic wouldn't exist if the result types were larger. So we can
- avoid these problems by replacing the C++ type promotion rules for
- expressions with our own rules. This can be done by specifying a
- promotion policy <code><code>automatic</code></code>. The policy stores
- the result of an expression in the smallest size type that can
- accommodate the largest value that an expression can yield. No checking
- for exceptions is necessary. The following example illustrates
- this.</para>
- <para><programlisting>#include <boost/safe_numerics/safe_integer.hpp>
- #include <iostream>
- int main(int, char[]){
- using safe_int = safe<
- int, boost::numeric::automatic,
- boost::numeric::default_exception_policy
- >;
- safe_int i;
- std::cin >> i; // might throw exception
- auto j = i * i; // won't ever trap - result type can hold the maximum value of i * i
- static_assert(boost::numeric::is_safe<decltype(j)>::value); // result is another safe type
- static_assert(
- std::numeric_limits<decltype(i * i)>::max() >=
- std::numeric_limits<safe_int>::max() * std::numeric_limits<safe_int>::max()
- ); // always true
- return 0;
- }</programlisting></para>
- </section>
- </section>
- <section>
- <title>Header</title>
- <para><filename><ulink
- url="../../include/boost/safe_numerics/safe_integer.hpp">#include
- <boost/numeric/safe_numerics/safe_integer.hpp></ulink></filename></para>
- </section>
- </section>
|