This set of patches adds a new module 'mbiterf', similar to 'mbiter',
just faster. The 'f' stands for "faster" or "functional style".

Kudos to Paul Eggert for the intuition that a function that returns values
is more efficient than an equivalent function that modifies state and
returns void.

The benchmarks clearly show the speedup, especially for the case of ASCII
text (CPU time, measured on x86_64, with gcc 13, on an AMD Ryzen 7 CPU):

    mbiter  mbiterf
a    0.926   0.230
b    0.765   0.233
c    1.706   1.125
d    1.324   0.847
e    1.580   0.889
f   14.134  13.095
g    8.409   8.244
h    8.882   8.553
i    4.110   4.000
j    4.430   4.212

The module 'mbiter' is still recommended for more complicated code
that is not performance critical, because it has a simpler idiom.


2023-07-18  Bruno Haible  <[email protected]>

        trim: Optimize.
        * lib/trim.c: Include mbiterf.h instead of mbiter.h.
        (trim2): Use mbif_* macros instead of mbi_* macros.
        * modules/trim (Depends-on): Add mbiterf. Remove mbiter.

        mbmemcasecmp: Optimize.
        * lib/mbmemcasecmp.c: Include mbiterf.h instead of mbiter.h.
        (mbmemcasecmp): Use mbif_* macros instead of mbi_* macros.
        * modules/mbmemcasecmp (Depends-on): Add mbiterf. Remove mbiter.

        mbsnlen: Optimize.
        * lib/mbsnlen.c: Include mbiterf.h instead of mbiter.h.
        (mbsnlen): Use mbif_* macros instead of mbi_* macros.
        * modules/mbsnlen (Depends-on): Add mbiterf. Remove mbiter.

        mbiterf: Add a benchmark.
        * tests/bench-mbiterf.c: New file, based on tests/bench-mbiter.c.
        * modules/mbiterf-bench-tests: New file, based on
        modules/mbiter-bench-tests.

        mbiterf: New module.
        * lib/mbiterf.h: New file, based on lib/mbiter.h.
        * lib/mbiterf.c: New file, based on lib/mbiter.c.
        * modules/mbiterf: New file, based on modules/mbiter.

>From 2cc8acfd202ee500f273592e27ab780bcc8b6b81 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 12:13:57 +0200
Subject: [PATCH 1/5] mbiterf: New module.

* lib/mbiterf.h: New file, based on lib/mbiter.h.
* lib/mbiterf.c: New file, based on lib/mbiter.c.
* modules/mbiterf: New file, based on modules/mbiter.
---
 ChangeLog       |   7 ++
 lib/mbiterf.c   |  21 +++++
 lib/mbiterf.h   | 203 ++++++++++++++++++++++++++++++++++++++++++++++++
 modules/mbiterf |  37 +++++++++
 4 files changed, 268 insertions(+)
 create mode 100644 lib/mbiterf.c
 create mode 100644 lib/mbiterf.h
 create mode 100644 modules/mbiterf

diff --git a/ChangeLog b/ChangeLog
index 53ed5759dd..108f1281c8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2023-07-18  Bruno Haible  <[email protected]>
+
+	mbiterf: New module.
+	* lib/mbiterf.h: New file, based on lib/mbiter.h.
+	* lib/mbiterf.c: New file, based on lib/mbiter.c.
+	* modules/mbiterf: New file, based on modules/mbiter.
+
 2023-07-18  Bruno Haible  <[email protected]>
 
 	mbstok_r: Simplify dependencies.
