
A friend and I have started working on a SafeInt library which we hope will be included in Boost the library is composed of a template class, which excepts existing integer types as a parameter, and an exception class. not all operators have been implemented and there is still work to be done on the library, but we have reached a stage in which at least the basic operators are ready and tested. I've attached to this thread a zip file containing the code for the library and a tester we wrote (as an example for how the class should be used) I've also uploaded it to the boost vault. We would appreciate it if you took the time to review our code and give us your comments, tips and opinions (either as a reply to this thread or by email - omerktz@gmail.com) thanks, Omer Katz and Zil Levi

AMDG Omer Katz wrote:
A friend and I have started working on a SafeInt library which we hope will be included in Boost
the library is composed of a template class, which excepts existing integer types as a parameter, and an exception class. not all operators have been implemented and there is still work to be done on the library, but we have reached a stage in which at least the basic operators are ready and tested.
I've attached to this thread a zip file containing the code for the library and a tester we wrote (as an example for how the class should be used) I've also uploaded it to the boost vault.
We would appreciate it if you took the time to review our code and give us your comments, tips and opinions (either as a reply to this thread or by email - omerktz@gmail.com)
* Use Boost style naming conventions (i.e. safe_int, not SafeInt). * Don't use exception specifications. * Use functions instead of macros. * use std::numeric_limits<T>::min/max() instead of computing it for yourself. * long long is not portable * It's better to use non-members for operator+, operator-, etc. It's odd that you overload for SafeInt<T>() + S, but not S + SafeInt<T>(). In Christ, Steven Watanabe

Steven Watanabe wrote:
It's better to use non-members for operator+, operator-, etc.
In the case of a template class like SafeInt<T>, do you think the binary operator+, operator-, etc., should be friend functions, defined inside the class declaration, or template functions? Note that I've just posted a slightly related ticket on David LeBlanc's SafeInt: "Potential performance gain from non-member operator+" http://safeint.codeplex.com/WorkItem/View.aspx?WorkItemId=7910 BTW, I do think it would be great to have such a library in Boost. Kind regards, Niels -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center

AMDG Niels Dekker - address until 2010-10-10 wrote:
Steven Watanabe wrote:
It's better to use non-members for operator+, operator-, etc.
In the case of a template class like SafeInt<T>, do you think the binary operator+, operator-, etc., should be friend functions, defined inside the class declaration, or template functions?
I don't think that non-template friends should be defined inline in a class template because they are always supposed to be instantiated regardless of whether they are used or not (unlike ordinary members). For templated operator+, etc, I don't really care.
Note that I've just posted a slightly related ticket on David LeBlanc's SafeInt: "Potential performance gain from non-member operator+" http://safeint.codeplex.com/WorkItem/View.aspx?WorkItemId=7910
BTW, I do think it would be great to have such a library in Boost.
Kind regards, Niels
In Christ, Steven Watanabe

Steven Watanabe wrote:
I don't think that non-template friends should be defined inline in a class template because they are always supposed to be instantiated regardless of whether they are used or not (unlike ordinary members).
Thanks, Steven. Do I understand correctly that when you look at the following example, you find the definition of operator+ preferable to operator- ? ////////////////////////////////////////////////////////// template <typename> class safe_int; template <typename T> safe_int<T> operator+(safe_int<T>, safe_int<T>); template <typename T> class safe_int { public: friend safe_int operator+ <>(safe_int, safe_int); inline friend safe_int operator-(safe_int, safe_int) { throw "operator- not yet implemented."; } }; template <typename T> safe_int<T> operator+(safe_int<T>, safe_int<T>) { throw "operator+ not yet implemented."; } ////////////////////////////////////////////////////////// I still hesitate, because the non-template inline friend, operator-, appears to support implicit conversions more intuitively... I think. ////////////////////////////////////////////////////////// struct convertible_to_safe_int { operator safe_int<int>() const { return safe_int<int>(); } }; int main() { safe_int<int>() - convertible_to_safe_int(); // okay convertible_to_safe_int() - safe_int<int>(); // okay safe_int<int>() + convertible_to_safe_int(); // error convertible_to_safe_int() + safe_int<int>(); // error } ////////////////////////////////////////////////////////// Isn't support of such conversions (in a symmetrical way) the main reason to declare such operators as non-members, rather than as member functions? Kind regards, Niels -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center

