220 30638 <66f9bab2-7220-4bf1-afb7-77c5efa1bac3@isocpp.org> article
Path: news.gmane.org!.POSTED!not-for-mail
From: federico.kircheis@gmail.com
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: safe integrals comparison
Date: Fri, 20 Jan 2017 08:31:37 -0800 (PST)
Lines: 269
Approved: news@gmane.org
Message-ID: <66f9bab2-7220-4bf1-afb7-77c5efa1bac3@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/mixed; 
	boundary="----=_Part_619_708454977.1484929897975"
X-Trace: blaine.gmane.org 1484929913 16131 195.159.176.226 (20 Jan 2017 16:31:53 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Fri, 20 Jan 2017 16:31:53 +0000 (UTC)
To: ISO C++ Standard - Future Proposals <std-proposals@isocpp.org>
Original-X-From: std-proposals+bncBCZ3PBGHYEBBB2XWRDCAKGQEEGCIWXI@isocpp.org Fri Jan 20 17:31:46 2017
Return-path: <std-proposals+bncBCZ3PBGHYEBBB2XWRDCAKGQEEGCIWXI@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-it0-f71.google.com ([209.85.214.71])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCZ3PBGHYEBBB2XWRDCAKGQEEGCIWXI@isocpp.org>)
	id 1cUc6A-0002rK-Gr
	for gclcip-std-proposals@m.gmane.org; Fri, 20 Jan 2017 17:31:34 +0100
Original-Received: by mail-it0-f71.google.com with SMTP id o185sf32345817itb.6
        for <gclcip-std-proposals@m.gmane.org>; Fri, 20 Jan 2017 08:31:39 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=date:from:to:message-id:subject:mime-version:x-original-sender
         :reply-to:precedence:mailing-list:list-id:x-spam-checked-in-group
         :list-post:list-help:list-archive:list-subscribe:list-unsubscribe;
        bh=wb9ffCEjCe0k3wnSuhq5uXyNooxCN3TWcT39K4IQfBE=;
        b=iGPwRVbftGy/ssIbfTyYf3fYdF2CzUECqkVysRaUpNiJ7Gq5RfnCRurh9X6hwmxNYN
         Qbp6g5ag5XiEbZ/CS180zMG4ObJRRg5CDeTwkFweIHENUCE+GTPUDp6YuCtvgdzByQpq
         rY2mcL3Ss1+W/Zi45lHd45K5THUhflV/BWbVzZyg13hTZ3YRrD70Et0nQbMiTHShHvKU
         w9zjp6pfeTFfuoY7G2F9ojMQD5CUvqoFW4yewUoAkDgfwn+hT5qiXBPotj1EUOEdm/PF
         8agE9JqxZLfS/5UEXiJ+Co9gxsKpAwVuIplsXt7RDDE+F1RUixXdgKAG3y1+zAgcVbHu
         Vakg==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20161025;
        h=date:from:to:message-id:subject:mime-version:x-original-sender
         :reply-to:precedence:mailing-list:list-id:x-spam-checked-in-group
         :list-post:list-help:list-archive:list-subscribe:list-unsubscribe;
        bh=wb9ffCEjCe0k3wnSuhq5uXyNooxCN3TWcT39K4IQfBE=;
        b=pWmhIysiRnc2Hd4qWsL7vh89QlJnfo6Uf7K5MBIPs+GS32cN7YAe/2S+CpaSIlSGbU
         keUehOkyiNkpQB0PgHGAXxiZ6vORNp/KNysKDAhLdHY7VFkl4yTKrNdSk1aXM3duFaI4
         5g1Ac4yG5X51Zlg5rGFRR5njw8DJ1Flzh7H/VaUUatL6PDh45akYOJRj+1KwaVNMAl2J
         H2trfNPJHhh6BBtWgSX9ulztnBMG+ge9taV7fMeSGXz9w+bX6n1V9CmZf5qzE6PExkA0
         aOdyB6BT9cSW5pOJUCLk54vu7AV93UVQRVjfFGIW16HmNSvS3MHvML0Hr60BJ4L7sDlf
         8W+A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:date:from:to:message-id:subject:mime-version
         :x-original-sender:reply-to:precedence:mailing-list:list-id
         :x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=wb9ffCEjCe0k3wnSuhq5uXyNooxCN3TWcT39K4IQfBE=;
        b=gWuwKboEABaebwTNfqjbGij5FmyeYahABVDv5JN0KwzNB3amwwmFULHlENPX7/1vA+
         NGGXm7gDlj8wNJjgNEm3Sve5sMj/fXNBnP1P8PSS4NUgl3kXckg9GvS53c1/254kx9ce
         ux7pQdDjALMGRg/JqHurLsimRAe8shy7zL6cPbLbl301PcwbJq3bYlgENN1RhNxr1JlW
         1YAfUBaBjojmT8ymXqie58Js68IQrbDlwP2IJmLxpCoIxKMum4l1OE0UdDHunGwUTixE
         jE4Qtm8Uumz1AEkoh0UdObN9LphK8L6cWEyodi76MtC7JU3G+BEojGoXH08UJVu/3nLF
         bfBw==
