[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master e93e17f 3/4: Signed uniform container size
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master e93e17f 3/4: Signed uniform container size |
Date: |
Mon, 4 Jun 2018 12:19:53 -0400 (EDT) |
branch: master
commit e93e17f12769f763866e2d800566a4278aba41bb
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>
Signed uniform container size
Naturally extend C++17 [iterator.container] (N4280) so that error-prone
mixing of signed and unsigned can be avoided.
---
Makefile.am | 7 ++++
objects.make | 5 +++
ssize_lmi.hpp | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++
ssize_lmi_test.cpp | 59 +++++++++++++++++++++++++++++++
4 files changed, 172 insertions(+)
diff --git a/Makefile.am b/Makefile.am
index 59d70c2..40a1d47 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -136,6 +136,7 @@ TESTS = \
test_safely_dereference_as \
test_sandbox \
test_snprintf \
+ test_ssize_lmi \
test_stratified_algorithms \
test_stream_cast \
test_system_command \
@@ -1032,6 +1033,11 @@ test_snprintf_SOURCES = \
snprintf_test.cpp
test_snprintf_CXXFLAGS = $(AM_CXXFLAGS)
+test_ssize_lmi_SOURCES = \
+ $(common_test_objects) \
+ ssize_lmi_test.cpp
+test_ssize_lmi_CXXFLAGS = $(AM_CXXFLAGS)
+
test_stratified_algorithms_SOURCES = \
$(common_test_objects) \
stratified_algorithms_test.cpp
@@ -1285,6 +1291,7 @@ noinst_HEADERS = \
single_choice_popup_menu.hpp \
skeleton.hpp \
so_attributes.hpp \
+ ssize_lmi.hpp \
stl_extensions.hpp \
stratified_algorithms.hpp \
stratified_charges.hpp \
diff --git a/objects.make b/objects.make
index 853e71a..baec96a 100644
--- a/objects.make
+++ b/objects.make
@@ -459,6 +459,7 @@ unit_test_targets := \
safely_dereference_as_test \
sandbox_test \
snprintf_test \
+ ssize_lmi_test \
stratified_algorithms_test \
stream_cast_test \
system_command_test \
@@ -912,6 +913,10 @@ snprintf_test$(EXEEXT): \
$(common_test_objects) \
snprintf_test.o \
+ssize_lmi_test$(EXEEXT): \
+ $(common_test_objects) \
+ ssize_lmi_test.o \
+
stratified_algorithms_test$(EXEEXT): \
$(common_test_objects) \
stratified_algorithms_test.o \
diff --git a/ssize_lmi.hpp b/ssize_lmi.hpp
new file mode 100644
index 0000000..db5c150
--- /dev/null
+++ b/ssize_lmi.hpp
@@ -0,0 +1,101 @@
+// Improved std::size() that returns a signed integer.
+//
+// Copyright (C) 2018 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+#ifndef ssize_lmi_hpp
+#define ssize_lmi_hpp
+
+#include "config.hpp"
+
+#include "bourn_cast.hpp"
+
+#include <cstddef> // size_t
+#include <cstring> // strlen()
+#include <type_traits> // make_signed_t
+
+/// Motivation: to avoid error-prone mixing of signed and unsigned.
+///
+/// https://github.com/ericniebler/stl2/issues/182
+/// "The fact that .size() returns an unsigned integer and iterators'
+/// difference type is required to be signed pretty much guarantees
+/// that there will be signed/unsigned mismatches in simple and sane
+/// uses of the STL. It's a mess. We should use signed integers
+/// everywhere that bit-twiddling isn't required."
+///
+/// Also see:
+/// http://www.aristeia.com/Papers/C++ReportColumns/sep95.pdf
+/// and the panel discussion here:
+/// https://isocpp.org/blog/2013/09/goingnative-2013-videos-now-available
+/// relevant portions of which are transcribed below.
+///
+/// 12:55 Stroustrup: "Use int until you have a reason not to. Don't use
+/// unsigned unless you are fiddling with bit patterns. And never mix
+/// signed and unsigned."
+/// 42:55 Stroustrup: "Whenever you mix signed and unsigned numbers you
+/// get trouble. The rules are just very surprising, and they turn up in
+/// code in the strangest places. They correlate very strongly with bugs.
+/// Now, when people use unsigned numbers, they usually have a reason,
+/// and the reason will be something like, well, 'it can't be negative',
+/// or 'I need an extra bit'. If you need an extra bit, I am very
+/// reluctant to believe you that you really need it, and I don't think
+/// that's a good reason. When you think you can't have negative numbers,
+/// you will have somebody who initialized your unsigned with minus two,
+/// and think they get minus two--and things like that. It is just highly
+/// error prone. I think one of the sad things about the standard library
+/// is that the indices are unsigned, whereas array indices are signed,
+/// and you're sort of doomed to have confusion and problems with that.
+/// There are far too many integer types. There are far too lenient rules
+/// for mixing them together, and it's a major bug source--which is why
+/// I'm saying: stay as simple as you can, use integers till you really,
+/// really need something else."
+/// Sutter: "It's unfortunately a mistake in the STL, in the standard
+/// library, that we use unsigned indices."
+/// Carruth: "How frequently have you written arithmetic and wanted ...
+/// 2^32 modular behavior? That's really unusual. Why would you select a
+/// type which gives you that?"
+/// 1:02:50 Question: "but all of the ordinals in the STL, vector::size()
+/// and all that kind of stuff, they're unsigned and so it's..."
+/// Sutter: "They're wrong."
+/// Question: "...it's gonna pollute, right?"
+/// Sutter: "We're sorry. As Scott would say, 'we were young'."
+
+namespace lmi
+{
+using ssize_t = std::make_signed_t<std::size_t>;
+
+template<typename Container>
+constexpr ssize_t ssize(Container const& c)
+{
+ return bourn_cast<ssize_t>(c.size());
+}
+
+template<typename T, std::size_t n>
+constexpr ssize_t ssize(T const(&)[n])
+{
+ return bourn_cast<ssize_t>(n);
+}
+
+inline ssize_t sstrlen(char const* s)
+{
+ return bourn_cast<ssize_t>(std::strlen(s));
+}
+} // namespace lmi
+
+#endif // ssize_lmi_hpp
diff --git a/ssize_lmi_test.cpp b/ssize_lmi_test.cpp
new file mode 100644
index 0000000..c05f207
--- /dev/null
+++ b/ssize_lmi_test.cpp
@@ -0,0 +1,59 @@
+// Improved std::size() that returns a signed integer: unit test.
+//
+// Copyright (C) 2018 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+#include "pchfile.hpp"
+
+#include "ssize_lmi.hpp"
+
+#include "bourn_cast.hpp"
+#include "test_tools.hpp"
+
+#include <array>
+#include <cstring> // strlen()
+#include <iterator> // size()
+#include <string>
+#include <vector>
+
+int test_main(int, char*[])
+{
+ char const c[2] = {'0'};
+ BOOST_TEST_EQUAL(lmi::ssize(c), 2);
+ BOOST_TEST_EQUAL(lmi::ssize(c), bourn_cast<int>(std::size(c)));
+
+ std::array<int,3> const a{1, 2};
+ BOOST_TEST_EQUAL(lmi::ssize(a), 3);
+ BOOST_TEST_EQUAL(lmi::ssize(a), bourn_cast<int>(std::size(a)));
+
+ std::vector<int> const v(5);
+ BOOST_TEST_EQUAL(lmi::ssize(v), 5);
+ BOOST_TEST_EQUAL(lmi::ssize(v), bourn_cast<int>(std::size(v)));
+
+ std::string const s("abcdefg");
+ BOOST_TEST_EQUAL(lmi::ssize(s), 7);
+ BOOST_TEST_EQUAL(lmi::ssize(s), bourn_cast<int>(std::size(s)));
+
+ char const* p = "ABCDEFGHIJK";
+ BOOST_TEST_EQUAL(lmi::sstrlen(p), 11);
+ BOOST_TEST_EQUAL(lmi::sstrlen(p), bourn_cast<int>(std::strlen(p)));
+
+ return 0;
+}
+