diff mbox

[v3] Reduce the size of variant, it doesn't need an index of type size_t internally.

Message ID CAFk2RUZvtch1=XANuPeomv+vfL_5tt8ZXWA6jr_tfXwgY03EHA@mail.gmail.com
State New
Headers show

Commit Message

Ville Voutilainen Jan. 9, 2017, 6:56 p.m. UTC
Tested on Linux-x64.

2017-01-09  Ville Voutilainen  <ville.voutilainen@gmail.com>

    Reduce the size of variant, it doesn't need an index of
    type size_t internally.
    * include/std/variant (parse_numbers.h): New include.
    (__select_index): New.
    (_Variant_storage<false, _Types...>::_M_reset_impl): Use
    _index_type for comparison with variant_npos.
    (_Variant_storage<false, _Types...>::__index_type): New.
    (_Variant_storage<false, _Types...>::_M_index): Change the
    type from size_t to __index_type.
    (_Variant_storage<true, _Types...>::__index_type): New.
    (_Variant_storage<true, _Types...>::_M_index): Change the
    type from size_t to __index_type.
    (_Variant_base::_M_valid): Use __index_type for comparison
    with variant_npos.
    (variant::__index_type): New.
    (variant::index): Use __index_type for comparison with variant_npos.
    * testsuite/20_util/variant/index_type.cc: New.
diff mbox

Patch

diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 3d025a7..b016f32 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -43,6 +43,7 @@ 
 #include <bits/functional_hash.h>
 #include <bits/invoke.h>
 #include <ext/aligned_buffer.h>
+#include <bits/parse_numbers.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -314,6 +315,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<bool __trivially_destructible, typename... _Types>
     struct _Variant_storage;
 
+  template <typename... _Types>
+  using __select_index =
+    typename __select_int::_Select_int_base<sizeof...(_Types)+1,
+					    unsigned char,
+					    unsigned short>
+    ::type::value_type;
+
   template<typename... _Types>
     struct _Variant_storage<false, _Types...>
     {
@@ -332,7 +340,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<size_t... __indices>
 	constexpr void _M_reset_impl(std::index_sequence<__indices...>)
 	{
-	  if (_M_index != variant_npos)
+	  if (_M_index != __index_type(variant_npos))
 	    _S_vtable<__indices...>[_M_index](*this);
 	}
 
@@ -346,7 +354,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { _M_reset(); }
 
       _Variadic_union<_Types...> _M_u;
-      size_t _M_index;
+      using __index_type = __select_index<_Types...>;
+      __index_type _M_index;
     };
 
   template<typename... _Types>
@@ -364,7 +373,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { _M_index = variant_npos; }
 
       _Variadic_union<_Types...> _M_u;
-      size_t _M_index;
+      using __index_type = __select_index<_Types...>;
+      __index_type _M_index;
     };
 
   // Helps SFINAE on special member functions. Otherwise it can live in variant
@@ -487,7 +497,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       constexpr bool
       _M_valid() const noexcept
-      { return this->_M_index != variant_npos; }
+      {
+	return this->_M_index !=
+	  typename _Storage::__index_type(variant_npos);
+      }
     };
 
   // For how many times does _Tp appear in _Tuple?
@@ -944,6 +957,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  __detail::__variant::__index_of_v<_Tp, _Types...>;
 
     public:
+      using __index_type = typename _Base::_Storage::__index_type;
       constexpr variant()
       noexcept(is_nothrow_default_constructible_v<__to_type<0>>) = default;
       variant(const variant&) = default;
@@ -1086,7 +1100,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return !this->_M_valid(); }
 
       constexpr size_t index() const noexcept
-      { return this->_M_index; }
+      {
+	if (this->_M_index == __index_type(variant_npos))
+	  return variant_npos;
+	return this->_M_index;
+      }
 
       void
       swap(variant& __rhs)
diff --git a/libstdc++-v3/testsuite/20_util/variant/index_type.cc b/libstdc++-v3/testsuite/20_util/variant/index_type.cc
new file mode 100644
index 0000000..ea6b4d6
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/variant/index_type.cc
@@ -0,0 +1,43 @@ 
+// { dg-options "-std=gnu++17" }
+// { dg-do compile }
+
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library 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 library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <variant>
+#include <type_traits>
+#include <climits>
+
+template <size_t N> struct Bogus {};
+
+template <size_t... I> auto f(std::index_sequence<I...>)
+{
+  return std::variant<Bogus<I>...>{};
+}
+
+static_assert(sizeof(char) >= sizeof(int) ||
+	      CHAR_BIT != 8 ||
+	      std::is_same_v<
+	      decltype(f(std::make_index_sequence<3>()))::__index_type,
+	      unsigned char>);
+
+static_assert(sizeof(char) >= sizeof(int) ||
+	      sizeof(char) >= sizeof(short) ||
+	      CHAR_BIT != 8 ||
+	      std::is_same_v<
+	      decltype(f(std::make_index_sequence<260>()))::__index_type,
+	      unsigned short>);