diff --git a/doc/boostbook/automatic.xml b/doc/boostbook/automatic.xml
index f302342..b3a58f8 100644
--- a/doc/boostbook/automatic.xml
+++ b/doc/boostbook/automatic.xml
@@ -7,8 +7,77 @@
Description
- This type contains the functions to return a type with sufficient
- capacity to hold the result of a given arithmetic operation.
+ This type contains the meta-functions to return a type with
+ sufficient capacity to hold the result of a given binary arithmetic
+ operation.
+
+ The standard C/C++ procedure for executing arithmetic operations on
+ operands of different types is:
+
+
+
+ Convert operands to some common type using a somewhat
+ elaborate elaborate rules defined in the C++ standard.
+
+
+
+ Execute the operation.
+
+
+
+ If the result of the operation cannot fit in the common type
+ of the operands, discard the high order bits.
+
+ The automatic promotion policy replaces the standard
+ C/C++ procedure for the following one:
+
+ Determine the signed/unsigned property of the result according
+ to the following rules.
+
+ For addition. If the operands are both unsigned the
+ result will be unsigned. Otherwise it will be signed.
+
+
+
+ For subtraction, the result will be signed.
+
+
+
+ For multiplication, division and modulus, if both
+ operations are unsigned the result will be unsigned.
+ Otherwise, the result will be signed.
+
+
+
+ For left/right shift, the sign of the result will be the
+ sign of the left operand.
+
+
+
+
+
+ Determine the smallest size of the signed or unsigned type
+ which can be guaranteed hold the result.
+
+
+
+ If this size exceeds the maximum size supported by the
+ compiler, use the maximum size supported by the compiler.
+
+
+
+ Execute the operation.
+
+ If the result cannot be contained in the result type as
+ above, invoke an error procedure.
+
+
+
+ Otherwise, return the result in the result type
+
+
+
+
diff --git a/doc/boostbook/checked_result.xml b/doc/boostbook/checked_result.xml
index b366a01..952425d 100644
--- a/doc/boostbook/checked_result.xml
+++ b/doc/boostbook/checked_result.xml
@@ -99,7 +99,14 @@
r
- An object of type R
+ An instance of type R
+
+
+
+ e
+
+ An instance of type exception_type
@@ -164,9 +171,9 @@
static_cast<const char *>(c)
- R
+ const char *
- extract wrapped value - asserts if not possible
+ returns pointer to error message
@@ -187,7 +194,7 @@
boost::logic::triboolcompare the wrapped values of two checked_result
- instances. If either one contains an invalid value, return
+ instances. If either one contains an error_type value, return
boost::logic::tribool::indeterminant.
diff --git a/doc/boostbook/cpp.xml b/doc/boostbook/cpp.xml
index 2b575f4..dc1f801 100644
--- a/doc/boostbook/cpp.xml
+++ b/doc/boostbook/cpp.xml
@@ -121,11 +121,11 @@
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
- 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
- has to work. This is a huge time saver and confidence builder. The
+ the evaluation of C++ expressions int 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 has to work. This is a huge time saver and confidence builder. The
following code is taken from a real project which has used this
method.
@@ -182,8 +182,6 @@ uint16 get_stopping_distance(LEMPARAMETER velocity){
...
Note the usage of the compile time trap policy in order to detect at
- compile time any possible error conditions. As I write this, this is still
- being refined. Hopefully this will be available by the time you read
- this.
+ compile time any possible error conditions.
diff --git a/doc/boostbook/eliminate_runtime_penalty.xml b/doc/boostbook/eliminate_runtime_penalty.xml
index b71e5df..692e474 100644
--- a/doc/boostbook/eliminate_runtime_penalty.xml
+++ b/doc/boostbook/eliminate_runtime_penalty.xml
@@ -17,6 +17,12 @@
special exception policy: trap_exception.
+
+ In this document we use the term "trap" to mean invocation of some
+ message at compile time. We use "throw" to indicate a runtime exception.
+
+
+
Now,
any expression which The promotion rules implemented in the default native
- type promotion policy are consistent with those of standard C++
+ linkend="safe_numerics.types.native">native type promotion
+ policy are consistent with those of standard C++
Up until now, we've focused on detecting when this happens and
invoking an interrupt or other kind of error handler.But now we look at another option. Using the automatic
- type promotion policy, we can change the rules of C++ arithmetic for safe
- types to something like the following:
+ linkend="safe_numerics.types.automatic">automatic type
+ promotion policy, we can change the rules of C++ arithmetic for safe types
+ to something like the following:
@@ -110,7 +116,7 @@ long z = (long)x + (long)y; // can never overflow
One could do this by editing his code manually, but such a
task would be tedious, error prone, and leave the resulting code
hard to read and verify. Using the automatic
+ linkend="safe_numerics.types.automatic">automatic
type promotion policy will achieve the equivalent result without
these problems.
@@ -119,7 +125,7 @@ long z = (long)x + (long)y; // can never overflow
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
trap_exception
+ linkend="safe_numerics.types.trap_exception">trap_exception
exception policy enforces this guarantee.
@@ -150,7 +156,7 @@ long z = (long)x + (long)y; // can never overflow
generated. Depending on the application, it should be rare to generate
error checking code, and even more rare to actually invoke it. Any such
instances are detected at compile time by the trap_exception
+ linkend="safe_numerics.types.trap_exception">trap_exception
exception policy.This small example illustrates how to use automatic type promotion
@@ -172,14 +178,14 @@ z = <long>[-4294967296,4294967294] = 2147483649
that:the automatic
+ linkend="safe_numerics.types.automatic">automatic
type promotion policy has rendered the result of the some of two
integers as a long type.our program compiles without error - even when using the trap_exception
+ linkend="safe_numerics.types.trap_exception">trap_exception
exception policy
diff --git a/doc/boostbook/exception_policy_concept.xml b/doc/boostbook/exception_policy_concept.xml
index 8e8604a..8d7c810 100644
--- a/doc/boostbook/exception_policy_concept.xml
+++ b/doc/boostbook/exception_policy_concept.xml
@@ -28,15 +28,15 @@
EP
- A type that full fills the requirements of an
+ A type that fulfills the requirements of an
ExceptionPollicymessage
- A const char * which refers to a text message about the
- cause of an exception
+ A const char * which refers to a text message
+ about the cause of an exception
@@ -49,11 +49,11 @@
Any operations which result in integers which cannot be represented
as some Numeric type will throw an exception.
-
+
-
+
@@ -156,15 +156,13 @@
- template<void (*F)(const char *), void (*G)(const char
- *), void (*H)(const char *)>
-
boost::numeric::no_exception_supportIf you want to specify specific behavior for particular
exception types, use this policy. The most likely situation is where
- you don't have exception support and you want to trap "exceptions" by
- calling your own special functions.
+ you don't have exception support and you want to handle runtime errors
+ by calling your own special functions. This should permit usage of the
+ library in environments where C++ exceptions are not supported.
diff --git a/doc/boostbook/exception_type.xml b/doc/boostbook/exception_type.xml
index 20f8e5a..16b57ae 100644
--- a/doc/boostbook/exception_type.xml
+++ b/doc/boostbook/exception_type.xml
@@ -124,7 +124,7 @@ dispatch<EP>(const exception_type & e, const char * msg);#include "exception_policy.hpp"
-dispatch(overflow_error, "operation resulted in overflow");
+dispatch<boost::numeric::throw_exception>(overflow_error, "operation resulted in overflow");
diff --git a/doc/boostbook/faq.xml b/doc/boostbook/faq.xml
index 1a585f4..aa0329b 100644
--- a/doc/boostbook/faq.xml
+++ b/doc/boostbook/faq.xml
@@ -24,7 +24,7 @@
- Can safe types be used as drop-in replacement for built-in
+ Can safe types be used as drop-in replacements for built-in
types?
@@ -214,12 +214,12 @@ using safe_t = boost::numeric::safe<
pic16_promotion,
boost::numeric::throw_exception // use for compiling and running tests
>;
-typedef safe_t<std::int16_t> int16_t;
-typedef safe_t<std::int32_t> int32_t;
+typedef safe_t<std::int_least16_t> int16_t;
+typedef safe_t<std::int_least32_t> int32_t;
#else
/* using C on embedded platform */
-typedef int int16_t;
-typedef long int32_t;
+typedef int int_least16_t;
+typedef long int_least16_t;
#endif
diff --git a/doc/boostbook/native.xml b/doc/boostbook/native.xml
index 711b5c0..023d4c1 100644
--- a/doc/boostbook/native.xml
+++ b/doc/boostbook/native.xml
@@ -1,7 +1,7 @@
-
+native
@@ -12,7 +12,7 @@
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.
@@ -56,7 +56,7 @@ void int f(safe_int x, safe_int y){
The following example illustrates the native type being
passed as a template parameter for the type safe<int>.
This example is slightly contrived in that safe<int>
- has native as it's default promotion parameter so explicitly
+ has native as its default promotion parameter so explicitly
using native is not necessary.#include <cassert>
diff --git a/doc/boostbook/no_exception_support.xml b/doc/boostbook/no_exception_support.xml
index 2f62882..f6f3e6b 100644
--- a/doc/boostbook/no_exception_support.xml
+++ b/doc/boostbook/no_exception_support.xml
@@ -2,7 +2,8 @@
- no_exception_support<O, U = O, R =O, D = O>
+ no_exception_support<NoError, UnInitalized, Overflow, Underflow,
+ Range, Domain>Description
@@ -27,8 +28,6 @@
-
-
@@ -37,8 +36,6 @@
Parameter
- Default
-
Type RequirementsDescription
@@ -47,43 +44,61 @@
- O
+ NoError
-
+ void (*NoError)(const char *)
- void (*O)(const char *)
+ Function to call on when an operation is invoked
+ which COULD throw but does not.
+
+
+
+ UnInitalized
+
+ void (*UnInitalizized)(const char *)
+
+ Function to call on when value is
+ uninitialized
+
+
+
+ Overflow
+
+ void (*Overflow)(const char *)Function to call on overflow error
- O
+ Overflow
- O
+ void (*Overflow)(const char *)
- void (*U)(const char *)
+ Function to call on overflow error
+
+
+
+ Underflow
+
+ void (*Underflow)(const char *)Function to call on underflow error
- O
+ Range
- O
-
- void (*R)(const char *)
+ void (*Range)(const char *)Function to call on range error
- O
+ Domain
- O
+ void (*Domain)(const char *)
- void (*D)(const char *)
-
- Function to call on domain error
+ Function to call on domain error
@@ -110,12 +125,16 @@
[A code fragment involving the type.]
- void overflow(const char * msg);
+ void no_error(const char * msg);
+void uninitialize(const char * msg);
+void overflow(const char * msg);
void underflow(const char * msg);
void range_error(const char * msg);
void domain_error(const char * msg);
using ep = ignore_exception<
+ no_error,
+ uninitialized,
overflow,
underflow,
range_error,
diff --git a/doc/boostbook/promotion_policy_concept.xml b/doc/boostbook/promotion_policy_concept.xml
index c12354c..eb2d1d4 100644
--- a/doc/boostbook/promotion_policy_concept.xml
+++ b/doc/boostbook/promotion_policy_concept.xml
@@ -25,9 +25,9 @@ auto z = x + ythe type of z will be an
-
+
-
+
@@ -38,15 +38,16 @@ auto z = x + ythe type of z will be an
- T, U, V
+ T, UA type that is a model of the Numeric concept
- t, u, v
+ R
- An object of type modeling Numeric
+ An object of type modeling Numeric which can be used to
+ construct a SafeNumeric type.
@@ -56,8 +57,11 @@ auto z = x + ythe type of z will be an
Valid Expressions
- Any operations which result in integers which cannot be represented
- as some Numeric type will throw an exception.
+ Any operations which result in integers which cannot be represented
+ as some Numeric type will throw an exception.These expressions return a
+ type which can be used as the basis create a SafeNumeric type.
+
+
@@ -107,19 +111,21 @@ auto z = x + ythe type of z will be an
- PP::left_shift_result<T>::type
+ PP::left_shift_result<T,
+ U>::typeunspecified Numeric type
- PP::right_shift_result<T>::type
+ PP::right_shift_result<T,
+ u>::typeunspecified Numeric type
- PP::bitwise_result<T>::type
+ PP::bitwise_result<T, U>::typeunspecified Numeric type
@@ -150,12 +156,16 @@ auto z = x + ythe type of z will be an
int x;
char y;
auto z = x + y; // could result in overflow
-safe<int> sx;
-auto sz = sx + y; // includes code which traps overflows at runtime
+safe<int, native> sx;
+auto sz = sx + y; // standard C++ code which detects errors
- The type of sz will be safe< type of z >.
+ Type sz will be a SafeNumeric type
+ based on int. If the result exceeds the maximum value
+ that can be stored in an int, an error is
+ detected.
- This policy is documented in The native policy is documented in Promotion Policies -
native.
@@ -172,13 +182,14 @@ auto sz = sx + y; // includes code which traps overflows at runtimeint x;
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.
-
+safe<int, automatic> sx;
+auto sz = sx + y;
+ // sz is a safe type based on long
+ // hence sz is guaranteed not to overflow.
safe_unsigned_range<1, 4> a;
safe_unsigned_range<2, 4> b;
-auto c = a + b; // c will be of type safe_unsigned_range<3, 8> and cannot overflow
+auto c = a + b; // c will be a safe type with a range [3,8] and cannot overflow
+
Type sz will be a SafeNumeric type
@@ -191,8 +202,8 @@ auto c = a + b; // c will be of type safe_unsigned_range<3, 8> and cannot
guaranteed to hold the sum so no overflow checking is done.This policy is documented in Promotion Policies -
- automatic
+ linkend="safe_numerics.promotion_policies.automatic">Promotion
+ Policies - automatic
diff --git a/doc/boostbook/safe.xml b/doc/boostbook/safe.xml
index 046921b..79c2a01 100644
--- a/doc/boostbook/safe.xml
+++ b/doc/boostbook/safe.xml
@@ -4,7 +4,7 @@
safe<T, PP, EP>
-
+
Description
@@ -35,8 +35,7 @@
T
- Underlying type from which a safe type is being
- derived
+ Underlying type from on which safe type based
@@ -181,8 +180,8 @@
As a Drop-in replacement for standard integer types.The following program will throw an exception and emit a error
- message at runtime if any of several events result in an incorrect
- arithmetic type. Behavior of this program could vary according to the
+ message at runtime if any of several events result in incorrect
+ arithmetic results. Behavior of this program could vary according to the
machine architecture in question.#include <exception>
@@ -217,10 +216,12 @@ 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.
+ code in any case. Remember that explicit variable casts *(via
+ static_cast) are allowed but the casting is guaranteed not to alter the
+ arithmetic value of the variable.
@@ -234,10 +235,11 @@ int main(){
The following program will emit a compile error at any statement
which might possibly result in incorrect behavior.
- This is because there is no way to guarantee that the expression i
- * i will return an arithmetically correct result. Since we know that the
- program cannot compile if there is any possibility of arithmetic error,
- we can dispense with the exception handling used above.
+ This is because there is no way to guarantee that the expression
+ i * i will return an arithmetically correct result. Since
+ we know that the program cannot compile if there is any possibility of
+ arithmetic error, we can dispense with the exception handling used
+ above.#include <iostream>
#include <boost/numeric/safe.hpp>
@@ -255,18 +257,18 @@ void f(){
Adjust type promotion rules.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
+ types to larger sizes before doing the arithmetic.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
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
- 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
- exception). The following example illustrates this.
+ non-default type promotion policy, automatic. The policy
+ stores the result of an expression in the smallest size that can
+ accommodate the largest value that an expression can yield. All this
+ work is done at compile time so the runtime overhead is diminished. In
+ those cases where it's still possible to generate an incorrect result,
+ an exception still might be invoked.
#include <boost/numeric/safe.hpp>
#include <iostream>
@@ -281,6 +283,13 @@ void f(){
std::numeric_limits<safe_int>::max() * std::numeric_limits<safe_int>::max()
); // always true
}
+
+ Here is an example where safe types are not drop-in replacements
+ for their underlying types. While reading the program, one must remember
+ that normal type promotion rules don't apply. That is, your program
+ might better reflect your true intentions and it might be less likely to
+ contain errors. But, strictly speaking, it's not really C++ any more.
+
diff --git a/doc/boostbook/safe_introduction.xml b/doc/boostbook/safe_introduction.xml
index 8766f6e..56d3207 100644
--- a/doc/boostbook/safe_introduction.xml
+++ b/doc/boostbook/safe_introduction.xml
@@ -79,9 +79,9 @@
applies to other operations such as subtraction, multiplication etc. .
C/C++ often automatically and silently converts some integer types to
others in the course of implementing binary operations and similar
- problems occur in this case as well. Since the problems and their solution
- are similar, We'll confine the current discussion to just this one
- example.
+ problems occur in this case as well. Since the problems and their
+ solutions are similar, we'll confine the current discussion to just this
+ one example.
@@ -90,10 +90,11 @@
This library implements special versions of int,
unsigned, etc. which behave exactly like the original ones
except that the results of these
- operations are guaranteed to be either arithmetically correct or invoke an
- error. Using this library, the above example would be rendered as:
+ operations are guaranteed to be either to be arithmetically correct or to
+ invoke an error. Using this library, the above example would be rendered
+ as:
- #include <boost/safe_numeric/safe_integer.hpp>
+ #include <boost/safe_numerics/safe_integer.hpp>
using namespace boost::numeric;
safe<int> f(safe<int> x, safe<int> y){
return x + y; // throw exception if correct result cannot be returned
@@ -215,9 +216,9 @@ safe<int> f(safe<int> x, safe<int> y){
Enforce of other program requirements using ranged integer
- types. The library includes the types safe_range<Min,
- Max> and safe_literal<N>. These types
- can be used to improve program correctness and performance.
+ types. The library includes types for safe ranges and safe
+ literals of signed and unsigned types. These types can be
+ used to improve program correctness and performance.
diff --git a/doc/boostbook/safe_literal.xml b/doc/boostbook/safe_literal.xml
index 314a923..fe6f6bc 100644
--- a/doc/boostbook/safe_literal.xml
+++ b/doc/boostbook/safe_literal.xml
@@ -82,8 +82,7 @@
PromotionPolicy<PP>
- Default value is boost::numeric::native
+ Default value is void
@@ -93,8 +92,7 @@
linkend="safe_numerics.exception_policy">Exception
Policy<EP>
- Default value is boost::numeric::throw_exception
+ Default value is void
diff --git a/doc/boostbook/safe_numeric_concept.xml b/doc/boostbook/safe_numeric_concept.xml
index 4879689..1842c3e 100644
--- a/doc/boostbook/safe_numeric_concept.xml
+++ b/doc/boostbook/safe_numeric_concept.xml
@@ -44,7 +44,8 @@
T, UTypes fulfilling Numeric type
+ linkend="safe_numerics.numeric">Numeric or Integer type
requirements
@@ -55,7 +56,7 @@
- S, S1, S2
+ SA type fulfilling SafeNumeric type requirements
@@ -69,19 +70,20 @@
op
- C++ infix operator
+ C++ infix operator which is supported by underlying numeric
+ typeprefix_op
- C++ prefix operator: -, +, ~
+ C++ prefix operator: ++, --, -, +, ~postfix_op
- C++ postfix operator
+ C++ postfix operator: ++, --
@@ -99,7 +101,7 @@
-
+
@@ -146,7 +148,7 @@
prefix_op S
- unspecified S
+ Sinvoke safe C++ operator prefix_op and
return another SafeNumeric type.
@@ -155,7 +157,7 @@
S postfix_op
- unspecified S
+ Sinvoke safe C++ operator postfix_op
and return another SafeNumeric type.
@@ -164,20 +166,20 @@
s assign_op t
- S1
+ Sconvert t to type S1 and assign it to s1. If the
- value t cannot be represented as an instance of type S1, it is
- an error.
+ value t cannot be represented as an instance of type S, it is an
+ error.S(t)
- unspecified S
+ Sconstruct a instance of S from a value of type T. f
- the value t cannot be represented as an instance of type S1, it
+ the value t cannot be represented as an instance of type S, it
is an error.
@@ -200,16 +202,57 @@
requirements for a SafeNumeric type.
+
+ get_promotion_policy<S>::type
+
+ PP
+
+ return the Promotion Policy associated with this
+ type. If there is no such policy associated with
+ this type, void shall be returned.
+
+
+
+ get_exception_policy<S>::type
+
+ EP
+
+ return the Exception Policy associated with this
+ type. If there is no such policy associated with
+ this type, void shall be returned.
+
+
+
+ base_type<S>::type
+
+ Numeric
+
+ return the underlying Numeric type on which this
+ Safe type is based.
+
+
+
+ base_value(s)
+
+ T
+
+ return the underlying value of an instance of the
+ Safe type.
+
+
static_cast<T>(s)T
- convert the value of s to type T. If the value of s
- cannot be correctly represented as a type T, it is an error.
- Note that implicit casting from a safe type to a built-in
- integer type is expressly prohibited and should invoke a compile
- time error.
+ convert the value of s to type T. In contrast to
+ base_value(s) described above, T may be any Numeric type. If the
+ value of s cannot be correctly represented as a type T, it is an
+ error which will be handled according to the Exception Policy of
+ the variable s. This is an explicit, checked cast. Implicit
+ casting from a safe type to a built-in integer type is expressly
+ prohibited and should invoke a compile time
+ error.
@@ -227,8 +270,19 @@
- Binary expressions which are not assignments require that
- promotion and exception policies be identical.
+ Binary expressions that are not assignments place similar
+ requirements on both Exception and Promotion policies of Safe
+ arguments.
+
+ at least one argument must be a Safe type with a non void
+ policy.
+
+
+
+ if both arguments are Safe types with non void policies,
+ the policies must be the same.
+
+
@@ -241,8 +295,9 @@ int main(){
safe<long> y;
f(y); // compile time error
return 0;
-}This behavior prevents a safe<T> from
- being a "drop-in" replacement for a T.
+}This behavior distinguishes a Safe type from its underlying
+ type T and prevents a safe<T> from being a
+ "drop-in" replacement for a T.
@@ -250,20 +305,20 @@ int main(){
Complexity Guarantees
- 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);
+ There are no complexity guarantees explicitly enforced here. Usage
+ of safe operations should add a fixed amount of time to compilation with
+ each usage.InvariantsThe fundamental requirement of a SafeNumeric type is that implements
- all C++ operations permitted on it's base type in a way the prevents the
+ 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
- an arithmetically incorrect result.
+ concept may handle circumstances which produce such results differently
+ (throw exception, compile time trap, etc..) no implementation should
+ return an arithmetically incorrect result.
diff --git a/doc/boostbook/safe_numerics.xml b/doc/boostbook/safe_numerics.xml
index 573b154..f922e76 100644
--- a/doc/boostbook/safe_numerics.xml
+++ b/doc/boostbook/safe_numerics.xml
@@ -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:
@@ -179,10 +179,10 @@
-
- MIN, MAX
- Minimum and maximum values that the range can
- represent.
+ Minimum and maximum Numeric values that the
+ range can represent.
@@ -60,15 +61,17 @@
PP
- Promotion Policy. A type which specifies the result type of
- an expression using safe types.
+ Promotion
+ Policy. A type which specifies the result type of an
+ expression using safe types.EP
- Exception Policy. A type containing members which are
- called when a correct result cannot be returned
+ Exception
+ Policy. A type containing members which are called when a
+ correct result cannot be returned
@@ -100,19 +103,19 @@
MIN
- must be non-integer literal
+ must be Numeric literal
- The minimum non-negative integer value that this type may
- hold
+ The minimum maximum value that this type may holdMAX
- must be a non-negative literal
+ must be a Numeric literal
- The maximum non-negative integer value that this type may
- hold
+ The maximum lowest value that this type may hold
@@ -177,11 +180,12 @@
Example of use
- #include <safe/numeric/safe_range.hpp>
+ #include <safe/numerics/safe_range.hpp> // safe_unsigned range
+#include <safe/numerics/safe_integer.hpp> // safe
void f(){
using namespace boost::numeric;
- safe_unsigned_range<7, 24> i
+ safe_unsigned_range<7, 24> i;
// since the range is included in [0,255], the underlying type of i
// will be an unsigned char.
i = 0; // throws out_of_range exception
@@ -193,9 +197,9 @@ void f(){
// the range of i is [7, 24] and the range of j is [0,255]
// if either or both types are safe types, the result is a safe type
- // determined by promotion policy. With the default native promotion policy
- // k will be safe<unsigned int>
- static_assert(std::is_same<decltype(k), safe<unsigned int>);
+ // determined by promotion policy.
+ // With the default native promotion policy k will be safe<unsigned int>
+ static_assert(std::is_same<decltype(k), safe<unsigned int>>);
}
diff --git a/doc/boostbook/trap_exception.xml b/doc/boostbook/trap_exception.xml
index 6780dfb..0249aa2 100644
--- a/doc/boostbook/trap_exception.xml
+++ b/doc/boostbook/trap_exception.xml
@@ -7,7 +7,7 @@
Description
- This exception policy will trap at compile time any operation
+ This exception policy will trap at compile time any operation which
COULD 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
diff --git a/doc/boostbook/tutorial.xml b/doc/boostbook/tutorial.xml
index 84d9df4..66f3d90 100644
--- a/doc/boostbook/tutorial.xml
+++ b/doc/boostbook/tutorial.xml
@@ -15,12 +15,15 @@
sense. This is called "overflow". Since word size can differ between
machines, code which produces mathematically correct results in one set of
circumstances may fail when re-compiled on a machine with different
- hardware. When this occurs, Most C++ compilers will continue to execute
- with no indication that the results are wrong. It is the programmer's
- responsibility to ensure such undefined behavior is avoided.
+ hardware.
+
+ When this occurs in a C++ program, the program will usually continue
+ to execute with no indication that the results are wrong. It is the
+ programmer's responsibility to write his code so as to ensure such
+ undefined behavior is avoided.This program demonstrates this problem. The solution is to replace
- instances of int type with safe<int>
+ instances of type int with safe<int>
type.Arithmetic Operations Can Overflow Silently
A variation of the above is when a value is incremented/decremented
- beyond it's domain. This is a common problem with for loops.
+ beyond it's domain.
@@ -150,7 +153,12 @@ detected error:converted negative value to unsigned
does illustrate the usage of safe_range<T> for
assigning legal range to variables. This will guarantee that under no
circumstances will the variable contain a value outside of the specified
- range.
+ range. Creating the bounds type can also be somewhat error-prone. It would
+ be quite easy for C++ programmers who are used to half-open ranges to use
+ safe_unsigned_range<0, i_array.size()>. On the other hand it would
+ certainly be easy to create a simple function
+ safe_array_bounds<T> which would return guaranteed
+ correct array bounds.
diff --git a/examples/Motor.c b/examples/Motor.c
index d17c249..d03afd0 100644
--- a/examples/Motor.c
+++ b/examples/Motor.c
@@ -116,7 +116,6 @@ void isr_motor_step()
} // if (ramp_sts != ramp_idle)
} // isr_motor_step()
-
void motor_run(short pos_new)
{ // set up to drive motor to pos_new (absolute step#)
if (pos_new < motor_pos) // get direction & #steps
diff --git a/examples/example10.cpp b/examples/example10.cpp
index fc2e99b..3609856 100644
--- a/examples/example10.cpp
+++ b/examples/example10.cpp
@@ -35,7 +35,7 @@ int main(){
safe_f(100, 100); // works as expected
safe_f(100, -100); // throw error
}
- catch(const exception & e){
+ catch(const std::exception & e){
cout << "detected error:" << e.what() << endl;;
}
return 0;
diff --git a/examples/example13.cpp b/examples/example13.cpp
index 3bf7ee9..35cbac8 100644
--- a/examples/example13.cpp
+++ b/examples/example13.cpp
@@ -28,7 +28,7 @@ int main(int argc, const char * argv[]){
safe x = 1;
safe 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;
diff --git a/examples/example83.cpp b/examples/example83.cpp
index e4b1ca6..dd36933 100644
--- a/examples/example83.cpp
+++ b/examples/example83.cpp
@@ -25,8 +25,8 @@ int main(int argc, const char * argv[]){
// since the sum of x and y wouldn't be in the legal
// range for z.
// const safe_signed_literal<20> x;
- const safe_signed_literal<10> x; // no problem
- const safe_signed_literal<67> y;
+ const safe_signed_literal<10, native, trap_exception> x; // no problem
+ const safe_signed_literal<67, native, trap_exception> y;
const safe_t z = x + y;
std::cout << "x = " << safe_format(x) << std::endl;
diff --git a/examples/example84.cpp b/examples/example84.cpp
index 4f25809..c017f71 100644
--- a/examples/example84.cpp
+++ b/examples/example84.cpp
@@ -21,7 +21,7 @@ using input_safe_t = safe_signed_range<
-24,
82,
automatic, // we don't need automatic in this case
- throw_exception // these variables need to
+ throw_exception // assignment of out of range value should throw
>;
// function arguments can never be outside of limits
diff --git a/examples/example91.cpp b/examples/example91.cpp
index bd8c748..d4b4106 100644
--- a/examples/example91.cpp
+++ b/examples/example91.cpp
@@ -46,7 +46,7 @@ using safe_bool_t = boost::numeric::safe_unsigned_range<
>;
#define DESKTOP
-#include "Motor1.c"
+#include "motor1.c"
#include
#include
diff --git a/include/automatic.hpp b/include/automatic.hpp
index 4a352a9..f94abc2 100644
--- a/include/automatic.hpp
+++ b/include/automatic.hpp
@@ -12,10 +12,8 @@
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
-// policy which creates results types equal to that of C++ promotions.
-// Using the policy will permit the program to build and run in release
-// mode which is identical to that in debug mode except for the fact
-// that errors aren't trapped.
+// policy which creates expanded results types designed
+// to avoid overflows.
#include
#include // (u)intmax_t,
@@ -23,7 +21,6 @@
#include
#include
-#include "utility.hpp"
#include "safe_common.hpp"
#include "checked_result.hpp"
#include "interval.hpp"
@@ -32,73 +29,8 @@ namespace boost {
namespace numeric {
struct automatic {
- // section 4.13 integer conversion rank
- template
- using rank =
- typename boost::mpl::if_c<
- sizeof(char) == sizeof(T),
- std::integral_constant,
- typename boost::mpl::if_c<
- sizeof(short) == sizeof(T),
- std::integral_constant,
- typename boost::mpl::if_c<
- sizeof(int) == sizeof(T),
- std::integral_constant,
- typename boost::mpl::if_c<
- sizeof(long) == sizeof(T),
- std::integral_constant,
- typename boost::mpl::if_c<
- sizeof(long long) == sizeof(T),
- std::integral_constant,
- void
- >::type >::type >::type >::type >::type;
-
- // note presumption that T & U don't have he same sign
- // if that's not true, these won't work
- template
- using select_signed = typename boost::mpl::if_c<
- std::numeric_limits::is_signed,
- T,
- U
- >::type;
-
- template
- using select_unsigned = typename boost::mpl::if_c<
- std::numeric_limits::is_signed,
- U,
- T
- >::type;
-
- template
- using calculate_max_t =
- typename boost::mpl::if_c<
- // clause 1 - if both operands have the same sign
- std::numeric_limits::is_signed
- == std::numeric_limits::is_signed,
- // use that sign
- typename boost::mpl::if_c<
- std::numeric_limits::is_signed,
- std::intmax_t,
- std::uintmax_t
- >::type,
- // clause 2 - otherwise if the rank of the unsigned type exceeds
- // the rank of the of the maximum signed type
- typename boost::mpl::if_c<
- (rank< select_unsigned>::value
- > rank< std::intmax_t >::value),
- // use unsigned type
- std::uintmax_t,
- // clause 3 - otherwise if the type of the signed integer type can
- // represent all the values of the unsigned type
- typename boost::mpl::if_c<
- std::numeric_limits< std::intmax_t >::digits >=
- std::numeric_limits< select_unsigned >::digits,
- // use signed type
- std::intmax_t,
- // clause 4 - otherwise use unsigned version of the signed type
- std::uintmax_t
- >::type >::type >::type;
-
+ // the following returns the "true" type. After calculating the new max and min
+ // these return the minimum size type which can hold the expected result.
template
struct defer_stored_signed_lazily {
using type = signed_stored_type;
@@ -117,43 +49,42 @@ struct automatic {
defer_stored_unsigned_lazily
>::type;
+
///////////////////////////////////////////////////////////////////////
template
struct addition_result {
+ using temp_base_type = typename boost::mpl::if_c<
+ // if both arguments are unsigned
+ ! std::numeric_limits::is_signed
+ && ! std::numeric_limits::is_signed,
+ // result is unsigned
+ std::uintmax_t,
+ // otherwise result is signed
+ std::intmax_t
+ >::type;
- using result_base_type = calculate_max_t;
- using t_base_type = typename base_type::type;
- using u_base_type = typename base_type::type;
-
- // filter out case were overflow cannot occur
- // note: subtle trickery. Suppose t is safe_range. Then
- // std::numeric_limits::min() will be safe_range t_interval{
+ constexpr static const interval::type> t_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
- constexpr static const interval u_interval{
+ constexpr static const interval::type> u_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
- // when we add the temporary intervals above, we'll get a new interval
- // with the correct range for the sum !
- constexpr static const checked_result> r_interval
- = add(t_interval, u_interval);
+ constexpr static const checked_result>
+ r_interval = add(t_interval, u_interval);
- constexpr static const interval result_interval =
- r_interval.no_exception() ?
- static_cast>(r_interval)
+ constexpr static const interval
+ result_interval = r_interval.no_exception() ?
+ static_cast>(r_interval)
:
- interval{}
+ interval{}
;
using type = typename result_type<
- result_base_type,
+ temp_base_type,
result_interval.l,
result_interval.u
>::type;
@@ -162,34 +93,30 @@ struct automatic {
///////////////////////////////////////////////////////////////////////
template
struct subtraction_result {
- // subtraction can result in negative result regardless of the
- // operand types !
- using result_base_type = std::intmax_t;
- using t_base_type = typename base_type::type;
- using u_base_type = typename base_type::type;
+ // result of subtraction are always signed.
+ using temp_base_type = intmax_t;
- constexpr static const interval t_interval{
+ constexpr static const interval::type> t_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
- constexpr static const interval u_interval{
+ constexpr static const interval::type> u_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
-
- constexpr static const checked_result> r_interval
- = subtract(t_interval, u_interval);
-
- constexpr static const interval result_interval =
+ constexpr static const checked_result>
+ r_interval = subtract(t_interval, u_interval);
+
+ constexpr static const interval result_interval =
r_interval.no_exception() ?
- static_cast>(r_interval)
+ static_cast>(r_interval)
:
- interval{}
+ interval{}
;
using type = typename result_type<
- result_base_type,
+ temp_base_type,
result_interval.l,
result_interval.u
>::type;
@@ -198,32 +125,38 @@ struct automatic {
///////////////////////////////////////////////////////////////////////
template
struct multiplication_result {
- using result_base_type = calculate_max_t;
- using t_base_type = typename base_type::type;
- using u_base_type = typename base_type::type;
+ using temp_base_type = typename boost::mpl::if_c<
+ // if both arguments are unsigned
+ ! std::numeric_limits::is_signed
+ && ! std::numeric_limits::is_signed,
+ // result is unsigned
+ std::uintmax_t,
+ // otherwise result is signed
+ std::intmax_t
+ >::type;
- constexpr static const interval t_interval{
+ constexpr static const interval::type> t_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
- constexpr static const interval u_interval{
+ constexpr static const interval::type> u_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
- constexpr static const checked_result> r_interval
- = multiply(t_interval, u_interval);
+ constexpr static const checked_result>
+ r_interval = multiply(t_interval, u_interval);
- constexpr static const interval result_interval =
+ constexpr static const interval result_interval =
r_interval.no_exception() ?
- static_cast>(r_interval)
+ static_cast>(r_interval)
:
- interval{}
+ interval{}
;
using type = typename result_type<
- result_base_type,
+ temp_base_type,
result_interval.l,
result_interval.u
>::type;
@@ -232,39 +165,39 @@ struct automatic {
///////////////////////////////////////////////////////////////////////
template
struct division_result {
- using t_base_type = typename base_type::type;
- using u_base_type = typename base_type::type;
+ using temp_base_type = typename boost::mpl::if_c<
+ // if both arguments are unsigned
+ ! std::numeric_limits::is_signed
+ && ! std::numeric_limits::is_signed,
+ // result is unsigned
+ std::uintmax_t,
+ // otherwise result is signed
+ std::intmax_t
+ >::type;
- constexpr static const interval t_interval{
+ constexpr static const interval::type> t_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
- constexpr static const interval u_interval{
+ constexpr static const interval::type> u_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
- using result_base_type = typename boost::mpl::if_c<
- std::numeric_limits::is_signed
- || std::numeric_limits::is_signed,
- std::intmax_t,
- std::uintmax_t
- >::type;
+ constexpr static const checked_result>
+ r_interval = divide_nz(t_interval, u_interval);
- constexpr static checked_result> r {
- divide_nz(t_interval, u_interval)
- };
- constexpr static const interval result_interval {
- r.no_exception() ?
- static_cast>(r)
+ constexpr static const interval result_interval {
+ r_interval.no_exception() ?
+ static_cast>(r_interval)
:
- interval{}
+ interval{}
};
using type = typename result_type<
- result_base_type,
+ temp_base_type,
result_interval.l,
result_interval.u
>::type;
@@ -283,33 +216,39 @@ struct automatic {
///////////////////////////////////////////////////////////////////////
template
struct modulus_result {
- using t_base_type = typename base_type::type;
- using u_base_type = typename base_type::type;
+ using temp_base_type = typename boost::mpl::if_c<
+ // if both arguments are unsigned
+ ! std::numeric_limits::is_signed
+ && ! std::numeric_limits::is_signed,
+ // result is unsigned
+ std::uintmax_t,
+ // otherwise result is signed
+ std::intmax_t
+ >::type;
- constexpr static const interval t_interval{
+ constexpr static const interval::type> t_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
- constexpr static const interval u_interval{
+ constexpr static const interval::type> u_interval{
base_value(std::numeric_limits::min()),
base_value(std::numeric_limits::max())
};
- using r_base_type = std::make_unsigned_t;
+ constexpr static const checked_result>
+ r_interval = modulus_nz(t_interval, u_interval);
- constexpr static const checked_result> r
- { modulus_nz(t_interval, u_interval) };
- constexpr static const interval result_interval =
- r.no_exception() ?
- static_cast>(r)
+ constexpr static const interval result_interval {
+ r_interval.no_exception() ?
+ static_cast>(r_interval)
:
- interval{}
- ;
+ interval{}
+ };
using type = typename result_type<
- r_base_type,
+ temp_base_type,
result_interval.l,
result_interval.u
>::type;
@@ -326,62 +265,8 @@ struct automatic {
}
///////////////////////////////////////////////////////////////////////
- // temporary version
-/*
- template
- struct left_shift_result {
- // calculate the number of bits were going to need to hold
- // the shifted result
- constexpr static int result_base_digits = boost::static_signed_min<
- // the largest number of bits possible
- std::numeric_limits::digits,
- // the largest number of bits that the shifted result might be
- std::numeric_limits::digits +
- // the number of bits in the max possible value of U
- boost::static_signed_min<
- // the largest number of bits of any type
- std::numeric_limits::digits,
- // the number bits to hold the maximum value of U
- // static_cast(std::numeric_limits::max())
- std::numeric_limits::max() % std::numeric_limits::max()
- >::value
- >::value;
+ // shift operations
- using result_base_type = typename boost::mpl::if_c<
- std::numeric_limits::is_signed,
- typename boost::int_t::least,
- typename boost::uint_t::least
- >::type;
-
- using t_base_type = typename base_type::type;
- using u_base_type = typename base_type::type;
- constexpr static const interval t_interval{
- base_value(std::numeric_limits::min()),
- base_value(std::numeric_limits::max())
- };
- constexpr static const interval u_interval{
- base_value(std::numeric_limits::min()),
- base_value(std::numeric_limits::max())
- };
- // when we add the temporary intervals above, we'll get a new interval
- // with the correct range for the shifted result !
- constexpr static const checked_result> r_interval
- = left_shift(t_interval, u_interval);
-
- constexpr static const interval result_interval =
- r_interval.no_exception() ?
- static_cast>(r_interval)
- :
- interval{}
- ;
- using type = typename result_type<
- result_base_type,
- result_interval.l,
- result_interval.u
- >::type;
-
- };
-*/
template
struct left_shift_result {
using t_base_type = typename base_type::type;
@@ -448,7 +333,27 @@ struct automatic {
///////////////////////////////////////////////////////////////////////
template
- struct bitwise_result {
+ struct bitwise_and_result {
+ using t_base_type = typename base_type::type;
+ using u_base_type = typename base_type::type;
+ using type = typename boost::mpl::if_c<
+ (sizeof(t_base_type) > sizeof(u_base_type)),
+ u_base_type,
+ t_base_type
+ >::type;
+ };
+ template
+ struct bitwise_or_result {
+ using t_base_type = typename base_type::type;
+ using u_base_type = typename base_type::type;
+ using type = typename boost::mpl::if_c<
+ (sizeof(t_base_type) > sizeof(u_base_type)),
+ t_base_type,
+ u_base_type
+ >::type;
+ };
+ template
+ struct bitwise_xor_result {
using t_base_type = typename base_type::type;
using u_base_type = typename base_type::type;
using type = typename boost::mpl::if_c<
diff --git a/include/checked.hpp b/include/checked.hpp
index d1874ea..23b9438 100644
--- a/include/checked.hpp
+++ b/include/checked.hpp
@@ -87,7 +87,7 @@ namespace detail {
template
constexpr static checked_result
invoke(const T & t){
- // INT32-C Ensure that operations on signed
+ // INT32-C Ensure that operations on unsigned
// integers do not overflow
return
t > std::numeric_limits::max() ?
@@ -224,10 +224,10 @@ constexpr checked_result add(
) {
static_assert(std::is_fundamental::value, "only intrinsic types permitted");
const checked_result rt(cast(t));
- if(! rt.no_exception() )
+ if(rt.exception() )
return rt;
const checked_result ru(cast(u));
- if(! ru.no_exception() )
+ if(ru.exception() )
return ru;
return detail::add(t, u);
}
@@ -408,8 +408,8 @@ namespace detail {
< static_cast(std::numeric_limits::min())
) ?
checked_result(
- exception_type::underflow_error,
- "multiplication underflow"
+ exception_type::overflow_error,
+ "multiplication overflow"
)
:
checked_result(t * u)
@@ -528,15 +528,15 @@ constexpr divide(
"divide by zero"
);
}
- auto tx = cast(t);
- auto ux = cast(u);
- if(!tx.no_exception()
- || !ux.no_exception())
+ checked_result tx = cast(t);
+ checked_result ux = cast(u);
+ if(tx.exception()
+ || ux.exception())
return checked_result(
exception_type::overflow_error,
"failure converting argument types"
);
- return detail::divide(tx.m_r, ux.m_r);
+ return detail::divide(tx, ux);
}
namespace detail_automatic {
@@ -596,6 +596,7 @@ constexpr divide_automatic(
////////////////////////////////
// safe modulus on unsafe types
+// built-in abs isn't constexpr - so fix this here
template
constexpr std::make_unsigned_t
abs(const T & t){
@@ -619,12 +620,21 @@ constexpr modulus(
"denominator is zero"
);
- return cast(abs(t) % abs(u));
+ // why to we need abs here? the sign of the modulus is the sign
+ // consider -128 % -1 The result of this operation should be -1
+ // but if I use t % u the x86 hardware uses the divide instruction
+ // capturing the modulus as a side effect. When it does this, it
+ // invokes the operation -128 / -1 -> 128 which overflows a signed type
+ // and provokes a hardware exception. We can fix this using abs()
+ // since -128 % -1 = -128 % 1 = 0
+ return t % abs(u);
}
///////////////////////////////////
// shift operations
+// left shift
+
namespace detail {
// INT34-C C++
@@ -718,7 +728,6 @@ constexpr checked_left_shift(
} // detail
-// left shift
template
constexpr checked_result left_shift(
const T & t,
@@ -739,6 +748,7 @@ constexpr checked_result left_shift(
return detail::checked_left_shift(t, u);
}
+// right shift
namespace detail {
// standard paragraph 5.8 / 3
@@ -836,19 +846,21 @@ namespace detail {
check_bitwise_operand(const T & t){
return true;
}
-}
+} // detail
template
constexpr checked_result bitwise_or(
const T & t,
const U & u
) {
+ /*
if(! detail::check_bitwise_operand(t))
return checked_result(
exception_type::domain_error,
"bitwise operands cannot be negative"
);
-
+ */
+
const checked_result rt = cast(t);
if(! rt.no_exception())
return rt;
diff --git a/include/checked_result.hpp b/include/checked_result.hpp
index 011c32b..e579ac4 100644
--- a/include/checked_result.hpp
+++ b/include/checked_result.hpp
@@ -32,20 +32,8 @@ struct checked_result {
R m_r;
char const * m_msg;
};
- // constructors
- // can't select constructor based on the current status of another
- // checked_result object. So no copy constructor
- /*
- constexpr checked_result(const checked_result & r) :
- m_e(r.m_e)
- {
- (no_exception()) ?
- (m_r = r.m_r), 0
- :
- (m_msg = r.m_msg), 0
- ;
- }
- */
+ // constructors - use default copy constructor
+
// don't permit construction without initial value;
checked_result() = delete;
@@ -64,6 +52,8 @@ struct checked_result {
// accesors
constexpr operator R() const {
+ // can't invoke assert at compiler time so it's in compatible
+ // with constexpr
//assert(no_exception());
return m_r;
}
@@ -97,7 +87,7 @@ struct checked_result {
}
template
constexpr boost::logic::tribool operator<=(const checked_result & t) const {
- return ! operator>(t) && ! operator<(t);
+ return ! operator>(t);
}
template
constexpr boost::logic::tribool operator!=(const checked_result & t) const {
@@ -130,6 +120,10 @@ template
constexpr bool no_exception(const checked_result & cr){
return cr.no_exception();
}
+template
+constexpr bool exception(const checked_result & cr){
+ return ! cr.no_exception();
+}
} // numeric
} // boost
@@ -139,9 +133,9 @@ constexpr bool no_exception(const checked_result & cr){
namespace std {
-template
-std::ostream & operator<<(
- std::ostream & os,
+template
+inline std::basic_ostream & operator<<(
+ std::basic_ostream & os,
const boost::numeric::checked_result & r
){
if(r.no_exception())
@@ -151,10 +145,10 @@ std::ostream & operator<<(
return os;
}
-template<>
-std::ostream & operator<<(
- std::ostream & os,
- const boost::numeric::checked_result & r
+template
+inline std::basic_ostream & operator<<(
+ std::basic_ostream os,
+ const boost::numeric::checked_result & r
){
if(r.no_exception())
os << static_cast(r);
@@ -163,10 +157,10 @@ std::ostream & operator<<(
return os;
}
-template<>
-std::ostream & operator<<(
- std::ostream & os,
- const boost::numeric::checked_result & r
+template
+inline std::basic_ostream & operator<<(
+ std::basic_ostream os,
+ const boost::numeric::checked_result & r
){
if(r.no_exception())
os << static_cast(r);
@@ -175,29 +169,36 @@ std::ostream & operator<<(
return os;
}
-/*
-template
-std::istream & operator>>(std::istream & is, const boost::numeric::checked_result & r){
+template
+inline std::basic_istream