X-Gm-Message-State: AIkVDXJpGiJrcRzxIGJbquOSU+kx1Waw+uVUuAMBgY16tCs6/vIvCz4vFpgySurakBM/pQ==
X-Received: by 10.107.143.14 with SMTP id r14mr3949388iod.34.1484929899313;
        Fri, 20 Jan 2017 08:31:39 -0800 (PST)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.157.42.168 with SMTP id e37ls5003106otb.13.gmail; Fri, 20 Jan
 2017 08:31:38 -0800 (PST)
X-Received: by 10.157.52.34 with SMTP id v31mr1591098otb.9.1484929898469;
        Fri, 20 Jan 2017 08:31:38 -0800 (PST)
X-Original-Sender: federico.kircheis@gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <https://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <https://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <https://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:30638
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/30638>

------=_Part_619_708454977.1484929897975
Content-Type: multipart/alternative; 
	boundary="----=_Part_620_2018933233.1484929897976"

------=_Part_620_2018933233.1484929897976
Content-Type: text/plain; charset=UTF-8

Hello to everyone, this is my first proposal, I hope you'll find it 
interesting, give me some feedback and help to improve my 
idea/implementation/proposal.


I found myself many times to compare different numeric types together, for 
example int and std::size_t.
This happens because the c++ standard library uses unsigned types when 
dealing with sizes and positions, whereas other libraries do not always, as 
for example CArray of the MFC framework.

I noticed, that most of the time, I needed one of the following three 
operations:
    1) convert one type to another (verify if a number is in a valid range),
    2) verify if two numbers of different types are equivalent (equality),
    3) verify how two numbers of different types relates (less than).

In order to do one of the above listed  operations, we might do different 
things. For example, verifying if both numbers are unsigned or not. If only 
one is unsigned, check if it is less than zero. If not, determine which of 
the two types has a greater precision, cast both of them to the bigger type 
(may be unnecessary in some cases), and finally do the desired operation. 
You also need to pay attention to implicit conversions.

You can see, that for doing a pretty trivial operation (is 5ul equal to 2?, 
can I convert -3 to an unsigned short?) you need to do a lot of repetitive 
work, and the worst part is, that some relations between the types might 
change based on the platform.
Usually types are related to your architecture, that means that a 
comparison valid where you are developing, might be invalid on some other 
architecture; One type might be bigger than the other one, or the signeddes 
may have changed. Of course this does not happen if you are working with 
the same type, but it may happen that you are working with two different 
types that are typedeffed, for example, to the same type on a 32 bit 
platform, whereas on 64 bit they are not.

For this reason it is essential to have some utility function to write 
correct code in a simpler way, which gives you the possibility to verify if 
a value of one type is in the range of a second type, if two values are 
equivalent, or if one is less (greater, and so on) than the other.


My proposal would be to add four templated functions which work only for 
integral types (bool excluded).

The first function would be:

template <typename R, typename T> constexpr bool in_range(const T t) 
noexcept;

Usage
size_t i == ...
if(in_range<DWORD>(i)){
    // safe to convert i to a DWORD value, parameter...
} else {
    // not possible to represent i as a DWORD
}

The second function would be:

template <typename T, typename U> constexpr bool cmp_equal(const T t, const 
U u) noexcept;

Usage
size_t i == ...
DWORD j == ...
if(cmp_equal(i,j)){
    // i and j represent the same quantity
} else {
    // i and j represents different quantities
}


And the third function would be:

template <typename T, typename U> constexpr bool cmp_less(const T t, const 
U u) noexcept

Usage:
size_t i == ...
DWORD j == ...
if(cmp_less(i,j)){
    //  i < j
} else {
    //  i >= j
}
    

