public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jonathan Wakely <jwakely@redhat.com>
To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org
Subject: [committed] libstdc++: Micro-optimize construction of named std::locale
Date: Thu, 17 Aug 2023 21:32:24 +0100	[thread overview]
Message-ID: <20230817203228.1131577-1-jwakely@redhat.com> (raw)

Tested x86_64-linux. Pushed to trunk.

-- >8 --

This shaves about 100ns off the std::locale constructor for named
locales (which is only about 1% of the total time).

Using !*s instead of !strcmp(s, "") doesn't make any difference as GCC
optimizes that already even at -O1. !strcmp(s, "C") is optimized at -O2
so replacing that with s[0] == 'C' && s[1] == '\0' only matters for the
--enable-libstdcxx-debug builds. But !strcmp(s, "POSIX") always makes a
call to strcmp at any optimization level. We make that strcmp call,
maybe several times, for any locale name except for "C" (which will be
matched before we get to the check for "POSIX").

For most targets, locale names begin with a lowercase letter and the
only one that begins with 'P' is "POSIX". Replacing !strcmp(s, "POSIX")
with s[0] == 'P' && !strcmp(s+1, "OSIX") means that we avoid calling
strcmp unless the string really does match "POSIX".

Maybe more importantly, I find is_C_locale(s) easier to read than
strcmp(s, "C") == 0 || strcmp(s, "POSIX") == 0, and !is_C_locale(s)
easier to read than strcmp(s, "C") != 0 && strcmp(s, "POSIX") != 0.

libstdc++-v3/ChangeLog:

	* src/c++98/localename.cc (is_C_locale): New function.
	(locale::locale(const char*)): Use is_C_locale.
---
 libstdc++-v3/src/c++98/localename.cc | 39 ++++++++++++++++------------
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/libstdc++-v3/src/c++98/localename.cc b/libstdc++-v3/src/c++98/localename.cc
index 25e6d966dca..68cb81d0709 100644
--- a/libstdc++-v3/src/c++98/localename.cc
+++ b/libstdc++-v3/src/c++98/localename.cc
@@ -36,24 +36,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   using namespace __gnu_cxx;
 
+  static inline bool
+  is_C_locale(const char* s)
+  {
+    switch (s[0])
+    {
+    case 'C':
+      return s[1] == '\0';
+    case 'P':
+      return !std::strcmp(s+1, "OSIX");
+    default:
+      return false;
+    }
+  }
+
   locale::locale(const char* __s) : _M_impl(0)
   {
     if (__s)
       {
 	_S_initialize();
-	if (std::strcmp(__s, "C") == 0 || std::strcmp(__s, "POSIX") == 0)
+	if (is_C_locale(__s))
 	  (_M_impl = _S_classic)->_M_add_reference();
-	else if (std::strcmp(__s, "") != 0)
+	else if (*__s)
 	  _M_impl = new _Impl(__s, 1);
 	else
 	  {
 	    // Get it from the environment.
 	    char* __env = std::getenv("LC_ALL");
 	    // If LC_ALL is set we are done.
-	    if (__env && std::strcmp(__env, "") != 0)
+	    if (__env && *__env)
 	      {
-		if (std::strcmp(__env, "C") == 0
-		    || std::strcmp(__env, "POSIX") == 0)
+		if (is_C_locale(__env))
 		  (_M_impl = _S_classic)->_M_add_reference();
 		else
 		  _M_impl = new _Impl(__env, 1);
@@ -63,9 +76,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		// LANG may set a default different from "C".
 		string __lang;
 		__env = std::getenv("LANG");
-		if (!__env || std::strcmp(__env, "") == 0
-		    || std::strcmp(__env, "C") == 0
-		    || std::strcmp(__env, "POSIX") == 0)
+		if (!__env || !*__env || is_C_locale(__env))
 		  __lang = "C";
 		else
 		  __lang = __env;
@@ -77,17 +88,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		  for (; __i < _S_categories_size; ++__i)
 		    {
 		      __env = std::getenv(_S_categories[__i]);
-		      if (__env && std::strcmp(__env, "") != 0
-			  && std::strcmp(__env, "C") != 0
-			  && std::strcmp(__env, "POSIX") != 0)
+		      if (__env && *__env && !is_C_locale(__env))
 			break;
 		    }
 		else
 		  for (; __i < _S_categories_size; ++__i)
 		    {
 		      __env = std::getenv(_S_categories[__i]);
-		      if (__env && std::strcmp(__env, "") != 0
-			  && __lang != __env)
+		      if (__env && *__env && __lang != __env)
 			break;
 		    }
 
@@ -113,14 +121,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		      {
 			__env = std::getenv(_S_categories[__i]);
 			__str += _S_categories[__i];
-			if (!__env || std::strcmp(__env, "") == 0)
+			if (!__env || !*__env)
 			  {
 			    __str += '=';
 			    __str += __lang;
 			    __str += ';';
 			  }
-			else if (std::strcmp(__env, "C") == 0
-				 || std::strcmp(__env, "POSIX") == 0)
+			else if (is_C_locale(__env))
 			  __str += "=C;";
 			else
 			  {
-- 
2.41.0


                 reply	other threads:[~2023-08-17 20:32 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230817203228.1131577-1-jwakely@redhat.com \
    --to=jwakely@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=libstdc++@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).