diff --git a/lib/mbiterf.c b/lib/mbiterf.c
new file mode 100644
index 0000000000..4c8168d3e3
--- /dev/null
+++ b/lib/mbiterf.c
@@ -0,0 +1,21 @@
+/* Iterating through multibyte strings: macros for multi-byte encodings.
+
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#define MBITERF_INLINE _GL_EXTERN_INLINE
+#include "mbiterf.h"
diff --git a/lib/mbiterf.h b/lib/mbiterf.h
new file mode 100644
index 0000000000..0059c97fbd
--- /dev/null
+++ b/lib/mbiterf.h
@@ -0,0 +1,203 @@
+/* Iterating through multibyte strings, faster: macros for multi-byte encodings.
+   Copyright (C) 2001, 2005, 2007, 2009-2023 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <[email protected]>,
+   with insights from Paul Eggert.  */
+
+/* The macros in this file implement forward iteration through a
+   multi-byte string.
+
+   With these macros, an iteration loop that looks like
+
+      char *iter;
+      for (iter = buf; iter < buf + buflen; iter++)
+        {
+          do_something (*iter);
+        }
+
+   becomes
+
+      const char *buf_end = buf + buflen;
+      mbif_state_t state;
+      [const] char *iter;
+      for (mbif_init (state), iter = buf; mbif_avail (state, iter, buf_end); )
+        {
+          mbchar_t cur = mbif_next (state, iter, buf_end);
+          // Note: Here always mb_ptr (cur) == iter.
+          do_something (iter, mb_len (cur));
+          iter += mb_len (cur);
+        }
+
+   The benefit of these macros over plain use of mbrtowc or mbrtoc32 is:
+   - Handling of invalid multibyte sequences is possible without
+     making the code more complicated, while still preserving the
+     invalid multibyte sequences.
+
+   The benefit of these macros over those from mbiter.h is that it
+   produces faster code with today's optimizing compilers (because mbif_next
+   returns its result by value).
+
+   mbif_state_t
+     is a type usable for variable declarations.
+
+   mbif_init (state)
+     initializes the state.
+
+   mbif_avail (state, iter, endptr)
+     returns true if another loop round is needed.
+
+   mbif_next (state, iter, endptr)
+     returns the next multibyte character.
+     It asssumes that the state is initialized and that iter < endptr.
+
+   Here are the function prototypes of the macros.
+
+   extern void      mbif_init (mbif_state_t state);
+   extern bool      mbif_avail (mbif_state_t state, const char *iter, const char *endptr);
+   extern mbchar_t  mbif_next (mbif_state_t state, const char *iter, const char *endptr);
+ */
+
+#ifndef _MBITERF_H
+#define _MBITERF_H 1
+
+/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE.  */
+#if !_GL_CONFIG_H_INCLUDED
+ #error "Please include config.h first."
+#endif
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include <uchar.h>
+#include <wchar.h>
+
+#include "mbchar.h"
+
+_GL_INLINE_HEADER_BEGIN
+#ifndef MBITERF_INLINE
+# define MBITERF_INLINE _GL_INLINE
+#endif
+
+struct mbif_state
+{
+  #if !GNULIB_MBRTOC32_REGULAR
+  bool in_shift;        /* true if next byte may not be interpreted as ASCII */
+                        /* If GNULIB_MBRTOC32_REGULAR, it is always false,
+                           so optimize it away.  */
+  #endif
+  mbstate_t state;      /* if in_shift: current shift state */
+                        /* If GNULIB_MBRTOC32_REGULAR, it is in an initial state
+                           before and after every mbiterf_next invocation.
+                         */
+};
+
+MBITERF_INLINE mbchar_t
+mbiterf_next (struct mbif_state *ps, const char *iter, const char *endptr)
+{
+  #if !GNULIB_MBRTOC32_REGULAR
+  if (ps->in_shift)
+    goto with_shift;
+  #endif
+  /* Handle most ASCII characters quickly, without calling mbrtowc().  */
+  if (is_basic (*iter))
+    {
+      /* These characters are part of the POSIX portable character set.
+         For most of them, namely those in the ISO C basic character set,
+         ISO C 99 guarantees that their wide character code is identical to
+         their char code.  For the few other ones, this is the case as well,
+         in all locale encodings that are in use.  The 32-bit wide character
+         code is the same as well.  */
+      return (mbchar_t) { ptr: iter, bytes: 1, wc_valid: true, wc: *iter };
+    }
+  else
+    {
+      assert (mbsinit (&ps->state));
+      #if !GNULIB_MBRTOC32_REGULAR
+      ps->in_shift = true;
+    with_shift:
+      #endif
+      size_t bytes;
+      char32_t wc;
+      bytes = mbrtoc32 (&wc, iter, endptr - iter, &ps->state);
+      if (bytes == (size_t) -1)
+        {
+          /* An invalid multibyte sequence was encountered.  */
+          /* Allow the next invocation to continue from a sane state.  */
+          #if !GNULIB_MBRTOC32_REGULAR
+          ps->in_shift = false;
+          #endif
+          mbszero (&ps->state);
+          return (mbchar_t) { ptr: iter, bytes: 1, wc_valid: false };
+        }
+      else if (bytes == (size_t) -2)
+        {
+          /* An incomplete multibyte character at the end.  */
+          #if !GNULIB_MBRTOC32_REGULAR
+          ps->in_shift = false;
+          #endif
+          /* Whether to reset ps->state or not is not important; the string end
+             is reached anyway.  */
+          return (mbchar_t) { ptr: iter, bytes: endptr - iter, wc_valid: false };
+        }
+      else
+        {
+          if (bytes == 0)
+            {
+              /* A null wide character was encountered.  */
+              bytes = 1;
+              assert (*iter == '\0');
+              assert (wc == 0);
+            }
+          #if !GNULIB_MBRTOC32_REGULAR
+          else if (bytes == (size_t) -3)
+            /* The previous multibyte sequence produced an additional 32-bit
+               wide character.  */
+            bytes = 0;
+          #endif
+
+          /* When in an initial state, we can go back treating ASCII
+             characters more quickly.  */
+          #if !GNULIB_MBRTOC32_REGULAR
+          if (mbsinit (&ps->state))
+            ps->in_shift = false;
+          #endif
+          return (mbchar_t) { ptr: iter, bytes: bytes, wc_valid: true, wc: wc };
+        }
+    }
+}
+
+/* Iteration macros.  */
+typedef struct mbif_state mbif_state_t;
+#if !GNULIB_MBRTOC32_REGULAR
+#define mbif_init(st) \
+  ((st).in_shift = false, mbszero (&(st).state))
+#else
+/* Optimized: no in_shift.  */
+#define mbif_init(st) \
+  (mbszero (&(st).state))
+#endif
+#if !GNULIB_MBRTOC32_REGULAR
+#define mbif_avail(st, iter, endptr) ((st).in_shift || ((iter) < (endptr)))
+#else
+/* Optimized: no in_shift.  */
+#define mbif_avail(st, iter, endptr) ((iter) < (endptr))
+#endif
+#define mbif_next(st, iter, endptr) \
+  mbiterf_next (&(st), (iter), (endptr))
+
+_GL_INLINE_HEADER_END
+
+#endif /* _MBITERF_H */
diff --git a/modules/mbiterf b/modules/mbiterf
new file mode 100644
index 0000000000..cfdddc3c23
--- /dev/null
+++ b/modules/mbiterf
@@ -0,0 +1,37 @@
+Description:
+Iterating through multibyte strings, faster.
+
+Files:
+lib/mbiterf.h
+lib/mbiterf.c
+m4/mbiter.m4
+m4/mbrtowc.m4
+
+Depends-on:
+extern-inline
+mbchar
+mbrtoc32
+mbsinit
+mbszero
+uchar
+stdbool
+
+configure.ac:
+gl_MBITER
+
+Makefile.am:
+lib_SOURCES += mbiterf.h mbiterf.c
+
+Include:
+"mbiterf.h"
+
+Link:
+$(LTLIBUNISTRING) when linking with libtool, $(LIBUNISTRING) otherwise
+$(MBRTOWC_LIB)
+$(LTLIBC32CONV) when linking with libtool, $(LIBC32CONV) otherwise
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.34.1

