]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix and complete __gnu_debug::basic_string implementation
authorFrançois Dumont <fdumont@gcc.gnu.org>
Fri, 5 Mar 2021 17:50:22 +0000 (18:50 +0100)
committerFrançois Dumont <fdumont@gcc.gnu.org>
Thu, 25 Mar 2021 20:56:14 +0000 (21:56 +0100)
Fix and complete __gnu_debug::basic_string so that it can be used as a transparent
replacement of std::basic_string.

libstdc++-v3/ChangeLog:

* include/debug/string
(basic_string(const basic_string&, const _Alloc&)): Define even if !_GLIBCXX_USE_CXX11_ABI.
(basic_string(basic_string&&, const _Alloc&)): Likewise and add noexcept qualification.
(basic_string<>::erase): Adapt to take __const_iterator.
(basic_string(const _CharT*, const _Allocator&)): Remove assign call.
(basic_string<>::insert(const_iterator, _InputIte, _InputIte)): Try to
remove iterator debug layer even if !_GLIBCXX_USE_CXX11_ABI.
[_GLIBCXX_USE_CHAR8_T] (__gnu_debug::u8string): New.
(__gnu_debug::u16string, __gnu_debug::u32string): New.
(std::hash<__gnu_debug::basic_string<>>): New partial specialization.
(std::__is_fast_hash<__gnu_debug::basic_string<>>): Likewise.
* testsuite/util/exception/safety.h
(erase_base<__gnu_debug::basic_string<>>): New partial specialization.
(insert_base<__gnu_debug::basic_string<>>): Likewise.
* testsuite/util/testsuite_container_traits.h (traits<__gnu_debug::basic_string<>>):
New partial specialization.
* testsuite/21_strings/basic_string/hash/debug.cc: New test.
* testsuite/21_strings/basic_string/requirements/citerators.cc:
Add test on __gnu_debug::string.
* testsuite/21_strings/basic_string/requirements/dr438/constructor.cc: Likewise.
* testsuite/21_strings/basic_string/requirements/exception/basic.cc: Likewise.
* testsuite/21_strings/basic_string/requirements/exception/generation_prohibited.cc:
Likewise.
* testsuite/21_strings/basic_string/requirements/exception/propagation_consistent.cc:
Likewise.
* testsuite/21_strings/basic_string/requirements/explicit_instantiation/char/1.cc:
Likewise.
* testsuite/21_strings/basic_string/requirements/explicit_instantiation/char16_t/1.cc:
Likewise.
* testsuite/21_strings/basic_string/requirements/explicit_instantiation/char32_t/1.cc:
Likewise.
* testsuite/21_strings/basic_string/requirements/explicit_instantiation/char8_t/1.cc:
Likewise.
* testsuite/21_strings/basic_string/requirements/explicit_instantiation/wchar_t/1.cc:
Likewise.
* testsuite/21_strings/basic_string/requirements/typedefs.cc: Likewise.

15 files changed:
libstdc++-v3/include/debug/string
libstdc++-v3/testsuite/21_strings/basic_string/hash/debug.cc [new file with mode: 0644]
libstdc++-v3/testsuite/21_strings/basic_string/requirements/citerators.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/dr438/constructor.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/exception/basic.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/exception/generation_prohibited.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/exception/propagation_consistent.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/explicit_instantiation/char/1.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/explicit_instantiation/char16_t/1.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/explicit_instantiation/char32_t/1.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/explicit_instantiation/char8_t/1.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/explicit_instantiation/wchar_t/1.cc
libstdc++-v3/testsuite/21_strings/basic_string/requirements/typedefs.cc
libstdc++-v3/testsuite/util/exception/safety.h
libstdc++-v3/testsuite/util/testsuite_container_traits.h