We could (and maybe should) also provide cmp_greater, cmp_less_or_equal, 
cmp_unequal and etc., but we can implement this functions using cmp_equal 
and cmp_less.

The fourth function I would like to add is: 

template <typename T> constexpr std::size_t precision() noexcept;


The reasons are described here:

https://www.securecoding.cert.org/confluence/display/c/INT35-C.+Use+correct+integer+precisions

Quote:
"Integer types in C have both a size and a precision. The size indicates 
the number of bytes used by an object and can be retrieved for any object 
or type using the sizeof operator.  The precision of an integer type is the 
number of bits it uses to represent values, excluding any sign and padding 
bits.

Padding bits contribute to the integer's size, but not to its precision. 
Consequently, inferring the precision of an integer type from its size may 
result in too large a value, which can then lead to incorrect assumptions 
about the numeric range of these types.  Programmers should use correct 
integer precisions in their code, and in particular, should not use the 
sizeof operator to compute the precision of an integer type on 
architectures that use padding bits or in strictly conforming (that is, 
portable) programs."


The function precision is used internally (by cmp_equal, cmp_less and 
in_range) for verifying which type is bigger, in order to safely cast 
before comparing the types. I also think, that this function should be part 
of the API, since it is very handy.


I've already provided and tested an implementation of those functions, you 
can find them at 

https://github.com/fekir/safeintegral

The file containing the implementation is:

https://github.com/fekir/safeintegral/blob/master/safeintegral/safeintegralop.hpp

As you can see the implementation is not particularly complex and should 
work on any conformant compiler (tested with gcc and msvc), those functions 
can be easily added in the standard library, maybe in <limits>.
My implementation is composed by more than four functions, the others are 
probably not necessary, but I'm not a template master, and I was not able 
to reduce the number of functions and maintain a good readability.

There are also other unrelated functions apart from the four I have 
mentioned, but my goal was to keep my proposal small. I also think, that 
the others are not yet complete, since they do not handle different types.


Let me know what you think.

Federico

-- 
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/66f9bab2-7220-4bf1-afb7-77c5efa1bac3%40isocpp.org.

------=_Part_620_2018933233.1484929897976
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Hello to everyone, this is my first proposal, I hope you&#=
39;ll find it interesting, give me some feedback and help to improve my ide=
a/implementation/proposal.<br><br><br>I found myself many times to compare =
different numeric types together, for example int and std::size_t.<br>This =
happens because the c++  standard library uses unsigned types when dealing =
with sizes and positions, whereas other libraries do not always, as for exa=
mple CArray of the MFC framework.<br><br>I noticed, that most of the time, =
I needed one of the following three operations:<br>=C2=A0=C2=A0=C2=A0 1) co=
nvert one type to another (verify if a number is in a valid range),<br>=C2=
=A0=C2=A0=C2=A0 2) verify if two numbers of different types are equivalent =
(equality),<br>=C2=A0=C2=A0=C2=A0 3) verify how two numbers of different ty=
pes relates (less than).<br><br>In order to do one of the above listed=C2=
=A0 operations, we might do different things. For example, verifying if bot=
h numbers are unsigned or not. If only one is unsigned, check if it is less=
 than zero. If not, determine which of the two types has a greater precisio=
n, cast both of them to the bigger type (may be unnecessary in some cases),=
 and finally do the desired operation. You also need to pay attention to im=
plicit conversions.<br><br>You can see, that for doing a pretty trivial ope=
ration (is 5ul equal to 2?, can I convert -3 to an unsigned short?) you nee=
d to do a lot of repetitive work, and the worst part is, that some relation=
s between the types might change based on the platform.<br>Usually types ar=
e related to your architecture, that means that a comparison valid where yo=
u are developing, might be invalid on some other architecture; One type mig=
ht be bigger than the other one, or the signeddes may have changed. Of cour=
se this does not happen if you are working with the same type, but it may h=
appen that you are working with two different types that are typedeffed, fo=
r example, to the same type on a 32 bit platform, whereas on 64 bit they ar=
e not.<br><br>For this reason it is essential to have some utility function=
 to write correct code in a simpler way, which gives you the possibility to=
 verify if a value of one type is in the range of a second type, if two val=