>From 43b4207d784f7f3d0dfb8a2651fa4410eb08b8c6 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 12:15:59 +0200
Subject: [PATCH 2/5] mbiterf: Add a benchmark.

* tests/bench-mbiterf.c: New file, based on tests/bench-mbiter.c.
* modules/mbiterf-bench-tests: New file, based on
modules/mbiter-bench-tests.
---
 ChangeLog                   |   5 ++
 modules/mbiterf-bench-tests |  18 +++++
 tests/bench-mbiterf.c       | 138 ++++++++++++++++++++++++++++++++++++
 3 files changed, 161 insertions(+)
 create mode 100644 modules/mbiterf-bench-tests
 create mode 100644 tests/bench-mbiterf.c

diff --git a/ChangeLog b/ChangeLog
index 108f1281c8..8581c23a95 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbiterf: Add a benchmark.
+	* tests/bench-mbiterf.c: New file, based on tests/bench-mbiter.c.
+	* modules/mbiterf-bench-tests: New file, based on
+	modules/mbiter-bench-tests.
+
 	mbiterf: New module.
 	* lib/mbiterf.h: New file, based on lib/mbiter.h.
 	* lib/mbiterf.c: New file, based on lib/mbiter.c.
diff --git a/modules/mbiterf-bench-tests b/modules/mbiterf-bench-tests
new file mode 100644
index 0000000000..dfd39d2006
--- /dev/null
+++ b/modules/mbiterf-bench-tests
@@ -0,0 +1,18 @@
+Files:
+tests/bench-mbiterf.c
+tests/bench-multibyte.h
+tests/bench.h
+
+Depends-on:
+mbrtoc32-regular
+mbiterf
+setlocale
+striconv
+getrusage
+gettimeofday
+
+configure.ac:
+
+Makefile.am:
+noinst_PROGRAMS += bench-mbiterf
+bench_mbiterf_LDADD = $(LDADD) $(LIBUNISTRING) $(SETLOCALE_LIB) $(MBRTOWC_LIB) $(LIBC32CONV)
diff --git a/tests/bench-mbiterf.c b/tests/bench-mbiterf.c
new file mode 100644
index 0000000000..0949fb6752
--- /dev/null
+++ b/tests/bench-mbiterf.c
@@ -0,0 +1,138 @@
+/* Benchmarks for the mbiterf module.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   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, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <uchar.h>
+
+#include "bench.h"
+#include "bench-multibyte.h"
+#include "mbiterf.h"
+
+unsigned long long volatile result;
+
+static void
+do_test (char test, int repeat, const char *locale_name, const char *text)
+{
+  printf ("Test %c\n", test);
+  if (setlocale (LC_ALL, locale_name) != NULL)
+    {
+      struct timings_state ts;
+      timing_start (&ts);
+
+      size_t text_len = strlen (text);
+      int count;
+      for (count = 0; count < repeat; count++)
+        {
+          unsigned long long sum = 0;
+          const char *text_end = text + text_len;
+          mbif_state_t state;
+          char *iter;
+          for (mbif_init (state), iter = text; mbif_avail (state, iter, text_end); )
+            {
+              mbchar_t cur = mbif_next (state, iter, text_end);
+              sum += cur.wc;
+              iter += mb_len (cur);
+            }
+          result = sum;
+        }
+
+      timing_end (&ts);
+      timing_output (&ts);
+    }
+  else
+    {
+      printf ("Skipping test: locale %s not installed.\n", locale_name);
+    }
+  printf ("\n");
+}
+
+/* Performs some or all of the following tests:
+     a - ASCII text, C locale
+     b - ASCII text, UTF-8 locale
+     c - French text, C locale
+     d - French text, ISO-8859-1 locale
+     e - French text, UTF-8 locale
+     f - Greek text, C locale
+     g - Greek text, ISO-8859-7 locale
+     h - Greek text, UTF-8 locale
+     i - Chinese text, UTF-8 locale
+     j - Chinese text, GB18030 locale
+   Pass the tests to be performed as first argument.  */
+int
+main (int argc, char *argv[])
+{
+  if (argc != 3)
+    {
+      fprintf (stderr, "Usage: %s TESTS REPETITIONS\n", argv[0]);
+      fprintf (stderr, "Example: %s abcdefghij 100000\n", argv[0]);
+      exit (1);
+    }
+
+  const char *tests = argv[1];
+  int repeat = atoi (argv[2]);
+
+  text_init ();
+
+  /* Execute each test.  */
+  size_t i;
+  for (i = 0; i < strlen (tests); i++)
+    {
+      char test = tests[i];
+
+      switch (test)
+        {
+        case 'a':
+          do_test (test, repeat, "C", text_latin_ascii);
+          break;
+        case 'b':
+          do_test (test, repeat, "en_US.UTF-8", text_latin_ascii);
+          break;
+        case 'c':
+          do_test (test, repeat, "C", text_french_iso8859);
+          break;
+        case 'd':
+          do_test (test, repeat, "fr_FR.ISO-8859-1", text_french_iso8859);
+          break;
+        case 'e':
+          do_test (test, repeat, "en_US.UTF-8", text_french_utf8);
+          break;
+        case 'f':
+          do_test (test, repeat, "C", text_greek_iso8859);
+          break;
+        case 'g':
+          do_test (test, repeat, "el_GR.ISO-8859-7", text_greek_iso8859);
+          break;
+        case 'h':
+          do_test (test, repeat, "en_US.UTF-8", text_greek_utf8);
+          break;
+        case 'i':
+          do_test (test, repeat, "en_US.UTF-8", text_chinese_utf8);
+          break;
+        case 'j':
+          do_test (test, repeat, "zh_CN.GB18030", text_chinese_gb18030);
+          break;
+        default:
+          /* Ignore.  */
+          ;
+        }
+    }
+
+  return 0;
+}
-- 
2.34.1