index 172179530aa3db36f196572023a00d676faa519d..8744a55be64236e80c19ad3f28ab1c1199574d80 100644 (file)
     __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func)          \
       ._M_message(#_Cond)._M_error()
 
+#if _GLIBCXX_USE_CXX11_ABI && __cplusplus >= 201103
+# define _GLIBCXX_INSERT_RETURNS_ITERATOR 1
+# define _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(expr) expr
+#else
+# define _GLIBCXX_INSERT_RETURNS_ITERATOR 0
+# define _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(expr)
+#endif
+
 namespace __gnu_debug
 {
   /** Checks that __s is non-NULL or __n == 0, and then returns __s. */
@@ -123,21 +131,21 @@ namespace __gnu_debug
 
       using _Base::npos;
 
-      basic_string()
-       _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_default_constructible<_Base>::value)
-       : _Base() { }
-
       // 21.3.1 construct/copy/destroy:
+
       explicit
       basic_string(const _Allocator& __a) _GLIBCXX_NOEXCEPT
       : _Base(__a) { }
 
 #if __cplusplus < 201103L
+      basic_string() : _Base() { }
+
       basic_string(const basic_string& __str)
       : _Base(__str) { }
 
       ~basic_string() { }
 #else
+      basic_string() = default;
       basic_string(const basic_string&) = default;
       basic_string(basic_string&&) = default;
 
@@ -146,13 +154,15 @@ namespace __gnu_debug
       : _Base(__l, __a)
       { }
 
-#if _GLIBCXX_USE_CXX11_ABI
       basic_string(const basic_string& __s, const _Allocator& __a)
       : _Base(__s, __a) { }
 
       basic_string(basic_string&& __s, const _Allocator& __a)
-      : _Base(std::move(__s), __a) { }
-#endif
+      noexcept(
+       std::is_nothrow_constructible<_Base, _Base, const _Allocator&>::value )
+      : _Safe(std::move(__s._M_safe()), __a),
+       _Base(std::move(__s._M_base()), __a)
+      { }
 
       ~basic_string() = default;
 
@@ -178,7 +188,7 @@ namespace __gnu_debug
 
       basic_string(const _CharT* __s, const _Allocator& __a = _Allocator())
       : _Base(__glibcxx_check_string_constructor(__s), __a)
-      { this->assign(__s); }
+      { }
 
       basic_string(size_type __n, _CharT __c,
                   const _Allocator& __a = _Allocator())
@@ -635,15 +645,22 @@ namespace __gnu_debug
          __glibcxx_check_insert_range(__p, __first, __last, __dist);
 
          typename _Base::iterator __res;
-#if _GLIBCXX_USE_CXX11_ABI && __cplusplus >= 201103
+#if ! _GLIBCXX_INSERT_RETURNS_ITERATOR
+         const size_type __offset = __p.base() - _Base::begin();
+#endif
          if (__dist.second >= __dp_sign)
-           __res = _Base::insert(__p.base(), __gnu_debug::__unsafe(__first),
-                                 __gnu_debug::__unsafe(__last));
+           {
+             _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(__res =)
+               _Base::insert(__p.base(), __gnu_debug::__unsafe(__first),
+                             __gnu_debug::__unsafe(__last));
+           }
          else
-           __res = _Base::insert(__p.base(), __first, __last);
-#else
-         const size_type __offset = __p.base() - _Base::begin();
-         _Base::insert(__p.base(), __first, __last);
+           {
+             _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(__res =)
+               _Base::insert(__p.base(), __first, __last);
+           }
+
+#if ! _GLIBCXX_INSERT_RETURNS_ITERATOR
          __res = _Base::begin() + __offset;
 #endif
          this->_M_invalidate_all();
@@ -676,7 +693,7 @@ namespace __gnu_debug
       }
 
       iterator
-      erase(iterator __position)
+      erase(__const_iterator __position)
       {
        __glibcxx_check_erase(__position);
        typename _Base::iterator __res = _Base::erase(__position.base());
@@ -685,7 +702,7 @@ namespace __gnu_debug
       }
 
       iterator
-      erase(iterator __first, iterator __last)
+      erase(__const_iterator __first, __const_iterator __last)
       {
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 151. can't currently clear() empty container
@@ -1285,6 +1302,19 @@ namespace __gnu_debug
   typedef basic_string<wchar_t> wstring;
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// A string of @c char8_t
+  typedef basic_string<char8_t> u8string;
+#endif
+
+#if __cplusplus >= 201103L
+  /// A string of @c char16_t
+  typedef basic_string<char16_t> u16string;
+
+  /// A string of @c char32_t
+  typedef basic_string<char32_t> u32string;
+#endif
+
   template<typename _CharT, typename _Traits, typename _Allocator>
     struct _Insert_range_from_self_is_safe<
       __gnu_debug::basic_string<_CharT, _Traits, _Allocator> >
@@ -1292,4 +1322,27 @@ namespace __gnu_debug
 
 } // namespace __gnu_debug
 
