[PATCH] Optimize truncating a basic_string

Jonathan Wakely jwakely@redhat.com
Fri Sep 23 17:30:00 GMT 2016


Currently str.erase(n) doesn't get inlined at -O2 and calls
_M_erase(n, length() - pos), which isn't very efficient. By checking
for the common case of erasing everything up to the end of the string
and avoiding _M_erase we can get it inlined. We can do the same thing
in erase(const_iterator, const_iterator) too by checking if the second
iterator is end(), and for resize() we don't even need to check
because (when shrinking the string) we know we're erasing to the end.

Thanks to Pedro Alves for pointing out this could be improved.

	* include/bits/basic_string.h [_GLIBCXX_USE_CXX11_ABI]
	(basic_string::erase(size_type, size_type)): Add fast path for
	truncating the string, by calling _M_set_length directly.
	(basic_string::erase(__const_iterator, __const_iterator)): Likewise.
	* include/bits/basic_string.tcc [_GLIBCXX_USE_CXX11_ABI]
	(basic_string::resize(size_type, _CharT)): Likewise.

Tested x86_64-linux, committed to trunk.


-------------- next part --------------
commit 63b539ac150ca68fe4f6762fc341bbc4a7737152
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Sep 23 16:55:42 2016 +0100

    Optimize truncating a basic_string
    
    	* include/bits/basic_string.h [_GLIBCXX_USE_CXX11_ABI]
    	(basic_string::erase(size_type, size_type)): Add fast path for
    	truncating the string, by calling _M_set_length directly.
    	(basic_string::erase(__const_iterator, __const_iterator)): Likewise.
    	* include/bits/basic_string.tcc [_GLIBCXX_USE_CXX11_ABI]
    	(basic_string::resize(size_type, _CharT)): Likewise.

diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index e823f13..2708cbc 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -1709,8 +1709,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       basic_string&
       erase(size_type __pos = 0, size_type __n = npos)
       {
-	this->_M_erase(_M_check(__pos, "basic_string::erase"),
-		       _M_limit(__pos, __n));
+	_M_check(__pos, "basic_string::erase");
+	if (__n == npos)
+	  this->_M_set_length(__pos);
+	else if (__n != 0)
+	  this->_M_erase(__pos, _M_limit(__pos, __n));
 	return *this;
       }
 
@@ -1747,7 +1750,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	_GLIBCXX_DEBUG_PEDASSERT(__first >= begin() && __first <= __last
 				 && __last <= end());
         const size_type __pos = __first - begin();
-	this->_M_erase(__pos, __last - __first);
+	if (__last == end())
+	  this->_M_set_length(__pos);
+	else
+	  this->_M_erase(__pos, __last - __first);
 	return iterator(this->_M_data() + __pos);
       }
 
diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc
index 0080d2b..df1e8dd 100644
--- a/libstdc++-v3/include/bits/basic_string.tcc
+++ b/libstdc++-v3/include/bits/basic_string.tcc
@@ -351,7 +351,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       if (__size < __n)
 	this->append(__n - __size, __c);
       else if (__n < __size)
-	this->_M_erase(__n, __size - __n);
+	this->_M_set_length(__n);
     }
 
   template<typename _CharT, typename _Traits, typename _Alloc>


More information about the Gcc-patches mailing list