>From cb55e214f9dd4f1eed6f8e488b7d0b3bd7c8505f Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 12:19:58 +0200
Subject: [PATCH 3/5] mbsnlen: Optimize.

* lib/mbsnlen.c: Include mbiterf.h instead of mbiter.h.
(mbsnlen): Use mbif_* macros instead of mbi_* macros.
* modules/mbsnlen (Depends-on): Add mbiterf. Remove mbiter.
---
 ChangeLog       |  5 +++++
 lib/mbsnlen.c   | 19 ++++++++++++-------
 modules/mbsnlen |  2 +-
 3 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 8581c23a95..a71e01cdbf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbsnlen: Optimize.
+	* lib/mbsnlen.c: Include mbiterf.h instead of mbiter.h.
+	(mbsnlen): Use mbif_* macros instead of mbi_* macros.
+	* modules/mbsnlen (Depends-on): Add mbiterf. Remove mbiter.
+
 	mbiterf: Add a benchmark.
 	* tests/bench-mbiterf.c: New file, based on tests/bench-mbiter.c.
 	* modules/mbiterf-bench-tests: New file, based on
diff --git a/lib/mbsnlen.c b/lib/mbsnlen.c
index 0a48ea93a0..ec1dfcaec3 100644
--- a/lib/mbsnlen.c
+++ b/lib/mbsnlen.c
@@ -22,7 +22,7 @@
 
 #include <stdlib.h>
 