+#if __cplusplus >= 201103L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /// std::hash specialization for __gnu_debug::basic_string.
+  template<typename _CharT>
+    struct hash<__gnu_debug::basic_string<_CharT>>
+    : public hash<std::basic_string<_CharT>>
+    { };
+
+  template<typename _CharT>
+    struct __is_fast_hash<hash<__gnu_debug::basic_string<_CharT>>>
+    : __is_fast_hash<hash<std::basic_string<_CharT>>>
+    { };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+}
+#endif /* C++11 */
+
+#undef _GLIBCXX_INSERT_RETURNS_ITERATOR
+#undef _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY
+
 #endif
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/hash/debug.cc b/libstdc++-v3/testsuite/21_strings/basic_string/hash/debug.cc
new file mode 100644 (file)
index 0000000..596bff9
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright (C) 2021 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/>.
+
+// { dg-do run { target c++17 } }
+
+#include <debug/string>
+#include <memory_resource>
+#include <testsuite_hooks.h>
+
+// C++17 24.3.5 [basic.string.hash]
+// If S is one of these string types, SV is the corresponding string view type,
+// and s is an object of type S, then hash<S>()(s) == hash<SV>()(SV(s)).
+
+template<typename S>
+  bool
+  test(const S& s)
+  {
+    using std::hash;
+    using SV = std::basic_string_view<typename S::value_type>;
+    return hash<S>()(s) == hash<SV>()(SV(s));
+  }
+
+void
+test01()
+{
+  VERIFY( test(__gnu_debug::string("a narrow string")) );
+#if _GLIBCXX_USE_CHAR8_T
+  VERIFY( test(__gnu_debug::u8string(u8"a narrow string")) );
+#endif
+  VERIFY( test(__gnu_debug::u16string(u"a utf-16 string")) );
+  VERIFY( test(__gnu_debug::u32string(U"a utf-32 string")) );
+#if _GLIBCXX_USE_WCHAR_T
+  VERIFY( test(__gnu_debug::wstring(L"a wide string")) );
+#endif
+}
+
+#if _GLIBCXX_USE_CHAR8_T
+void
+test02()
+{
+  using std::hash;
+  __gnu_debug::string native("a string, a string, my stringdom for a string");
+  __gnu_debug::u8string utf8(u8"a string, a string, my stringdom for a string");
+  VERIFY( hash<__gnu_debug::string>()(native) == hash<__gnu_debug::u8string>()(utf8) );
+}
+#endif
+
+int
+main()
+{
+  test01();
+#if _GLIBCXX_USE_CHAR8_T
+  test02();
+#endif
+}
index 99bf5726dccb55207030101d0161d215788e5e46..fca2a8940e9af28974bda851c0831b55a49f4a87 100644 (file)
 // <http://www.gnu.org/licenses/>.
 
 #include <string>
+#include <debug/string>
+
 #include <testsuite_containers.h>
 
 int main()
 {
   __gnu_test::citerator<std::string> test1;
+  __gnu_test::citerator<__gnu_debug::string> dtest1;
 #ifdef _GLIBCXX_USE_WCHAR_T
   __gnu_test::citerator<std::wstring> test2;
+  __gnu_test::citerator<__gnu_debug::wstring> dtest2;
 #endif
   return 0;
 }
index 82d42ebb6a647227067778e8bc69f0c83849d56e..059e32aa970ac76cfaff567d99883fc6f8620803 100644 (file)
 // { dg-do compile }
 
 #include <string>
+#include <debug/string>
 
 void f()
 {
   std::string s(10, 1);
+  __gnu_debug::string ds(10, 1);
 }
index 2b6e27432e8744a888a5b297c0775f9fa5f0f243..2ff020d81d47eaf119712d33b2df857dd77bc163 100644 (file)
@@ -21,6 +21,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include <string>
+#include <debug/string>
 #include <exception/safety.h>
 
 void
@@ -31,8 +32,16 @@ value()
   typedef char value_type;
   typedef __gnu_cxx::throw_allocator_limit<value_type> allocator_type;
   typedef std::char_traits<value_type> traits_type;
