mirror of
https://github.com/boostorg/safe_numerics.git
synced 2026-02-24 04:12:26 +00:00
Merge pull request #27 from insideoutclub/master
Fixing Typos in Documentation and Examples
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
safe_numerics
|
||||
=============
|
||||
|
||||
Arithmetic operations in C++ are NOT guarenteed to yield a correct mathematical result. This feature is inherited from the early days of C. The behavior of int, unsigned int and others were designed to map closely to the underlying hardware. Computer hardware implements these types as a fixed number of bits. When the result of arithmetic operations exceeds this number of bits, the result is undefined and usually not what the programmer intended. It is incumbent up the C++ programmer to guarentee that this behavior does not result in incorrect behavior of the program. This library implements special versions of these data types which behave exactly like the original ones EXCEPT that the results of these operations are checked to be sure that an exception will be thrown anytime an attempt is made to store the result of an undefined operation.
|
||||
Arithmetic operations in C++ are NOT guarenteed to yield a correct mathematical result. This feature is inherited from the early days of C. The behavior of int, unsigned int and others were designed to map closely to the underlying hardware. Computer hardware implements these types as a fixed number of bits. When the result of arithmetic operations exceeds this number of bits, the result is undefined and usually not what the programmer intended. It is incumbent upon the C++ programmer to guarantee that this behavior does not result in incorrect behavior of the program. This library implements special versions of these data types which behave exactly like the original ones EXCEPT that the results of these operations are checked to be sure that an exception will be thrown anytime an attempt is made to store the result of an undefined operation.
|
||||
|
||||
Additionally, we define data types safe_signed_range<MIN, MAX> and safe_unsigned_range<MIN, MAX> which will throw an exception if an attempt is made to store a result which is outside the closed range [MIN, MAX]
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
|
||||
<para><glosslist>
|
||||
<glossentry>
|
||||
<glossterm>David LaBlanc</glossterm>
|
||||
<glossterm>David LeBlanc</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>This library is inspired by <ulink
|
||||
url="http://safeint.codeplex.com">David LeBlanc's SafeInt
|
||||
Library</ulink> . I found this library very well done in every way
|
||||
and useful in my embedded systems work. This motivated me to take to
|
||||
and useful in my embedded systems work. This motivated me to take it to
|
||||
the "next level".</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
@@ -28,11 +28,11 @@
|
||||
<para>Andrzej Commented and reviewed the library as it was
|
||||
originally posted on the <ulink
|
||||
url="http://www.blincubator.com">Boost Library Incubator</ulink>.
|
||||
The the consequent back and forth motivated me to invest more effort
|
||||
The consequent back and forth motivated me to invest more effort
|
||||
in developing documentation and examples to justify the utility,
|
||||
indeed the necessity, for this library. He also noted many errors in
|
||||
code, documentation, and tests. Without his interested and effort, I
|
||||
do not believe the library would have progressed beyond it's initial
|
||||
code, documentation, and tests. Without his interest and effort, I
|
||||
do not believe the library would have progressed beyond its initial
|
||||
stages.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
@@ -43,7 +43,7 @@ int main(){
|
||||
// In such cases, there is no runtime overhead from using safe types.
|
||||
safe_t x = 127;
|
||||
safe_t y = 2;
|
||||
auto z = x + y; // z is guarenteed correct without any runtime overhead or interrupt.
|
||||
auto z = x + y; // z is guaranteed correct without any runtime overhead or exception.
|
||||
|
||||
return 0;
|
||||
}</programlisting>
|
||||
|
||||
@@ -29,7 +29,7 @@ template<class R, class T, class U>
|
||||
constexpr checked_result<R>
|
||||
checked::multiply(const T & t, const U & u);
|
||||
|
||||
// safe division on unsafe types
|
||||
// safe division on primitive types
|
||||
template<class R, class T, class U>
|
||||
constexpr checked_result<R>
|
||||
checked::divide(const T & t, const U & u);
|
||||
@@ -38,7 +38,7 @@ template<class R, class T, class U>
|
||||
constexpr checked_result<R>
|
||||
checked::divide_automatic(const T & t, const U & u);
|
||||
|
||||
// safe modulus on unsafe types
|
||||
// safe modulus on primitive types
|
||||
template<class R, class T, class U>
|
||||
constexpr checked_result<R>
|
||||
checked::modulus(const T & t, const U & u);
|
||||
@@ -86,7 +86,7 @@ checked::bitwise_xor(const T & t, const U & u);
|
||||
<section>
|
||||
<title>Complexity</title>
|
||||
|
||||
<para>Each function performs one and only one arithmetic operation</para>
|
||||
<para>Each function performs one and only one arithmetic operation.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -110,7 +110,7 @@ checked_result<result_base_type> r = checked::multiply<int>(24, 42);
|
||||
<title>Notes</title>
|
||||
|
||||
<para>Some compilers have command line switches (e.g. -ftrapv) which
|
||||
enable special behavior such erroneous integer operations are detected at
|
||||
enable special behavior such that erroneous integer operations are detected at
|
||||
run time. The library has been implemented in such a way that these
|
||||
facilities are not used. It's possible they might be helpful in particular
|
||||
environment. These could be be exploited by re-implementing some functions
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<section>
|
||||
<title>Description</title>
|
||||
|
||||
<para>checked_result is a wrapper class designed to hold result of some
|
||||
<para>checked_result is a wrapper class designed to hold the result of some
|
||||
operation. It can hold either the result of the operation or information
|
||||
on why the operation failed to produce a valid result. Note that this type
|
||||
is an internal feature of the library and shouldn't be exposed to library
|
||||
@@ -213,7 +213,7 @@
|
||||
|
||||
<entry>void</entry>
|
||||
|
||||
<entry>invoke exception in accordance exception_type
|
||||
<entry>invoke exception in accordance with exception_type
|
||||
value</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
|
||||
@@ -8,17 +8,17 @@
|
||||
<title>Description</title>
|
||||
|
||||
<para>This policy is used to promote safe types in arithmetic expressions
|
||||
according the standard rules in the C++ standard. But rather than using
|
||||
according to the rules in the C++ standard. But rather than using
|
||||
the native C++ standard types supported by the compiler, it uses types
|
||||
whose length in number of bits is specified by the template
|
||||
parameters.</para>
|
||||
|
||||
<para>This policy is useful for running test program which use C++
|
||||
<para>This policy is useful for running test programs which use C++
|
||||
portable integer types but which are destined to run on an architecture
|
||||
which is different than the one on which the test program is being built
|
||||
and run. This can happen when developing code for embedded systems.
|
||||
Algorithms developed or borrowed from one architecture but destined for
|
||||
another can be tested on the desk top.</para>
|
||||
another can be tested on the desktop.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -108,7 +108,7 @@
|
||||
uses a very small microprocessor and a very limited C compiler. The chip
|
||||
is so small, you can't print anything from the code, log, debug or
|
||||
anything else. One debugs this code by using the "burn" and "crash" method
|
||||
- you burn the chip (download the code) run the code, observe the results,
|
||||
- you burn the chip (download the code), run the code, observe the results,
|
||||
make changes and try again. This is a crude method which is usually the
|
||||
one used. But it can be quite time consuming.</para>
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
other problems), make our algorithm testing environment differ from our
|
||||
target environment. We can address this by defining INT as a safe integer
|
||||
with a range of 8 bits. By using a custom promotion policy, we can force
|
||||
the evaluation of C++ expressions test environment to be the same as that
|
||||
the evaluation of C++ expressions in the test environment to be the same as that
|
||||
in the target environment. Also in our target environment, we can trap any
|
||||
overflows or other errors. So we can write and test our code on our
|
||||
desktop system and download the code to the target knowing that it just
|
||||
@@ -161,7 +161,7 @@ using uint16 = safe_t<std::uint16_t>;
|
||||
using uint32 = safe_t<std::uint32_t>;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Mock defines, functions etc which are in he "real application
|
||||
// Mock defines, functions etc which are in the "real application"
|
||||
|
||||
...
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<para>Up until now, we've focused on detecting when incorrect results are
|
||||
produced and handling these occurrences either by throwing an exception or
|
||||
invoking some designated function. We've achieved our goal of detecting and
|
||||
handling arithmetically incorrect behavior - but at what cost. It is a fact
|
||||
handling arithmetically incorrect behavior - but at what cost? It is a fact
|
||||
that many C++ programmers will find this trade-off unacceptable. So the
|
||||
question arises as to how we might minimize or eliminate this runtime
|
||||
penalty.</para>
|
||||
@@ -54,12 +54,12 @@
|
||||
<para>So the result of the sum of two integer types may result in another
|
||||
integer type. If the values are large, the result can exceed the size that
|
||||
the resulting integer type can hold. This is what we call "overflow". The
|
||||
C/C++ standard characterises this as undefined behavior and leaves to
|
||||
C/C++ standard characterizes this as undefined behavior and leaves to
|
||||
compiler implementors the decision as to how such a situation will be
|
||||
handled. Usually, this means just truncating the result to fit into the
|
||||
result type - which sometimes will make the result arithmetically
|
||||
incorrect. However, depending on the compiler, compile time switch
|
||||
settings, the such case may result in some sort of run time
|
||||
incorrect. However, depending on the compiler and compile time switch
|
||||
settings, such cases may result in some sort of run time
|
||||
exception.</para>
|
||||
|
||||
<para>The complete signature for a safe integer type is:</para>
|
||||
@@ -77,7 +77,7 @@ safe;
|
||||
type promotion policy are consistent with those of standard C++ </para>
|
||||
|
||||
<para>Up until now, we've focused on detecting when this happens and
|
||||
invoking an interrupt or other kind of error handler.</para>
|
||||
invoking an exception or other kind of error handler.</para>
|
||||
|
||||
<para>But now we look at another option. Using the <link
|
||||
linkend="safe_numerics.promotion_policy.models.automatic"><code>automatic</code></link>
|
||||
@@ -117,7 +117,7 @@ long z = (long)x + (long)y; // can never overflow</programlisting>
|
||||
|
||||
<listitem>
|
||||
<para>Since the result type is guaranteed to hold the result, there
|
||||
is no need to check for errors - they can't happen !!! The usage of
|
||||
is no need to check for errors - they can't happen!!! The usage of the
|
||||
<link
|
||||
linkend="safe_numerics.exception_policy.models.trap_exception"><code>trap_exception</code></link>
|
||||
exception policy enforces this guarantee.</para>
|
||||
@@ -173,7 +173,7 @@ z = <long>[-4294967296,4294967294] = 2147483649
|
||||
<listitem>
|
||||
<para>the <link
|
||||
linkend="safe_numerics.promotion_policy.models.automatic"><code>automatic</code></link>
|
||||
type promotion policy has rendered the result of the some of two
|
||||
type promotion policy has rendered the result of the sum of two
|
||||
<code>integers</code> as a <code>long</code> type.</para>
|
||||
</listitem>
|
||||
|
||||
@@ -184,7 +184,7 @@ z = <long>[-4294967296,4294967294] = 2147483649
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>We do not need to use <code>try/catch</code> idiom to handle
|
||||
<para>We do not need to use the <code>try/catch</code> idiom to handle
|
||||
arithmetic errors - we will have none.</para>
|
||||
</listitem>
|
||||
|
||||
@@ -262,15 +262,15 @@ z = <signed char>[-24,82] = 77
|
||||
<para><itemizedlist>
|
||||
<listitem>
|
||||
<para>As before, we define a type <code>safe_t</code> to reflect our
|
||||
view of legal values for this program. This uses <link
|
||||
view of legal values for this program. This uses the <link
|
||||
linkend="safe_numerics.promotion_policy.models.automatic"><code>automatic</code></link>
|
||||
type promotion policy as well as <link
|
||||
type promotion policy as well as the <link
|
||||
linkend="safe_numerics.exception_policies.trap_exception"><code>trap_exception</code></link>
|
||||
exception policy to enforce elimination of runtime penalties.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The function f accepts only arguments of type
|
||||
<para>The function <code>f</code> accepts only arguments of type
|
||||
<code>safe_t</code> so there is no need to check the input values.
|
||||
This performs the functionality of <emphasis><emphasis
|
||||
role="bold">programming by contract</emphasis></emphasis> with no
|
||||
@@ -289,7 +289,7 @@ z = <signed char>[-24,82] = 77
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>On calling of the function f, arguments of type
|
||||
<para>On calling of the function <code>f</code>, arguments of type
|
||||
<code>input_safe_t</code> are converted to values of type
|
||||
<code>safe_t</code> . In this particular example, it can be
|
||||
determined at compile time that construction of an instance of a
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
<row>
|
||||
<entry><code>EP</code></entry>
|
||||
|
||||
<entry>A type that full fills the requirements of an
|
||||
ExceptionPollicy</entry>
|
||||
<entry>A type that fulfills the requirements of an
|
||||
ExceptionPolicy</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -145,7 +145,7 @@
|
||||
|
||||
<para>If an exceptional condition is detected at runtime throw the
|
||||
exception. Safe types use this exception policy as the default if no
|
||||
other one is specified.</para>
|
||||
other policy is specified.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem id="safe_numerics.exception_policy.models.ignore_exception">
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</question>
|
||||
|
||||
<answer>
|
||||
<para>I used "safe" in large part this is what has been used by other
|
||||
<para>I used "safe" in large part because this is what has been used by other
|
||||
similar libraries. Maybe a better word might have been "correct" but
|
||||
that would raise similar concerns. I'm not inclined to change this.
|
||||
I've tried to make it clear in the documentation what the problem that
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
<answer>
|
||||
<para>Actually, I believe that this can/should be applied to any type
|
||||
T which satisfies the type requirement "Numeric" type as defined in
|
||||
T which satisfies the type requirement <code>Numeric</code> type as defined in
|
||||
the documentation. So there should be specializations
|
||||
<code>safe<float></code> and related types as well as new types
|
||||
like <code>safe<fixed_decimal></code> etc. But the current
|
||||
@@ -83,7 +83,7 @@
|
||||
<qandaentry>
|
||||
<question>
|
||||
<para>Isn't putting a defensive check just before any potential
|
||||
undefined behavior is often considered a bad practice?</para>
|
||||
undefined behavior often considered a bad practice?</para>
|
||||
</question>
|
||||
|
||||
<answer>
|
||||
@@ -104,7 +104,7 @@
|
||||
|
||||
<answer>
|
||||
<para>As far as is known as of this writing, the library does not
|
||||
presume that the underlying hardware is two's compliment. However,
|
||||
presume that the underlying hardware is two's complement. However,
|
||||
this has yet to be verified in a rigorous way.</para>
|
||||
</answer>
|
||||
</qandaentry>
|
||||
@@ -118,7 +118,7 @@
|
||||
<answer>
|
||||
<para><code>safe<T></code> behaves like a "number" just as int
|
||||
does. It has max, min, etc Any code which uses numeric limits to test
|
||||
a type <code>T</code> should works with <code>safe<T></code>.
|
||||
a type <code>T</code> should work with <code>safe<T></code>.
|
||||
<code>safe<T></code> is a drop-in replacement for <code>T</code>
|
||||
so it has to implement all the operations.</para>
|
||||
</answer>
|
||||
@@ -141,7 +141,7 @@
|
||||
arithmetic is not intended, such as array indexes. Finally, the
|
||||
modulus for such an integer would vary depending upon the machine
|
||||
architecture. For these reasons, in the context of this library, an
|
||||
unsigned integer is considered to a representation of a subset of
|
||||
unsigned integer is considered to be a representation of a subset of
|
||||
integers. Note that this decision is consistent with
|
||||
<citation>INT30-C</citation>, “Ensure that unsigned integer operations
|
||||
do not wrap” in the CERT C Secure Coding Standard
|
||||
@@ -163,7 +163,7 @@
|
||||
meta-programming. But this wasn't enough. It became apparent that the
|
||||
only way to really minimize run-time penalty was to implement
|
||||
compile-time integer range arithmetic - a pretty elaborate sub
|
||||
library. By doing range arithmetic at compiler-time, I could skip
|
||||
library. By doing range arithmetic at compile-time, I could skip
|
||||
runtime checking on many/most integer operations. C++11 constexpr
|
||||
wasn't quite enough to do the job. C++14 constexpr can do the job. The
|
||||
library currently relies very heavily on C++14 constexpr. I think that
|
||||
@@ -180,7 +180,7 @@
|
||||
</question>
|
||||
|
||||
<answer>
|
||||
<para>C++ has evolved way beyond the original C language. But C++ it's
|
||||
<para>C++ has evolved way beyond the original C language. But C++ is
|
||||
still (mostly) compatible with C. So most C programs can be compiled
|
||||
with a C++ compiler. The problems of incorrect arithmetic afflict both
|
||||
C and C++. Suppose we have a legacy C program designed for some
|
||||
@@ -207,7 +207,7 @@ using pic16_promotion = boost::numeric::cpp<
|
||||
16, // long
|
||||
32 // long long
|
||||
>;
|
||||
// define safe types used desktop version of the program.
|
||||
// define safe types used in the desktop version of the program.
|
||||
template <typename T> // T is char, int, etc data type
|
||||
using safe_t = boost::numeric::safe<
|
||||
T,
|
||||
@@ -231,7 +231,7 @@ typedef long int32_t;
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Run the tests and change code to address any thrown
|
||||
<para>Run the tests and change the code to address any thrown
|
||||
exceptions.</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
<section>
|
||||
<title>Description</title>
|
||||
|
||||
<para>A type is fulfills the requirements of an Integer if it has the
|
||||
<para>A type fulfills the requirements of an Integer if it has the
|
||||
properties of a integer.</para>
|
||||
|
||||
<para>More specifically, a type T is Integer if there exists
|
||||
<para>More specifically, a type T is Integer if there exists a
|
||||
specialization of <code>std::numeric_limits<T> for which
|
||||
std::numeric_limits<T>.is_integer</code> is equal to
|
||||
<code>true</code>. See the documentation for standard library class
|
||||
@@ -20,7 +20,7 @@
|
||||
specializations for all built-in numeric types. Note that this concept is
|
||||
distinct from the C++ standard library type traits
|
||||
<code>is_integral</code> and <code>is_arithmetic</code>. These latter
|
||||
fulfill the requirement of the concept Numeric. But there are types which
|
||||
fulfill the requirements of the concept Numeric. But there are types which
|
||||
fulfill this concept for which <code>is_arithmetic<T>::value ==
|
||||
false</code>. For example see <code>safe<int></code>.</para>
|
||||
</section>
|
||||
@@ -134,7 +134,7 @@
|
||||
|
||||
<entry>V</entry>
|
||||
|
||||
<entry>and of t and u padded out max # bits in t, u</entry>
|
||||
<entry>and of t and u padded out to max # bits in t, u</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -142,7 +142,7 @@
|
||||
|
||||
<entry>V</entry>
|
||||
|
||||
<entry>or of t and u padded out max # bits in t, u</entry>
|
||||
<entry>or of t and u padded out to max # bits in t, u</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -150,7 +150,7 @@
|
||||
|
||||
<entry>V</entry>
|
||||
|
||||
<entry>exclusive or of t and u padded out max # bits in t,
|
||||
<entry>exclusive or of t and u padded out to max # bits in t,
|
||||
u</entry>
|
||||
</row>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<section>
|
||||
<title>Template Parameters</title>
|
||||
|
||||
<para>R must model the type requirements <link
|
||||
<para>R must model the type requirements of<link
|
||||
linkend="safe_numerics.numeric">Numeric</link></para>
|
||||
</section>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<row>
|
||||
<entry><code>l, u</code></entry>
|
||||
|
||||
<entry>lower and upper Numeric limits of an interval</entry>
|
||||
<entry>Lower and upper Numeric limits of an interval</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -103,7 +103,7 @@
|
||||
<section>
|
||||
<title>Valid Expressions</title>
|
||||
|
||||
<para>Note that all expressions are constexpr .</para>
|
||||
<para>Note that all expressions are constexpr.</para>
|
||||
|
||||
<para><informaltable>
|
||||
<tgroup cols="3">
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
<title>Description</title>
|
||||
|
||||
<para>This type contains the functions to return a safe type corresponding
|
||||
to the C++ type resulting for a given arithmetic operation.</para>
|
||||
to the C++ type resulting from a given arithmetic operation.</para>
|
||||
|
||||
<para>Usage of this policy with safe types will produce the exact same
|
||||
arithmetic results that using normal unsafe integer types will. Hence this
|
||||
policy is suitable as a drop-in replacement for these unsafe types. It's
|
||||
policy is suitable as a drop-in replacement for these unsafe types. Its
|
||||
main function is to trap incorrect arithmetic results when using C++ for
|
||||
integer arithmetic.</para>
|
||||
</section>
|
||||
@@ -70,12 +70,12 @@ int main(){
|
||||
safe_int8 x = 127;
|
||||
safe_int8 y = 2;
|
||||
safe_int8 z;
|
||||
// rather than producing and invalid result an exception is thrown
|
||||
// rather than producing an invalid result an exception is thrown
|
||||
z = x + y;
|
||||
assert(false); // never arrive here
|
||||
}
|
||||
catch(std::exception & e){
|
||||
// which can catch here
|
||||
// which we can catch here
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ int main(){
|
||||
safe_int8 x = 127;
|
||||
safe_int8 y = 2;
|
||||
safe<int, native> z; // z can now hold the result of the addition of any two 8 bit numbers
|
||||
z = x + y; // is guarenteed correct without any runtime overhead or interrupt.
|
||||
z = x + y; // is guaranteed correct without any runtime overhead or exception.
|
||||
|
||||
return 0;
|
||||
}</programlisting>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<title>Template Parameters</title>
|
||||
|
||||
<para>Function objects to be invoked are specified for each error
|
||||
condition are specified via template parameters.</para>
|
||||
condition via template parameters.</para>
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="4">
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
<para>A type is Numeric if it has the properties of a number.</para>
|
||||
|
||||
<para>More specifically, a type T is Numeric if there exists
|
||||
<para>More specifically, a type T is Numeric if there exists a
|
||||
specialization of <code>std::numeric_limits<T></code>. See the
|
||||
documentation for standard library class <code>numeric_limits</code>. The
|
||||
documentation for the standard library class <code>numeric_limits</code>. The
|
||||
standard library includes such specializations for all the built-in
|
||||
numeric types. Note that this concept is distinct from the C++ standard
|
||||
library type traits <code>is_integral</code> and
|
||||
@@ -36,13 +36,13 @@
|
||||
<row>
|
||||
<entry><code>T, U, V</code></entry>
|
||||
|
||||
<entry>A type that is a model of the Numeric</entry>
|
||||
<entry>A type that is a model of Numeric</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><code>t, u</code></entry>
|
||||
|
||||
<entry>An object of type modeling Numeric</entry>
|
||||
<entry>An object of a type modeling Numeric</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
char y;
|
||||
auto z = x + y</programlisting>the type of <code>z</code> will be an
|
||||
<code>int</code>. This is a consequence for the standard rules for type
|
||||
promotion for C/C++ arithmetic. A key feature of library permits one to
|
||||
promotion for C/C++ arithmetic. A key feature of the library permits one to
|
||||
specify his own type promotion rules via a PromotionPolicy class.</para>
|
||||
</section>
|
||||
|
||||
@@ -46,7 +46,7 @@ auto z = x + y</programlisting>the type of <code>z</code> will be an
|
||||
<row>
|
||||
<entry><code>t, u, v</code></entry>
|
||||
|
||||
<entry>An object of type modeling Numeric</entry>
|
||||
<entry>An object of a type modeling Numeric</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
@@ -174,7 +174,7 @@ char y;
|
||||
auto z = x + y; // could result in overflow
|
||||
safe<int> sx;
|
||||
auto sz = sx + y; // promotes expression type to a safe<long int> which requires no result checking
|
||||
is guaranteed not to overflow.
|
||||
// is guaranteed not to overflow.
|
||||
|
||||
safe_unsigned_range<1, 4> a;
|
||||
safe_unsigned_range<2, 4> b;
|
||||
@@ -182,12 +182,12 @@ auto c = a + b; // c will be of type safe_unsigned_range<3, 8> and cannot
|
||||
|
||||
<para>Type sz will be a <link
|
||||
linkend="safe_numerics.safe_numeric_concept">SafeNumeric</link> type
|
||||
which is guaranteed to hold he result of x + y. In this case that will
|
||||
which is guaranteed to hold the result of x + y. In this case that will
|
||||
be a long int (or perhaps a long long) depending upon the compiler and
|
||||
machine architecture. In this case, there will be no need for any
|
||||
special checking on the result and there can be no overflow.</para>
|
||||
|
||||
<para>Type of c will be a signed character as that type can be
|
||||
<para>The type of c will be a signed character as that type can be
|
||||
guaranteed to hold the sum so no overflow checking is done.</para>
|
||||
|
||||
<para>This policy is documented in <link
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<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 trap in some way.</para>
|
||||
an arithmetically correct value or to trap in some way.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -99,7 +99,7 @@
|
||||
<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
|
||||
<entry><para>The underlying type. Currently only integer types are
|
||||
supported</para></entry>
|
||||
</row>
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
|
||||
<para>Implements all expressions and only those expressions defined by the
|
||||
<link linkend="safe_numerics.safe_numeric_concept">SafeNumeric</link> type
|
||||
requirements. This, the result type of such an expression will be another
|
||||
requirements. 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>
|
||||
</section>
|
||||
@@ -170,7 +170,7 @@
|
||||
<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 a
|
||||
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
|
||||
@@ -180,7 +180,7 @@
|
||||
<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 a error
|
||||
<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 type. Behavior of this program could vary according to the
|
||||
machine architecture in question.</para>
|
||||
@@ -217,7 +217,7 @@ int main(){
|
||||
creates the possibility of subtle bugs. It conflicts with the purpose of
|
||||
the library in a fundamental way. The library specifies that these
|
||||
conversions are errors that are to be invoked at compile time. If one
|
||||
wants to switch between save and built-in types via an alias, this type
|
||||
wants to switch between safe and built-in types via an alias, this type
|
||||
of code will have to be fixed so that implicit conversions to built-in
|
||||
types do not occur. In our view, this will be a net improvement to the
|
||||
code in any case.</para>
|
||||
@@ -226,10 +226,10 @@ int main(){
|
||||
<section>
|
||||
<title>Guarantee correct behavior at compile time.</title>
|
||||
|
||||
<para>In some instance catching an error at run time is not sufficient.
|
||||
<para>In some instances, catching an error at run time is not sufficient.
|
||||
We want to be sure that the program can never fail. To achieve this, use
|
||||
the trap_exception exception policy rather than the default throw
|
||||
exception policy.</para>
|
||||
the <code>trap_exception</code> exception policy rather than the default
|
||||
<code>throw_exception</code> policy.</para>
|
||||
|
||||
<para>The following program will emit a compile error at any statement
|
||||
which might possibly result in incorrect behavior.</para>
|
||||
@@ -255,17 +255,16 @@ void f(){
|
||||
<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. This can be justified
|
||||
by the observe</para>
|
||||
types to larger sizes before doing the arithmetic.</para>
|
||||
|
||||
<para>Stepping back, we can see that many of the cases of invalid
|
||||
arithmetic are wouldn't exist if results types were larger. So we can
|
||||
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
|
||||
non-default type promotion policy automatic. The policy stores the
|
||||
non-default type promotion policy <code>automatic</code>. The policy stores the
|
||||
result of an expression in the smallest size that can accommodate the
|
||||
largest value that an expression can yield. All the work is done at
|
||||
compile time - checking for exceptions necessary (input is of course an
|
||||
compile time - no checking for exceptions is necessary (input is of course an
|
||||
exception). The following example illustrates this.</para>
|
||||
|
||||
<para><programlisting>#include <boost/numeric/safe.hpp>
|
||||
|
||||
@@ -101,8 +101,8 @@ safe<int> f(safe<int> x, safe<int> y){
|
||||
</programlisting>
|
||||
|
||||
<para><note>
|
||||
<para>Library code in this document resides in the name space
|
||||
<code>boost::numeric</code>. This name space has generally been
|
||||
<para>Library code in this document resides in the namespace
|
||||
<code>boost::numeric</code>. This namespace has generally been
|
||||
eliminated from text, code and examples in order to improve
|
||||
readability of the text.</para>
|
||||
</note>The addition expression is checked at runtime or (if possible) at
|
||||
@@ -214,7 +214,7 @@ safe<int> f(safe<int> x, safe<int> y){
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Enforce of other program requirements using ranged integer
|
||||
<para>Enforce other program requirements using ranged integer
|
||||
types. The library includes the types <code>safe_range<Min,
|
||||
Max></code> and <code>safe_literal<N</code>>. These types
|
||||
can be used to improve program correctness and performance.</para>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<title>Description</title>
|
||||
|
||||
<para>A safe type which holds a literal value. This is required to be able
|
||||
to initialize other safe type in such a way that exception code is not
|
||||
to initialize other safe types in such a way that an exception code is not
|
||||
generated. It is also useful when creating constexpr versions of safe
|
||||
types. It contains one immutable value known at compile time and hence can
|
||||
be used in any constexpr expression.</para>
|
||||
@@ -117,7 +117,7 @@
|
||||
<title>Inherited Valid Expressions</title>
|
||||
|
||||
<para>SafeLiteral types are immutable. Hence they only inherit those valid
|
||||
expressions which don't change the value. The excludes assignment,
|
||||
expressions which don't change the value. This excludes assignment,
|
||||
increment, and decrement operators. Other than that, they can be used
|
||||
anywhere a SafeNumeric type can be used.</para>
|
||||
</section>
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
|
||||
<entry>unspecified S</entry>
|
||||
|
||||
<entry><para>construct a instance of S from a value of type T. f
|
||||
<entry><para>construct an instance of S from a value of type T. If
|
||||
the value t cannot be represented as an instance of type S1, it
|
||||
is an error.</para></entry>
|
||||
</row>
|
||||
@@ -186,7 +186,7 @@
|
||||
|
||||
<entry>S</entry>
|
||||
|
||||
<entry><para>construct a uninitialized instance of
|
||||
<entry><para>construct an uninitialized instance of
|
||||
S.</para></entry>
|
||||
</row>
|
||||
|
||||
@@ -217,7 +217,7 @@
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Result of any binary operation where one or both of the operands
|
||||
<para>The result of any binary operation where one or both of the operands
|
||||
is a SafeNumeric type is also a SafeNumeric type.</para>
|
||||
</listitem>
|
||||
|
||||
@@ -250,6 +250,7 @@ int main(){
|
||||
<section>
|
||||
<title>Complexity Guarantees</title>
|
||||
|
||||
|
||||
<para>There are no complexity guarantees explicitly enforced here.
|
||||
However, it would be very surprising if any implementation were to be more
|
||||
complex that O(0);</para>
|
||||
@@ -258,11 +259,11 @@ int main(){
|
||||
<section>
|
||||
<title>Invariants</title>
|
||||
|
||||
<para>The fundamental requirement of a SafeNumeric type is that implements
|
||||
all C++ operations permitted on it's base type in a way the prevents the
|
||||
<para>The fundamental requirement of a SafeNumeric type is that it implements
|
||||
all C++ operations permitted on its base type in a way the prevents the
|
||||
return of an incorrect arithmetic result. Various implementations of this
|
||||
concept may handle circumstances which produce such results differently (
|
||||
throw exception, compile time trap, etc..) no implementation should return
|
||||
concept may handle circumstances which produce such results differently
|
||||
(throw exception, compile time trap, etc..) no implementation should return
|
||||
an arithmetically incorrect result.</para>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
fundamental software components described here. It is not necessary to
|
||||
know about these components to use the library. This information has been
|
||||
included to help those who want to understand how the library works so
|
||||
they can extend it, correct bugs in it, or understand it's limitations.
|
||||
they can extend it, correct bugs in it, or understand its limitations.
|
||||
These components are also interesting in their own right. For all these
|
||||
reasons, they are documented here. In general terms, the library works in
|
||||
the following manner:</para>
|
||||
@@ -126,9 +126,9 @@
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>All unary/binary expressions where one of the operands is a
|
||||
"safe" type are Overloaded. These overloads are declared and defined
|
||||
"safe" type are overloaded. These overloads are declared and defined
|
||||
in the header file "safe_integer.hpp". SFINAE - "Substitution Failure
|
||||
Is Not An Error and <code>std::enable_if</code> are key features of
|
||||
Is Not An Error" and <code>std::enable_if</code> are key features of
|
||||
C++ used to define these overloads in a correct manner.</para>
|
||||
</listitem>
|
||||
|
||||
@@ -143,12 +143,12 @@
|
||||
<listitem>
|
||||
<para>Given the ranges of the operands, determine the range of
|
||||
the result of the operation using interval arithmetic. This is
|
||||
implemented in the "interval.hpp" header file using constexpr
|
||||
implemented in the "interval.hpp" header file using the <code>constexpr</code>
|
||||
facility of C++14.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>if the range of the result type includes the range of the
|
||||
<para>If the range of the result type includes the range of the
|
||||
result of the operation, no run time checking of the result is
|
||||
necessary. So the operation reduces to the original built-in
|
||||
C/C++ operation.</para>
|
||||
@@ -165,7 +165,7 @@
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>if a valid result has been obtained, it is passed to the
|
||||
<para>If a valid result has been obtained, it is passed to the
|
||||
caller.</para>
|
||||
</listitem>
|
||||
|
||||
@@ -192,10 +192,10 @@
|
||||
<section id="safe_numerics.performance_tests">
|
||||
<title>Performance Tests</title>
|
||||
|
||||
<para>Our goal creating facilities which make it possible write programs
|
||||
<para>Our goal is to create facilities which make it possible to write programs
|
||||
known to be correct. But we also want programmers to actually use the
|
||||
facilities we provide here. This won't happen if using these facilities
|
||||
impacts performance to a significant degree. Although we've take
|
||||
impacts performance to a significant degree. Although we've taken
|
||||
precautions to avoid doing this, the only real way to know is to create
|
||||
and run some tests.</para>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
[MIN, MAX]. A <code>safe_signed_range<MIN, MAX, PP, EP></code> or
|
||||
<code>safe_unsigned_range<MIN, MAX, PP, EP></code> can be used
|
||||
anywhere an arithmetic type is permitted. Any expression which uses either
|
||||
of these types is guaranteed to return an arithmetically correct value or
|
||||
of these types is guaranteed to return an arithmetically correct value or to
|
||||
trap in some way.</para>
|
||||
</section>
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<row>
|
||||
<entry><code>MIN</code></entry>
|
||||
|
||||
<entry>must be non-integer literal</entry>
|
||||
<entry>must be a non-negative literal</entry>
|
||||
|
||||
<entry>The minimum non-negative integer value that this type may
|
||||
hold</entry>
|
||||
@@ -162,7 +162,7 @@
|
||||
|
||||
<para>Implements all expressions and only those expressions defined by the
|
||||
<link linkend="safe_numerics.safe_numeric_concept">SafeNumeric</link> type
|
||||
requirements. This, the result type of such an expression will be another
|
||||
requirements. 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>
|
||||
</section>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<section id="safenumerics.throw_exception">
|
||||
<title>Description</title>
|
||||
|
||||
<para>This exception policy throws a an exception derived from
|
||||
<para>This exception policy throws an exception derived from
|
||||
<code>std::exception</code> any time some operation would result in an
|
||||
incorrect result. This is the default exception handling policy.</para>
|
||||
</section>
|
||||
@@ -31,7 +31,7 @@
|
||||
<title>Example of use</title>
|
||||
|
||||
<para>This example is somewhat contrived as throw_exception is the default
|
||||
for safe types. Hence it usually is not necessarily to request it
|
||||
for safe types. Hence it usually is not necessary to request it
|
||||
explicitly.</para>
|
||||
|
||||
<programlisting>#include "../../include/safe_integer.hpp"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<section>
|
||||
<title>Description</title>
|
||||
|
||||
<para>This exception policy will trap at compile time any operation
|
||||
<para>This exception policy will trap at compile time any operation that
|
||||
<emphasis><emphasis role="bold">COULD</emphasis></emphasis> result in a
|
||||
runtime exception. It can be used in an environment which can tolerate
|
||||
neither arithmetic errors nor runtime overhead. Usage of this policy will
|
||||
@@ -32,8 +32,6 @@
|
||||
<section>
|
||||
<title>Example of use</title>
|
||||
|
||||
<para>The following</para>
|
||||
|
||||
<programlisting>#include "../../include/safe_integer.hpp"
|
||||
#include "../../include/automatic.hpp"
|
||||
#include "../../include/exception_policies.hpp"
|
||||
|
||||
@@ -20,22 +20,18 @@
|
||||
responsibility to ensure such undefined behavior is avoided.</para>
|
||||
|
||||
<para>This program demonstrates this problem. The solution is to replace
|
||||
instances of <code>char</code> type with <code>safe<char></code>
|
||||
instances of <code>int</code> type with <code>safe<int></code>
|
||||
type.</para>
|
||||
|
||||
<programlisting><xi:include href="../../examples/example1.cpp"
|
||||
parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>
|
||||
|
||||
<para>Note that I've used <code>char</code> types in this example to make
|
||||
the problem and solution easier to see. The exact same example could have
|
||||
been done with <code>int</code> types albeit with different values.</para>
|
||||
</section>
|
||||
|
||||
<section id="safe_numerics.tutorial.2">
|
||||
<title>Arithmetic Operations Can Overflow Silently</title>
|
||||
|
||||
<para>A variation of the above is when a value is incremented/decremented
|
||||
beyond it's domain. This is a common problem with for loops.</para>
|
||||
beyond its domain. This is a common problem with for loops.</para>
|
||||
|
||||
<programlisting><xi:include href="../../examples/example2.cpp"
|
||||
parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>
|
||||
@@ -48,9 +44,8 @@
|
||||
<section id="safe_numerics.tutorial.4">
|
||||
<title>Implicit Conversions Can Lead to Erroneous Results</title>
|
||||
|
||||
<para>At CPPCon 2016 Jon Kalb gave a very entertaining (and disturbing
|
||||
example) <ulink
|
||||
url="https://www.youtube.com/watch?v=wvtFGa6XJDU">lightening talk</ulink>
|
||||
<para>At CPPCon 2016 Jon Kalb gave a very entertaining (and disturbing) <ulink
|
||||
url="https://www.youtube.com/watch?v=wvtFGa6XJDU">lightning talk</ulink>
|
||||
related to C++ expressions.</para>
|
||||
|
||||
<para>The talk included a very, very simple example similar to the
|
||||
@@ -62,7 +57,7 @@
|
||||
<para>A normal person reads the above code and has to be dumbfounded by
|
||||
this. The code doesn't do what the text - according to the rules of
|
||||
algebra - says it does. But C++ doesn't follow the rules of algebra - it
|
||||
has it's own rules. There is generally no compile time error. You can get
|
||||
has its own rules. There is generally no compile time error. You can get
|
||||
a compile time warning if you set some specific compile time switches. The
|
||||
explanation lies in reviewing how C++ reconciles binary expressions
|
||||
(<code>a < b</code> is an expression here) where operands are different
|
||||
@@ -71,7 +66,7 @@
|
||||
<para><itemizedlist>
|
||||
<listitem>
|
||||
<para>Determines the "best" common type for the two operands. In
|
||||
this case, application the the rules in the C++ standard dictate
|
||||
this case, application of the rules in the C++ standard dictate
|
||||
that this type will be an <code>unsigned int</code>.</para>
|
||||
</listitem>
|
||||
|
||||
@@ -83,7 +78,7 @@
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Performs the calculation - in this case it's,
|
||||
<para>Performs the calculation - in this case it's
|
||||
<code><</code>, the "less than" operation. Since 1 is less than
|
||||
4294967295 the program prints "b is less than a".</para>
|
||||
</listitem>
|
||||
@@ -93,21 +88,21 @@
|
||||
should be pretty familiar with the implicit conversion rules of the C++
|
||||
standard. These are available in a copy of the standard and also in the
|
||||
canonical reference book <citetitle><link linkend="stroustrup">The C++
|
||||
Programming Language</link></citetitle> . (both are over 1200 pages
|
||||
Programming Language</link></citetitle> (both are over 1200 pages
|
||||
long!). Even experienced programmers won't spot this issue and know to
|
||||
take precautions to avoid it. And this is a relatively easy one to spot.
|
||||
In the more general case this will use integers which don't correspond to
|
||||
easily recognizable numbers and/or will be buried as a part of some more
|
||||
complex expression.</para>
|
||||
|
||||
<para>This example generated a good amount of web traffic along with every
|
||||
one's pet suggestions. See for example <ulink
|
||||
<para>This example generated a good amount of web traffic along with
|
||||
everyone's pet suggestions. See for example <ulink
|
||||
url="https://bulldozer00.com/2016/10/16/the-unsigned-conundrum/">a blog
|
||||
post with every one's favorite "solution"</ulink>. All the proposed
|
||||
post with everyone's favorite "solution"</ulink>. All the proposed
|
||||
"solutions" have disadvantages and attempts to agree on how handle this
|
||||
are ultimately fruitless in spite of, or maybe because of, the <ulink
|
||||
url="https://twitter.com/robertramey1/status/795742870045016065">emotional
|
||||
content</ulink>. Our solution is by far the simplest: Just use the safe
|
||||
content</ulink>. Our solution is by far the simplest: just use the safe
|
||||
numerics library as shown in the example above.</para>
|
||||
|
||||
<para>Note that in this particular case, there is absolutely no extra
|
||||
@@ -135,7 +130,7 @@ Not using safe numerics
|
||||
Using safe numerics
|
||||
10000
|
||||
detected error:converted negative value to unsigned
|
||||
</screen>This solution is simple, Just replace instances of the
|
||||
</screen>This solution is simple, just replace instances of
|
||||
<code>int</code> with <code>safe<int></code>.</para>
|
||||
</section>
|
||||
|
||||
@@ -149,10 +144,10 @@ detected error:converted negative value to unsigned
|
||||
|
||||
<para><programlisting><xi:include href="../../examples/example5.cpp"
|
||||
parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>Collections
|
||||
like standard arrays, vectors do array index checking in some function
|
||||
like standard arrays and vectors do array index checking in some function
|
||||
calls and not in others so this may not be the best example. However it
|
||||
does illustrate the usage of <code>safe_range<T></code> for
|
||||
assigning legal range to variables. This will guarantee that under no
|
||||
assigning legal ranges to variables. This will guarantee that under no
|
||||
circumstances will the variable contain a value outside of the specified
|
||||
range.</para>
|
||||
</section>
|
||||
@@ -187,7 +182,7 @@ detected error:converted negative value to unsigned
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>invocation some configuration functions which convert these
|
||||
<para>invocation of some configuration functions which convert these
|
||||
hardware events into C++ exceptions</para>
|
||||
</listitem>
|
||||
</itemizedlist>It's not all that clear how one would detect and recover
|
||||
@@ -195,7 +190,7 @@ detected error:converted negative value to unsigned
|
||||
ignore the issue which usually results in immediate program termination
|
||||
when this situation occurs.</para>
|
||||
|
||||
<para>This library will detect for divide by zero errors before the
|
||||
<para>This library will detect divide by zero errors before the
|
||||
operation is invoked. Any errors of this nature are handled according to
|
||||
the ErrorPolicy selected by the library user.</para>
|
||||
|
||||
@@ -207,7 +202,7 @@ detected error:converted negative value to unsigned
|
||||
<title>Programming by Contract is Too Slow</title>
|
||||
|
||||
<para>Programming by Contract is a highly regarded technique. There has
|
||||
been much written about it has been proposed as an addition to the C++
|
||||
been much written about it and it has been proposed as an addition to the C++
|
||||
language <citation>Garcia</citation><citation>Crowl &
|
||||
Ottosen</citation>. It (mostly) depends upon runtime checking of parameter
|
||||
and object values upon entry to and exit from every function. This can
|
||||
@@ -220,15 +215,15 @@ detected error:converted negative value to unsigned
|
||||
runtime cost.</para>
|
||||
|
||||
<para>The Safe Numerics Library has facilities which, in many cases, can
|
||||
check guarantee parameter requirements with little or no runtime overhead.
|
||||
check guaranteed parameter requirements with little or no runtime overhead.
|
||||
Consider the following example:</para>
|
||||
|
||||
<para><programlisting><xi:include href="../../examples/example7.cpp"
|
||||
parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting></para>
|
||||
|
||||
<para>In the example above the function convert incurs significant runtime
|
||||
<para>In the example above, the function <code>convert</code> incurs significant runtime
|
||||
cost every time the function is called. By using "safe" types, this cost
|
||||
is moved to moment when the parameters are constructed. Depending on how
|
||||
is moved to the moment when the parameters are constructed. Depending on how
|
||||
the program is constructed, this may totally eliminate extraneous
|
||||
computations for parameter requirement type checking. In this scenario,
|
||||
there is no reason to suppress the checking for release mode and our
|
||||
|
||||
@@ -15,10 +15,7 @@ int main(int argc, const char * argv[]){
|
||||
int z;
|
||||
// this produces an invalid result !
|
||||
z = x + y;
|
||||
// but assert fails to detect it since C++ implicitly
|
||||
// converts variables to int before evaluating he expression!
|
||||
// assert(z == x + y);
|
||||
std::cout << static_cast<int>(z) << " != " << x + y << std::endl;
|
||||
std::cout << z << " != " << x + y << std::endl;
|
||||
std::cout << "error NOT detected!" << std::endl;
|
||||
}
|
||||
catch(std::exception){
|
||||
@@ -28,14 +25,14 @@ int main(int argc, const char * argv[]){
|
||||
std::cout << "Using safe numerics" << std::endl;
|
||||
try{
|
||||
using namespace boost::numeric;
|
||||
safe<int> x = 127;
|
||||
safe<int> x = INT_MAX;
|
||||
safe<int> y = 2;
|
||||
safe<int> z;
|
||||
// rather than producing and invalid result an exception is thrown
|
||||
// rather than producing an invalid result an exception is thrown
|
||||
z = x + y;
|
||||
}
|
||||
catch(std::exception & e){
|
||||
// which can catch here
|
||||
// which we can catch here
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
#include "../include/safe_integer.hpp"
|
||||
|
||||
int main(int argc, const char * argv[]){
|
||||
// problem: checking of externally produced value can be overlooked
|
||||
// problem: cannot recover from arithmetic errors
|
||||
std::cout << "example 7: ";
|
||||
std::cout << "cannot recover From arithmetic errors" << std::endl;
|
||||
std::cout << "cannot recover from arithmetic errors" << std::endl;
|
||||
std::cout << "Not using safe numerics" << std::endl;
|
||||
|
||||
try{
|
||||
@@ -21,14 +21,14 @@ int main(int argc, const char * argv[]){
|
||||
std::cout << "error detected!" << std::endl;
|
||||
}
|
||||
|
||||
// solution: assign externally retrieved values to safe equivalents
|
||||
// solution: replace int with safe<int>
|
||||
std::cout << "Using safe numerics" << std::endl;
|
||||
try{
|
||||
using namespace boost::numeric;
|
||||
safe<int> x = 1;
|
||||
safe<int> y = 0;
|
||||
std::cout << x / y;
|
||||
std::cout << " error detected!" << std::endl;
|
||||
std::cout << " error NOT detected!" << std::endl;
|
||||
}
|
||||
catch(std::exception & e){
|
||||
std::cout << e.what() << std::endl;
|
||||
|
||||
@@ -24,7 +24,7 @@ int main(){
|
||||
std::cout << "error detected!" << std::endl;
|
||||
}
|
||||
|
||||
// solution: replace int with safe<int> and char with safe<char>
|
||||
// solution: replace int with safe<int> and unsigned int with safe<unsigned int>
|
||||
std::cout << "Using safe numerics" << std::endl;
|
||||
try{
|
||||
using namespace boost::numeric;
|
||||
|
||||
@@ -22,7 +22,7 @@ int main(int argc, const char * argv[]){
|
||||
std::cout << "error detected!" << std::endl;
|
||||
}
|
||||
|
||||
// solution: asign externally retrieved values to safe equivalents
|
||||
// solution: assign externally retrieved values to safe equivalents
|
||||
std::cout << "Using safe numerics" << std::endl;
|
||||
{
|
||||
using namespace boost::numeric;
|
||||
|
||||
@@ -12,7 +12,7 @@ unsigned int convert(
|
||||
const unsigned int & minutes
|
||||
) {
|
||||
// check that parameters are within required limits
|
||||
// invokes a runtime cost EVERYTIME the function is called
|
||||
// invokes a runtime cost EVERY TIME the function is called
|
||||
// and the overhead of supporting an interrupt.
|
||||
// note high runtime cost!
|
||||
if(minutes > 59)
|
||||
@@ -23,7 +23,7 @@ unsigned int convert(
|
||||
}
|
||||
|
||||
// Use safe numeric to enforce program contract automatically
|
||||
// define convient typenames for hours and minutes hh:mm
|
||||
// define convenient typenames for hours and minutes hh:mm
|
||||
using hours_t = boost::numeric::safe_unsigned_range<0, 23>;
|
||||
using minutes_t = boost::numeric::safe_unsigned_range<0, 59>;
|
||||
|
||||
@@ -52,9 +52,9 @@ int main(int argc, const char * argv[]){
|
||||
std::cout << "Using safe numerics" << std::endl;
|
||||
|
||||
try {
|
||||
// parameters are guarenteed to meet requirements
|
||||
// parameters are guaranteed to meet requirements
|
||||
hours_t hours(10);
|
||||
minutes_t minutes(83); // interrupt thrown here
|
||||
minutes_t minutes(83); // exception thrown here
|
||||
// so the following will never throw
|
||||
safe_convert(hours, minutes);
|
||||
}
|
||||
@@ -76,7 +76,7 @@ int main(int argc, const char * argv[]){
|
||||
}
|
||||
|
||||
try {
|
||||
// parameters are guarenteed to meet requirements when
|
||||
// parameters are guaranteed to meet requirements when
|
||||
// implicitly constructed to safe types to match function signature
|
||||
safe_convert(10, 83);
|
||||
}
|
||||
@@ -102,7 +102,7 @@ int main(int argc, const char * argv[]){
|
||||
convert(hours, minutes); // zero (depending on compiler) runtime overhead
|
||||
|
||||
// since unsafe types can be implicitly converted to corresponding
|
||||
// safe types we can just pass the unsafe types. checkin will occur
|
||||
// safe types we can just pass the unsafe types. checking will occur
|
||||
// when the safe type is constructed.
|
||||
safe_convert(10, 17); // runtime cost in creating parameters
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ using safe_t = safe_signed_range<
|
||||
trap_exception
|
||||
>;
|
||||
|
||||
// define variables use for input
|
||||
// define variables used for input
|
||||
using input_safe_t = safe_signed_range<
|
||||
-24,
|
||||
82,
|
||||
|
||||
Reference in New Issue
Block a user