-#include "mbiter.h"
+#include "mbiterf.h"
 
 /* Return the number of multibyte characters in the character string starting
    at STRING and ending at STRING + LEN.  */
@@ -31,12 +31,17 @@ mbsnlen (const char *string, size_t len)
 {
   if (MB_CUR_MAX > 1)
     {
-      size_t count;
-      mbi_iterator_t iter;
-
-      count = 0;
-      for (mbi_init (iter, string, len); mbi_avail (iter); mbi_advance (iter))
-        count++;
+      size_t count = 0;
+
+      const char *string_end = string + len;
+      mbif_state_t state;
+      const char *iter;
+      for (mbif_init (state), iter = string; mbif_avail (state, iter, string_end); )
+        {
+          mbchar_t cur = mbif_next (state, iter, string_end);
+          count++;
+          iter += mb_len (cur);
+        }
 
       return count;
     }
diff --git a/modules/mbsnlen b/modules/mbsnlen
index 307b6c34b2..3a3486f689 100644
--- a/modules/mbsnlen
+++ b/modules/mbsnlen
@@ -5,7 +5,7 @@ Files:
 lib/mbsnlen.c
 
 Depends-on:
-mbiter
+mbiterf
 string
 
 configure.ac:
-- 
2.34.1

>From cf7c3e9b9a8d589f2f31b92af1a9b24825359a90 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 12:21:46 +0200
Subject: [PATCH 4/5] mbmemcasecmp: Optimize.

* lib/mbmemcasecmp.c: Include mbiterf.h instead of mbiter.h.
(mbmemcasecmp): Use mbif_* macros instead of mbi_* macros.
* modules/mbmemcasecmp (Depends-on): Add mbiterf. Remove mbiter.
---
 ChangeLog            |  5 +++++
 lib/mbmemcasecmp.c   | 31 ++++++++++++++++++++-----------
 modules/mbmemcasecmp |  2 +-
 3 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index a71e01cdbf..62479a2f6d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbmemcasecmp: Optimize.
+	* lib/mbmemcasecmp.c: Include mbiterf.h instead of mbiter.h.
+	(mbmemcasecmp): Use mbif_* macros instead of mbi_* macros.
+	* modules/mbmemcasecmp (Depends-on): Add mbiterf. Remove mbiter.
+
 	mbsnlen: Optimize.
 	* lib/mbsnlen.c: Include mbiterf.h instead of mbiter.h.
 	(mbsnlen): Use mbif_* macros instead of mbi_* macros.
diff --git a/lib/mbmemcasecmp.c b/lib/mbmemcasecmp.c
index d79879866d..e53ffd99ae 100644
--- a/lib/mbmemcasecmp.c
+++ b/lib/mbmemcasecmp.c
@@ -25,7 +25,7 @@
 #include <limits.h>
 #include <stdlib.h>
 
-#include "mbiter.h"
+#include "mbiterf.h"
 
 #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
 
@@ -37,26 +37,35 @@ mbmemcasecmp (const char *s1, size_t n1, const char *s2, size_t n2)
 
   if (MB_CUR_MAX > 1)
     {
-      mbi_iterator_t iter1;
-      mbi_iterator_t iter2;
+      const char *s1_end = s1 + n1;
+      mbif_state_t state1;
+      const char *iter1;
+      mbif_init (state1);
+      iter1 = s1;
 
-      mbi_init (iter1, s1, n1);
-      mbi_init (iter2, s2, n2);
+      const char *s2_end = s2 + n2;
+      mbif_state_t state2;
+      const char *iter2;
+      mbif_init (state2);
+      iter2 = s2;
 
-      while (mbi_avail (iter1) && mbi_avail (iter2))
+      while (mbif_avail (state1, iter1, s1_end)
+             && mbif_avail (state2, iter2, s2_end))
         {
-          int cmp = mb_casecmp (mbi_cur (iter1), mbi_cur (iter2));
+          mbchar_t cur1 = mbif_next (state1, iter1, s1_end);
+          mbchar_t cur2 = mbif_next (state2, iter2, s2_end);
+          int cmp = mb_casecmp (cur1, cur2);
 
           if (cmp != 0)
             return cmp;
 
-          mbi_advance (iter1);
-          mbi_advance (iter2);
+          iter1 += mb_len (cur1);
+          iter2 += mb_len (cur2);
         }
-      if (mbi_avail (iter1))
+      if (mbif_avail (state1, iter1, s1_end))
         /* s2 terminated before s1.  */
         return 1;
-      if (mbi_avail (iter2))
+      if (mbif_avail (state2, iter2, s2_end))
         /* s1 terminated before s2.  */
         return -1;
       return 0;
diff --git a/modules/mbmemcasecmp b/modules/mbmemcasecmp
index 52db8d34ee..0034893cd0 100644
--- a/modules/mbmemcasecmp
+++ b/modules/mbmemcasecmp
@@ -6,7 +6,7 @@ lib/mbmemcasecmp.h
 lib/mbmemcasecmp.c
 
 Depends-on:
-mbiter
+mbiterf
 
 configure.ac:
 
-- 
2.34.1

>From 201b1e7bac1fbbbc9c3ea65f947c36104a7f1b18 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 12:23:12 +0200
Subject: [PATCH 5/5] trim: Optimize.

* lib/trim.c: Include mbiterf.h instead of mbiter.h.
(trim2): Use mbif_* macros instead of mbi_* macros.
* modules/trim (Depends-on): Add mbiterf. Remove mbiter.
---
 ChangeLog    |  5 +++++
 lib/trim.c   | 47 ++++++++++++++++++++++++++++++-----------------
 modules/trim |  2 +-
 3 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 62479a2f6d..af0f128722 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	trim: Optimize.
+	* lib/trim.c: Include mbiterf.h instead of mbiter.h.
+	(trim2): Use mbif_* macros instead of mbi_* macros.
+	* modules/trim (Depends-on): Add mbiterf. Remove mbiter.
+
 	mbmemcasecmp: Optimize.
 	* lib/mbmemcasecmp.c: Include mbiterf.h instead of mbiter.h.
 	(mbmemcasecmp): Use mbif_* macros instead of mbi_* macros.
diff --git a/lib/trim.c b/lib/trim.c
index d33dd13a5c..23ee5a2e2d 100644
--- a/lib/trim.c
+++ b/lib/trim.c
@@ -27,7 +27,7 @@
 #include <stdlib.h>
 
 #include "mbchar.h"
-#include "mbiter.h"
+#include "mbiterf.h"
 #include "xalloc.h"
 
 char *
@@ -42,17 +42,23 @@ trim2 (const char *s, int how)
 
   if (MB_CUR_MAX > 1)
     {
-      mbi_iterator_t i;
-
       /* Trim leading whitespaces. */
       if (how != TRIM_TRAILING)
         {
-          mbi_init (i, d, strlen (d));
+          const char *d_end = d + strlen (d);
+          mbif_state_t state;
+          char *iter;
+          for (mbif_init (state), iter = d; mbif_avail (state, iter, d_end); )
+            {
+              mbchar_t cur = mbif_next (state, iter, d_end);
 
-          for (; mbi_avail (i) && mb_isspace (mbi_cur (i)); mbi_advance (i))
-            ;
+              if (!mb_isspace (cur))
+                break;
 
-          memmove (d, mbi_cur_ptr (i), strlen (mbi_cur_ptr (i)) + 1);
+              iter += mb_len (cur);
+            }
+
+          memmove (d, iter, strlen (iter) + 1);
         }
 
       /* Trim trailing whitespaces. */
@@ -60,16 +66,23 @@ trim2 (const char *s, int how)
         {
           char *start_of_spaces = NULL;
 
-          mbi_init (i, d, strlen (d));
-
-          for (; mbi_avail (i); mbi_advance (i))
-            if (mb_isspace (mbi_cur (i)))
-              {
-                if (start_of_spaces == NULL)
-                  start_of_spaces = (char *) mbi_cur_ptr (i);
-              }
-            else
-              start_of_spaces = NULL;
+          const char *d_end = d + strlen (d);
+          mbif_state_t state;
+          char *iter;
+          for (mbif_init (state), iter = d; mbif_avail (state, iter, d_end); )
+            {
+              mbchar_t cur = mbif_next (state, iter, d_end);
+
+              if (mb_isspace (cur))
+                {
+                  if (start_of_spaces == NULL)
+                    start_of_spaces = iter;
+                }
+              else
+                start_of_spaces = NULL;
+
+              iter += mb_len (cur);
+            }
 
           if (start_of_spaces != NULL)
             *start_of_spaces = '\0';
diff --git a/modules/trim b/modules/trim
index 2de4d6fb01..90f553076a 100644
--- a/modules/trim
+++ b/modules/trim
@@ -8,7 +8,7 @@ lib/trim.c
 Depends-on:
 xalloc
 mbchar
-mbiter
+mbiterf
 memmove
 strdup
 
-- 
2.34.1

Reply via email to