-  typedef std::basic_string<value_type, traits_type, allocator_type> test_type;
-  __gnu_test::basic_safety<test_type> test;
+
+  {
+    typedef std::basic_string<value_type, traits_type, allocator_type> test_type;
+    __gnu_test::basic_safety<test_type> test;
+  }
+
+  {
+    typedef __gnu_debug::basic_string<value_type, traits_type, allocator_type> test_type;
+    __gnu_test::basic_safety<test_type> test;
+  }
 }
 
 // Container requirement testing, exceptional behavior
index 07d2a2e20741f6639cde151fc4d0676b78286fb1..02d3242db59341cd4d5d37f32b4b106875d818d1 100644 (file)
@@ -21,6 +21,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include <string>
+#include <debug/string>
 #include <exception/safety.h>
 
 void
@@ -29,8 +30,16 @@ char_allocator()
   typedef char value_type;
   typedef __gnu_cxx::throw_allocator_random<value_type> allocator_type;
   typedef std::char_traits<value_type> traits_type;
-  typedef std::basic_string<value_type, traits_type, allocator_type> test_type;
-  __gnu_test::generation_prohibited<test_type> test;
+
+  {
+    typedef std::basic_string<value_type, traits_type, allocator_type> test_type;
+    __gnu_test::generation_prohibited<test_type> test;
+  }
+
+  {
+    typedef __gnu_debug::basic_string<value_type, traits_type, allocator_type> test_type;
+    __gnu_test::generation_prohibited<test_type> test;
+  }
 }
 
 void
@@ -39,8 +48,16 @@ wchar_allocator()
   typedef wchar_t value_type;
   typedef __gnu_cxx::throw_allocator_random<value_type> allocator_type;
   typedef std::char_traits<value_type> traits_type;
-  typedef std::basic_string<value_type, traits_type, allocator_type> test_type;
-  __gnu_test::generation_prohibited<test_type> test;
+
+  {
+    typedef std::basic_string<value_type, traits_type, allocator_type> test_type;
+    __gnu_test::generation_prohibited<test_type> test;
+  }
+
+  {
+    typedef __gnu_debug::basic_string<value_type, traits_type, allocator_type> test_type;
+    __gnu_test::generation_prohibited<test_type> test;
+  }
 }
 
 // Container requirement testing, exceptional behavior
index ce99dab915e75a4bb6ac7565d460f1279a3aa0d8..0526745cb912eed80be75b59e4aecf846af2991a 100644 (file)
@@ -21,6 +21,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include <string>
+#include <debug/string>
 #include <exception/safety.h>
 
 void
@@ -31,8 +32,16 @@ value()
   typedef char value_type;
   typedef __gnu_cxx::throw_allocator_limit<value_type> allocator_type;
   typedef std::char_traits<value_type> traits_type;
-  typedef std::basic_string<value_type, traits_type, allocator_type> test_type;
-  __gnu_test::propagation_consistent<test_type> test;
+
+  {
+    typedef std::basic_string<value_type, traits_type, allocator_type> test_type;
+    __gnu_test::propagation_consistent<test_type> test;
+  }
+
+  {
+    typedef __gnu_debug::basic_string<value_type, traits_type, allocator_type> test_type;
+    __gnu_test::propagation_consistent<test_type> test;
+  }
 }
 
 // Container requirement testing, exceptional behavior
index 275354c1f4ccc6c99322fcfa6b18214204393219..9d2ca54c5df8a514ec0139a11f1c268cfd255f6a 100644 (file)
@@ -18,5 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include <string>
+#include <debug/string>
 
 template class std::basic_string<char>;
+template class __gnu_debug::basic_string<char>;
index 2b5139de533a178c1caab386b04d8e9c6c5a19bd..64030165d2b21521c0a6c03517c10ff690cee086 100644 (file)
@@ -18,5 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include <string>
+#include <debug/string>
 
 template class std::basic_string<char16_t>;
+template class __gnu_debug::basic_string<char16_t>;
index 0fa685e9094f955b162b79fabfe2208a00621ed6..6e12fadf8cd372e4d71a77a4ad8531a423684ee7 100644 (file)
@@ -18,5 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include <string>
+#include <debug/string>
 
 template class std::basic_string<char32_t>;
+template class __gnu_debug::basic_string<char32_t>;
index db88b0f47a33f3bfddd08355d4fc55e30a0c6967..abab7972b8d87a707a3777854c27e133ae50e128 100644 (file)
@@ -19,5 +19,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include <string>
+#include <debug/string>
 
 template class std::basic_string<char8_t>;