ues are equivalent, or if one is less (greater, and so on) than the other.<=
br><br><br>My proposal would be to add four templated functions which work =
only for integral types (bool excluded).<br><br>The first function would be=
:<br><br>template &lt;typename R, typename T&gt; constexpr bool in_range(co=
nst T t) noexcept;<br><br>Usage<br>size_t i =3D=3D ...<br>if(in_range&lt;DW=
ORD&gt;(i)){<br>=C2=A0=C2=A0=C2=A0 // safe to convert i to a DWORD value, p=
arameter...<br>} else {<br>=C2=A0=C2=A0=C2=A0 // not possible to represent =
i as a DWORD<br>}<br><br>The second function would be:<br><br>template &lt;=
typename T, typename U&gt; constexpr bool cmp_equal(const T t, const U u) n=
oexcept;<br><br>Usage<br>size_t i =3D=3D ...<br>DWORD j =3D=3D ...<br>if(cm=
p_equal(i,j)){<br>=C2=A0=C2=A0=C2=A0 // i and j represent the same quantity=
<br>} else {<br>=C2=A0=C2=A0=C2=A0 // i and j represents different quantiti=
es<br>}<br><br><br>And the third function would be:<br><br>template &lt;typ=
ename T, typename U&gt; constexpr bool cmp_less(const T t, const U u) noexc=
ept<br><br>Usage:<br>size_t i =3D=3D ...<br>DWORD j =3D=3D ...<br>if(cmp_le=
ss(i,j)){<br>=C2=A0=C2=A0=C2=A0 //=C2=A0 i &lt; j<br>} else {<br>=C2=A0=C2=
=A0=C2=A0 //=C2=A0 i &gt;=3D j<br>}<br>=C2=A0=C2=A0=C2=A0 <br><br>We could =
(and maybe should) also provide cmp_greater, cmp_less_or_equal, cmp_unequal=
 and etc., but we can implement this functions using cmp_equal and cmp_less=
..<br><br>The fourth function I would like to add is: <br><br>template &lt;t=
ypename T&gt; constexpr std::size_t precision() noexcept;<br><br><br>The re=
asons are described here:<br><br>https://www.securecoding.cert.org/confluen=
ce/display/c/INT35-C.+Use+correct+integer+precisions<br><br>Quote:<br>&quot=
;Integer types in C have both a size and a precision. The size indicates th=
e number of bytes used by an object and can be retrieved for any object or =
type using the sizeof operator.=C2=A0 The precision of an integer type is t=
he number of bits it uses to represent values, excluding any sign and paddi=
ng bits.<br><br>Padding bits contribute to the integer&#39;s size, but not =
to its precision. Consequently, inferring the precision of an integer type =
from its size may result in too large a value, which can then lead to incor=
rect assumptions about the numeric range of these types.=C2=A0 Programmers =
should use correct integer precisions in their code, and in particular, sho=
uld not use the sizeof operator to compute the precision of an integer type=
 on architectures that use padding bits or in strictly conforming (that is,=
 portable) programs.&quot;<br><br><br>The function precision is used intern=
ally (by cmp_equal, cmp_less and in_range) for verifying which type is bigg=
er, in order to safely cast before comparing the types. I also think, that =
this function should be part of the API, since it is very handy.<br><br><br=
>I&#39;ve already provided and tested an implementation of those functions,=
 you can find them at <br><br>https://github.com/fekir/safeintegral<br><br>=
The file containing the implementation is:<br><br>https://github.com/fekir/=
safeintegral/blob/master/safeintegral/safeintegralop.hpp<br><br>As you can =
see the implementation is not particularly complex and should work on any c=
onformant compiler (tested with gcc and msvc), those functions can be easil=
y added in the standard library, maybe in &lt;limits&gt;.<br>My implementat=
ion is composed by more than four functions, the others are probably=20
not necessary, but I&#39;m not a template master, and I was not able to=20
reduce the number of functions and maintain a good readability.<br><br>Ther=
e are also other unrelated functions apart from the four I have mentioned, =
but my goal was to keep my proposal small. I also think, that the others ar=
e not yet complete, since they do not handle different types.<br><br><br>Le=
t me know what you think.<br><br>Federico<br><br></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/66f9bab2-7220-4bf1-afb7-77c5efa1bac3%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/66f9bab2-7220-4bf1-afb7-77c5efa1bac3=
%40isocpp.org</a>.<br />

------=_Part_620_2018933233.1484929897976--

------=_Part_619_708454977.1484929897975--

.