AMDG Niels Dekker - address until 2010-10-10 wrote:
Steven Watanabe wrote:
I don't think that non-template friends should be defined inline in a class template because they are always supposed to be instantiated regardless of whether they are used or not (unlike ordinary members).
Thanks, Steven. Do I understand correctly that when you look at the following example, you find the definition of operator+ preferable to operator- ?
////////////////////////////////////////////////////////// template <typename> class safe_int;
template <typename T> safe_int<T> operator+(safe_int<T>, safe_int<T>);
template <typename T> class safe_int { public: friend safe_int operator+ <>(safe_int, safe_int);
inline friend safe_int operator-(safe_int, safe_int) { throw "operator- not yet implemented."; } };
template <typename T> safe_int<T> operator+(safe_int<T>, safe_int<T>) { throw "operator+ not yet implemented."; } //////////////////////////////////////////////////////////
I still hesitate, because the non-template inline friend, operator-, appears to support implicit conversions more intuitively... I think.
Sorry. I reacted automatically, because of the problems that I've had with inline friends. In this case, I think it's not a problem to define them inline. The cases that cause problems are like: template<class Iterator> struct reverse_iterator { friend reverse_iterator operator+(typename Iterator::difference_type n, reverse_iterator iter) { return(reverse_iterator(iter.base() - n)); // oops... early error if Iterator is not a RandomAccessIterator } }; For safe_int, you could only run into problem by both a) supporting user-defined type. I don't see the point of this. b) only requiring the underlying type to support division (e.g.) if the user tries to divide two safe_ints.
Isn't support of such conversions (in a symmetrical way) the main reason to declare such operators as non-members, rather than as member functions?
Maybe. For me it's more important that the operators are defined consistently and there is no way to overload an operator as a member with the first argument being of a different type. In any case, it's okay to support implicit conversions for both arguments or neither, as far as I am concerned. It's the matter of supporting implicit conversions only for the second argument that makes the member operator really unattractive. In Christ, Steven Watanabe

I don't think that non-template friends should be defined inline in a class template because they are always supposed to be instantiated regardless of whether they are used or not (unlike ordinary members).
[snip]
Sorry. I reacted automatically, because of the problems that I've had with inline friends. In this case, I think it's not a problem to define them inline.
[pedanticism] Don't both your examples rely on pre-standard C++ friend declarations and definitions injecting the function name in the innermost enclosing namespace? I might be reading this worng, but 7.3.1.2 [namespace.memdef] paragraph 3 states: "The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope". So you'd still need to declare in the namespace. From what I understand the examples shouldn't work. Correct me if I'm wrong :) JF

Jean-Francois Bastien wrote:
[pedanticism] Don't both your examples rely on pre-standard C++ friend declarations and definitions injecting the function name in the innermost enclosing namespace? I might be reading this worng, but 7.3.1.2 [namespace.memdef] paragraph 3 states: "The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope". So you'd still need to declare in the namespace. From what I understand the examples shouldn't work.
Correct me if I'm wrong :)
Well... I do appreciate your pedanticism, but I think you're wrong. All the compilers I tried accept the function calls to the inline friend function, operator-(safe_int,safe_int), including MSVC 2008 SP1, Comeau (www.comeaucomputing.com/tryitout), and g++ 4.1.2, run at http://codepad.org/dB9IbQJ7 You might want to have a look at [temp.inject] ("Friend names declared within a class template"). Quoting the latest C++0x Working Draft, www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2857.pdf, 14.7.5/2 (slightly reformatted): "As with non-template classes, the names of namespace-scope friend functions of a class template specialization are not visible during an ordinary lookup unless explicitly declared at namespace scope (11.4). Such names may be found under the rules for associated classes (3.4.2). [ Example: template<typename T> struct number { number(int); friend number gcd(number x, number y) { return 0; }; }; void g() { number<double> a(3), b(4); a = gcd(a,b); // finds gcd because number<double> is an // associated class, making gcd visible // in its namespace (global scope) b = gcd(3,4); // ill-formed; gcd is not visible } —end example ] Kind regards, Niels

Niels,
Correct me if I'm wrong :)
Well... I do appreciate your pedanticism, but I think you're wrong. All the compilers I tried accept the function calls to the inline friend function, operator-(safe_int,safe_int), including MSVC 2008 SP1, Comeau (www.comeaucomputing.com/tryitout), and g++ 4.1.2, run at http://codepad.org/dB9IbQJ7
You might want to have a look at [temp.inject] ("Friend names declared within a class template"). Quoting the latest C++0x Working Draft, www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2857.pdf, 14.7.5/2 (slightly reformatted):
"As with non-template classes, the names of namespace-scope friend functions of a class template specialization are not visible during an ordinary lookup unless explicitly declared at namespace scope (11.4). Such names may be found under the rules for associated classes (3.4.2). [ Example:
template<typename T> struct number { number(int); friend number gcd(number x, number y) { return 0; }; };
void g() { number<double> a(3), b(4); a = gcd(a,b); // finds gcd because number<double> is an // associated class, making gcd visible // in its namespace (global scope) b = gcd(3,4); // ill-formed; gcd is not visible } -end example ]
I might very well be wrong, that part of the standard has always been a bit shady to me and had a ring of "pre-standard stuff". That being said compilers aren't the best way to verify standard compliance ;)
From the section you quote some of the lookup rules do apply while others not, but only for templates. If I remember that was used before template templates existed.
Sorry for being OT, curiosity bit me :)

Jean-Francois Bastien wrote:
Niels,
Correct me if I'm wrong :)
Well... I do appreciate your pedanticism, but I think you're wrong. All the compilers I tried accept the function calls to the inline friend function, operator-(safe_int,safe_int), including MSVC 2008 SP1, Comeau (www.comeaucomputing.com/tryitout), and g++ 4.1.2, run at http://codepad.org/dB9IbQJ7
You might want to have a look at [temp.inject] ("Friend names declared within a class template"). Quoting the latest C++0x Working Draft, www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2857.pdf, 14.7.5/2 (slightly reformatted):
"As with non-template classes, the names of namespace-scope friend functions of a class template specialization are not visible during an ordinary lookup unless explicitly declared at namespace scope (11.4). Such names may be found under the rules for associated classes (3.4.2). [ Example:
template<typename T> struct number { number(int); friend number gcd(number x, number y) { return 0; }; };
void g() { number<double> a(3), b(4); a = gcd(a,b); // finds gcd because number<double> is an // associated class, making gcd visible // in its namespace (global scope) b = gcd(3,4); // ill-formed; gcd is not visible } -end example ]
I might very well be wrong, that part of the standard has always been a bit shady to me and had a ring of "pre-standard stuff". That being said compilers aren't the best way to verify standard compliance ;)
I believe that the friend becomes visible once the template is instantiated for a specific type. Therefore there is a gcd for number<double> visible in the example above, but not for any other types. Bo Persson

AMDG Niels Dekker - address until 2010-10-10 wrote:
Jean-Francois Bastien wrote:
[pedanticism] Don't both your examples rely on pre-standard C++ friend declarations and definitions injecting the function name in the innermost enclosing namespace? I might be reading this worng, but 7.3.1.2 [namespace.memdef] paragraph 3 states: "The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope". So you'd still need to declare in the namespace. From what I understand the examples shouldn't work.
Correct me if I'm wrong :)
Well... I do appreciate your pedanticism, but I think you're wrong. All the compilers I tried accept the function calls to the inline friend function, operator-(safe_int,safe_int), including MSVC 2008 SP1, Comeau (www.comeaucomputing.com/tryitout), and g++ 4.1.2, run at http://codepad.org/dB9IbQJ7
You might want to have a look at [temp.inject] ("Friend names declared within a class template"). Quoting the latest C++0x Working Draft, www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2857.pdf, 14.7.5/2 (slightly reformatted):
"As with non-template classes, the names of namespace-scope friend functions of a class template specialization are not visible during an ordinary lookup unless explicitly declared at namespace scope (11.4). Such names may be found under the rules for associated classes (3.4.2). [ Example: <snip> ]
Exactly. In the current standard, they can be found by argument-dependent lookup: When considering an associated namespace, the lookup is the same as the lookup performed when the associated namespace is used as a qualifier (3.4.3.2) except that: — Any using-directives in the associated namespace are ignored. — Any namespace-scope friend functions declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup (11.4). In Christ, Steven Watanabe

Omer Katz wrote:
A friend and I have started working on a SafeInt library which we hope will be included in Boost
the library is composed of a template class, which excepts existing integer types as a parameter, and an exception class. not all operators have been implemented and there is still work to be done on the library, but we have reached a stage in which at least the basic operators are ready and tested.
I've attached to this thread a zip file containing the code for the library and a tester we wrote (as an example for how the class should be used) I've also uploaded it to the boost vault.
We would appreciate it if you took the time to review our code and give us your comments, tips and opinions (either as a reply to this thread or by email - omerktz@gmail.com)
I really doubt that you library will be accepted in its current form. For the following reasons: 1. The SafeInt objects are 3 time larger than the integer they wrap. max_value and min_value can be static - they really depend only on the type of the integer you wrap. Not on the value that is currently contained. 2. Default constructor does 1 or 2 pow calls. You can use << to get a power of 2. 3. Many checks that are performed currently at run time can be done at compile time. 4. x86 has hardware support for checking for integer overflows. It means that the OS may provide some means to check if an overflow has occurred. Using hardware may be way faster then doing the checks in the software. P.S. Your code seems to be very similar to what is published here: http://msdn.microsoft.com/en-us/library/ms972705.aspx

Omer Katz wrote:
A friend and I have started working on a SafeInt library which we hope will be included in Boost
I think such a library would be very useful. But as Ilya Bobir mentions, it is very similar to Microsoft's SafeInt, developed by David LeBlanc. Did you have a look at his library before? Ilya Bobir wrote:
I really doubt that you library will be accepted in its current form. For the following reasons: [...] 4. x86 has hardware support for checking for integer overflows. It means that the OS may provide some means to check if an overflow has occurred. Using hardware may be way faster then doing the checks in the software.
Interesting! How would you use hardware to check int overflow?
P.S. Your code seems to be very similar to what is published here: http://msdn.microsoft.com/en-us/library/ms972705.aspx
Indeed. Note that Microsoft's SafeInt will be shipped with MSVC 2010. Actually, Visual Studio Beta 1 already has it placed at "C:\Program Files\Microsoft Visual Studio 10.0\VC\include" There's also a freely available version of David LeBlanc's SafeInt at Microsoft's open source website, www.codeplex.com/SafeInt BTW, I did help a little bit to get it compiling on GCC. :-) Kind regards, Niels -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center

Niels Dekker - address until 2010-10-10 wrote:
4. x86 has hardware support for checking for integer overflows. It means that the OS may provide some means to check if an overflow has occurred. Using hardware may be way faster then doing the checks in the software.
Interesting! How would you use hardware to check int overflow?
If you are programming in x86 assembler you can use OF flag in FLAGS register that is set when an integer operation overflows. But you need to check it after each operation. There is a special INTO instruction that triggers an overflow interrupt handler if the OF flag is set. It means that you just have to put INTO after all of instructions that you want to check for overflow and provide proper handler. POSIX defines a signal that is delivered to a process upon invalid integer operation, SIGPFE: http://en.wikipedia.org/wiki/SIGFPE. On Windows there is a structures exception with code STATUS_INTEGER_OVERFLOW. There seems to be a sample of how to use it here: http://msdn.microsoft.com/en-us/library/7sw7cha4.aspx, but it is not complete.

Hi everyone, first of all, thank you for your comments, and thank you for pointing out David's library. We actually haven't seen David's code until today, that you've mentioned it... We had no idea that it existed we asked about a month and a half ago (12.5.09) regarding adding a SafeInt lib for boost, and no one actually replied, so did happen in the IRC, and when we didn't find any other such thing in boost, we decided that it would be a good idea to have something like that, under the boost licence. Regarding David's work: indeed a great job, much more complete than ours for the moment, though we still think that such a library in boost will be a good idea. we may suggest our help if David will decide to port histo boost, or it's possible to keep developing a parrallel independent library, fixing the portabilities issues and adding more functionality... We are aware that there is still work to be done on our library There is indeed an overflow flag as mentioned, but the library should be platform independent, that's why it doesn't use it, though it will be probably faster. "Omer Katz" <omerktz@gmail.com> כתב בהודעת news:h1jnme$i7k$1@ger.gmane.org...
A friend and I have started working on a SafeInt library which we hope will be included in Boost
the library is composed of a template class, which excepts existing integer types as a parameter, and an exception class. not all operators have been implemented and there is still work to be done on the library, but we have reached a stage in which at least the basic operators are ready and tested.
I've attached to this thread a zip file containing the code for the library and a tester we wrote (as an example for how the class should be used) I've also uploaded it to the boost vault.
We would appreciate it if you took the time to review our code and give us your comments, tips and opinions (either as a reply to this thread or by email - omerktz@gmail.com)
thanks, Omer Katz and Zil Levi
--------------------------------------------------------------------------------
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Hi Omer,
the library should be platform independent
I've noticed that you make implicit assumptions in the code like: - the number of bits in a byte is 8, - signed integer types use 2's complement representation. These assumptions are not true for all platforms, making your code not fully portable and not standards-compliant. I realise that implementing the library without such assumptions may be much more difficult, but if you decide to make them, it is necessary to: - describe them precisely in the documentation, - add corresponding static asserts in the code to prevent people from using it on unsupported platforms. Apart from this, you should adhere to Boost coding conventions (see http://www.boost.org/development/requirements.html for details). That said, I think such a library would be a very useful addition to Boost, so I hope all the problems will be solved and the code will be submitted for a review. ;-) Best regards, Robert

Omer Katz wrote:
There is indeed an overflow flag as mentioned, but the library should be platform independent, that's why it doesn't use it, though it will be probably faster.
You can write platform specializations so that on those platforms that do support it, they are not penalized.
participants (8)
-
Bo Persson
-
Ilya Bobir
-
Jean-Francois Bastien
-
Niels Dekker - address until 2010-10-10
-
Omer Katz
-
Raindog
-
Robert Kawulak
-
Steven Watanabe