+template class __gnu_debug::basic_string<char8_t>;
index 7f16ca4cb5b7a1ac4b16752ecc00a2e264b68396..1a25fa839d4639835a1528bc6f152b36047d8216 100644 (file)
@@ -18,5 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include <string>
+#include <debug/string>
 
 template class std::basic_string<wchar_t>;
+template class __gnu_debug::basic_string<wchar_t>;
index 2fc313b9cbf9bdbd34fac796b8ce32eae7e63124..ff5f98e78058d283b3792725da6f5391b21e3cb3 100644 (file)
 
 #include <testsuite_containers.h>
 #include <string>
+#include <debug/string>
 
 // Check container for required typedefs.
 __gnu_test::types<std::string> t1;
+__gnu_test::types<__gnu_debug::string> dt1;
 #ifdef _GLIBCXX_USE_WCHAR_T
 __gnu_test::types<std::wstring> t2;
+__gnu_test::types<__gnu_debug::wstring> dt2;
 #endif
index 2e5d8acae00765c54bcd6d9da94f25450e6410ac..54449d2f7bb9fafe27b3f39f95b2f6c47e21675c 100644 (file)
@@ -275,6 +275,20 @@ namespace __gnu_test
        iterator (container_type::* _F_erase_point)(iterator);
        iterator (container_type::* _F_erase_range)(iterator, iterator);
 
+       erase_base()
+       : _F_erase_point(&container_type::erase),
+         _F_erase_range(&container_type::erase) { }
+      };
+
+    template<typename _Tp1, typename _Tp2, typename _Tp3>
+      struct erase_base<__gnu_debug::basic_string<_Tp1, _Tp2, _Tp3>>
+      {
+       typedef __gnu_debug::basic_string<_Tp1, _Tp2, _Tp3>     container_type;
+       typedef typename container_type::iterator       iterator;
+
+       iterator (container_type::* _F_erase_point)(iterator);
+       iterator (container_type::* _F_erase_range)(iterator, iterator);
+
        erase_base()
        : _F_erase_point(&container_type::erase),
          _F_erase_range(&container_type::erase) { }
@@ -701,6 +715,24 @@ namespace __gnu_test
        typedef typename container_type::const_iterator const_iterator;
        typedef typename container_type::value_type     value_type;
 
+#if _GLIBCXX_USE_CXX11_ABI == 0 || __cplusplus < 201103L
+       iterator (container_type::* _F_insert_point)(iterator, value_type);
+#else
+       iterator (container_type::* _F_insert_point)(const_iterator,
+                                                    value_type);
+#endif
+
+       insert_base() : _F_insert_point(&container_type::insert) { }
+      };
+
+    template<typename _Tp1, typename _Tp2, typename _Tp3>
+      struct insert_base<__gnu_debug::basic_string<_Tp1, _Tp2, _Tp3>>
+      {
+       typedef __gnu_debug::basic_string<_Tp1, _Tp2, _Tp3>     container_type;
+       typedef typename container_type::iterator       iterator;
+       typedef typename container_type::const_iterator const_iterator;
+       typedef typename container_type::value_type     value_type;
+
 #if _GLIBCXX_USE_CXX11_ABI == 0 || __cplusplus < 201103L
        iterator (container_type::* _F_insert_point)(iterator, value_type);
 #else
index fb1f558011c0a369072e60a0ecfe1001b4939655..0bc7a2aa53ae76d6e0293a221d33da23ab19f62c 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <bits/stdc++.h>
 #include <ext/vstring.h>
+#include <debug/string>
 
 namespace __gnu_test
 {
@@ -128,6 +129,17 @@ namespace __gnu_test
       typedef std::true_type   has_insert;
     };
 
+  template<typename _Tp1, typename _Tp2, typename _Tp3>
+    struct traits<__gnu_debug::basic_string<_Tp1, _Tp2, _Tp3>> : public traits_base
+    {
+      typedef std::true_type    is_container;
+      typedef std::true_type    is_reversible;
+      typedef std::true_type    is_allocator_aware;
+
+      typedef std::true_type   has_erase;
+      typedef std::true_type   has_insert;
+    };
+
   template<typename _Tp1, typename _Tp2, typename _Tp3,
           template <typename, typename, typename> class _Tp4>
     struct traits<__gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>>