Merge pull request #27 from insideoutclub/master

Fixing Typos in Documentation and Examples
This commit is contained in:
Robert Ramey
2017-04-08 11:21:00 -07:00
committed by GitHub
30 changed files with 146 additions and 156 deletions

View File

@@ -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]

View File

@@ -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>

View File

@@ -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>

View File

@@ -29,7 +29,7 @@ template&lt;class R, class T, class U&gt;
constexpr checked_result&lt;R&gt;
checked::multiply(const T &amp; t, const U &amp; u);
// safe division on unsafe types
// safe division on primitive types
template&lt;class R, class T, class U&gt;
constexpr checked_result&lt;R&gt;
checked::divide(const T &amp; t, const U &amp; u);
@@ -38,7 +38,7 @@ template&lt;class R, class T, class U&gt;
constexpr checked_result&lt;R&gt;
checked::divide_automatic(const T &amp; t, const U &amp; u);
// safe modulus on unsafe types
// safe modulus on primitive types
template&lt;class R, class T, class U&gt;
constexpr checked_result&lt;R&gt;
checked::modulus(const T &amp; t, const U &amp; u);
@@ -86,7 +86,7 @@ checked::bitwise_xor(const T &amp; t, const U &amp; 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&lt;result_base_type&gt; r = checked::multiply&lt;int&gt;(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

View File

@@ -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>

View File

@@ -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&lt;std::uint16_t&gt;;
using uint32 = safe_t&lt;std::uint32_t&gt;;
////////////////////////////////////////////////////////////////
// Mock defines, functions etc which are in he "real application
// Mock defines, functions etc which are in the "real application"
...

View File

@@ -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 = &lt;long&gt;[-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 = &lt;long&gt;[-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 = &lt;signed char&gt;[-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 = &lt;signed char&gt;[-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

View File

@@ -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">

View File

@@ -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&lt;float&gt;</code> and related types as well as new types
like <code>safe&lt;fixed_decimal&gt;</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&lt;T&gt;</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&lt;T&gt;</code>.
a type <code>T</code> should work with <code>safe&lt;T&gt;</code>.
<code>safe&lt;T&gt;</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&lt;
16, // long
32 // long long
&gt;;
// define safe types used desktop version of the program.
// define safe types used in the desktop version of the program.
template &lt;typename T&gt; // T is char, int, etc data type
using safe_t = boost::numeric::safe&lt;
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>

View File

@@ -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&lt;T&gt; for which
std::numeric_limits&lt;T&gt;.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&lt;T&gt;::value ==
false</code>. For example see <code>safe&lt;int&gt;</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>

View File

@@ -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">

View File

@@ -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 &amp; e){
// which can catch here
// which we can catch here
std::cout &lt;&lt; e.what() &lt;&lt; std::endl;
}
@@ -84,7 +84,7 @@ int main(){
safe_int8 x = 127;
safe_int8 y = 2;
safe&lt;int, native&gt; 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>

View File

@@ -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">

View File

@@ -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&lt;T&gt;</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>

View File

@@ -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&lt;int&gt; sx;
auto sz = sx + y; // promotes expression type to a safe&lt;long int&gt; which requires no result checking
is guaranteed not to overflow.
// is guaranteed not to overflow.
safe_unsigned_range&lt;1, 4&gt; a;
safe_unsigned_range&lt;2, 4&gt; b;
@@ -182,12 +182,12 @@ auto c = a + b; // c will be of type safe_unsigned_range&lt;3, 8&gt; 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

View File

@@ -11,7 +11,7 @@
<para>A <code>safe&lt;T, PP , EP&gt;</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&lt;T&gt;</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 &lt;boost/numeric/safe.hpp&gt;

View File

@@ -101,8 +101,8 @@ safe&lt;int&gt; f(safe&lt;int&gt; x, safe&lt;int&gt; 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&lt;int&gt; f(safe&lt;int&gt; x, safe&lt;int&gt; 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&lt;Min,
Max&gt;</code> and <code>safe_literal&lt;N</code>&gt;. These types
can be used to improve program correctness and performance.</para>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -14,7 +14,7 @@
[MIN, MAX]. A <code>safe_signed_range&lt;MIN, MAX, PP, EP&gt;</code> or
<code>safe_unsigned_range&lt;MIN, MAX, PP, EP&gt;</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>

View File

@@ -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"

View File

@@ -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"

View File

@@ -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&lt;char&gt;</code>
instances of <code>int</code> type with <code>safe&lt;int&gt;</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 &lt; 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>&lt;</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&lt;int&gt;</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&lt;T&gt;</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 &amp;
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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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,