This set of patches adds a new module 'mbuiterf', similar to 'mbuiter',
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):

          gcc              clang
    mbuiter mbuiterf  mbuiter mbuiterf
a    0.990   0.205     1.225   1.038
b    1.032   0.207     1.232   1.054
c    2.323   1.212     2.607   2.345
d    2.036   0.905     2.358   2.076
e    2.120   0.953     2.358   2.083
f   15.335  15.036    15.307  15.496
g   10.402   9.726    10.636  10.382
h   11.082  10.223    11.324  10.899
i    4.846   4.713     4.882   4.922
j    5.151   4.919     5.097   5.137

The speedup of the ASCII case with gcc is understandable when one looks
at the generated code: The inner loop in bench-mbuiter's do_test is

.L8:
        addq    %rax, %rbx
        movq    120(%rsp), %rax
        addq    %rax, 112(%rsp)
        movb    $0, 104(%rsp)
.L6:
        movq    112(%rsp), %r14
        cmpb    $0, (%r14)
        js      .L9
        movq    $1, 120(%rsp)
        movsbl  (%r14), %eax
        movb    $1, 128(%rsp)
        movl    %eax, 132(%rsp)
        movb    $1, 104(%rsp)
.L7:
        testl   %eax, %eax
        jne     .L8

whereas the inner loop in bench-mbuiterf's do_test is

.L15:
        testb   %al, %al
        js      .L6
        addq    %rax, %rbx
        movl    $1, %eax
        addq    %rax, %r14
        movsbq  (%r14), %rax
        testb   %al, %al
        jne     .L15

That's nearly optimal.

The module 'mbuiter' is still recommended for more complicated code
that is not performance critical, because it has a simpler idiom.
For this reason, I'm not optimizing the modules 'mbsstr', 'mbscasestr',
'regex-quote', 'propername', 'exclude': Their code is more readable
with the 'mbuiter' macros.


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

        mbsspn: Optimize.
        * lib/mbsspn.c: Include mbuiterf.h instead of mbuiter.h.
        (mbsspn): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbsspn (Depends-on): Add mbuiterf. Remove mbuiter.

        mbscspn: Optimize.
        * lib/mbscspn.c: Include mbuiterf.h instead of mbuiter.h.
        (mbscspn): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbscspn (Depends-on): Add mbuiterf. Remove mbuiter.

        mbspbrk: Optimize.
        * lib/mbspbrk.c: Include mbuiterf.h instead of mbuiter.h.
        (mbspbrk): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbspbrk (Depends-on): Add mbuiterf. Remove mbuiter.

        mbspcasecmp: Optimize.
        * lib/mbspcasecmp.c: Include mbuiterf.h instead of mbuiter.h.
        (mbspcasecmp): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbspcasecmp (Depends-on): Add mbuiterf. Remove mbuiter.

        mbsncasecmp: Optimize.
        * lib/mbsncasecmp.c: Include mbuiterf.h instead of mbuiter.h.
        (mbsncasecmp): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbsncasecmp (Depends-on): Add mbuiterf. Remove mbuiter.

        mbscasecmp: Optimize.
        * lib/mbscasecmp.c: Include mbuiterf.h instead of mbuiter.h.
        (mbscasecmp): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbscasecmp (Depends-on): Add mbuiterf. Remove mbuiter.

        mbssep: Optimize.
        * lib/mbssep.c: Include mbuiterf.h instead of mbuiter.h.
        (mbssep): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbssep (Depends-on): Add mbuiterf. Remove mbuiter.

        mbsrchr: Optimize.
        * lib/mbsrchr.c: Include mbuiterf.h instead of mbuiter.h.
        (mbsrchr): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbsrchr (Depends-on): Add mbuiterf. Remove mbuiter.

        mbschr: Optimize.
        * lib/mbschr.c: Include mbuiterf.h instead of mbuiter.h.
        (mbschr): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbschr (Depends-on): Add mbuiterf. Remove mbuiter.

        mbslen: Optimize.
        * lib/mbslen.c: Include mbuiterf.h instead of mbuiter.h.
        (mbslen): Use mbuif_* macros instead of mbui_* macros.
        * modules/mbslen (Depends-on): Add mbuiterf. Remove mbuiter.

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

        mbuiterf: New module.
        * lib/mbuiterf.h: New file, based on lib/mbuiter.h.
        * lib/mbuiterf.c: New file, based on lib/mbuiter.c.
        * modules/mbuiterf: New file, based on modules/mbuiter.

>From a271a43eb1fd93903ddf2862f2ff9a4f7d3a8751 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:24:35 +0200
Subject: [PATCH 01/12] mbuiterf: New module.

* lib/mbuiterf.h: New file, based on lib/mbuiter.h.
* lib/mbuiterf.c: New file, based on lib/mbuiter.c.
* modules/mbuiterf: New file, based on modules/mbuiter.
---
 ChangeLog        |   7 ++
 lib/mbuiterf.c   |  20 +++++
 lib/mbuiterf.h   | 212 +++++++++++++++++++++++++++++++++++++++++++++++
 modules/mbuiterf |  38 +++++++++
 4 files changed, 277 insertions(+)
 create mode 100644 lib/mbuiterf.c
 create mode 100644 lib/mbuiterf.h
 create mode 100644 modules/mbuiterf

diff --git a/ChangeLog b/ChangeLog
index a4aa3b1714..0445b2f3c9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2023-07-18  Bruno Haible  <[email protected]>
+
+	mbuiterf: New module.
+	* lib/mbuiterf.h: New file, based on lib/mbuiter.h.
+	* lib/mbuiterf.c: New file, based on lib/mbuiter.c.
+	* modules/mbuiterf: New file, based on modules/mbuiter.
+
 2023-07-18  Bruno Haible  <[email protected]>
 
 	mbiterf: Fix compiler warnings.
diff --git a/lib/mbuiterf.c b/lib/mbuiterf.c
new file mode 100644
index 0000000000..c87772a051
--- /dev/null
+++ b/lib/mbuiterf.c
@@ -0,0 +1,20 @@
+/* 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 3 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 MBUITERF_INLINE _GL_EXTERN_INLINE
+#include "mbuiterf.h"
diff --git a/lib/mbuiterf.h b/lib/mbuiterf.h
new file mode 100644
index 0000000000..e74f9e16c1
--- /dev/null
+++ b/lib/mbuiterf.h
@@ -0,0 +1,212 @@
+/* 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 3 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, without knowing its length a-priori.
+
+   With these macros, an iteration loop that looks like
+
+      char *iter;
+      for (iter = buf; *iter != '\0'; iter++)
+        {
+          do_something (*iter);
+        }
+
+   becomes
+
+      mbuif_state_t state;
+      [const] char *iter;
+      for (mbuif_init (state), iter = buf; mbuif_avail (state, iter); )
+        {
+          mbchar_t cur = mbuif_next (state, iter);
+          // 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.
+
+   Compared to mbiterf.h, the macros here don't need to know the string's
+   length a-priori.  The downside is that at each step, the look-ahead
+   that guards against overrunning the terminating '\0' is more expensive.
+   The mbuif_* macros are therefore suitable when there is a high probability
+   that only the first few multibyte characters need to be inspected.
+   Whereas the mbif_* macros are better if usually the iteration runs
+   through the entire string.
+
+   The benefit of these macros over those from mbuiter.h is that it
+   produces faster code with today's optimizing compilers (because mbuif_next
+   returns its result by value).
+
+   mbuif_state_t
+     is a type usable for variable declarations.
+
+   mbuif_init (state)
+     initializes the state.
+
+   mbuif_avail (state, iter)
+     returns true if another loop round is needed.
+
+   mbuif_next (state, iter)
+     returns the next multibyte character.
+     It asssumes that the state is initialized and that *iter != '\0'.
+
+   Here are the function prototypes of the macros.
+
+   extern void      mbuif_init (mbuif_state_t state);
+   extern bool      mbuif_avail (mbuif_state_t state, const char *iter);
+   extern mbchar_t  mbuif_next (mbuif_state_t state, const char *iter);
+ */
+
+#ifndef _MBUITERF_H
+#define _MBUITERF_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 <stdlib.h>
+#include <string.h>
+#include <uchar.h>
+#include <wchar.h>
+
+#include "mbchar.h"
+#include "strnlen1.h"
+
+_GL_INLINE_HEADER_BEGIN
+#ifndef MBUITERF_INLINE
+# define MBUITERF_INLINE _GL_INLINE
+#endif
+
+struct mbuif_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 mbuiterf_next invocation.
+                         */
+  unsigned int cur_max; /* A cache of MB_CUR_MAX.  */
+};
+
+MBUITERF_INLINE mbchar_t
+mbuiterf_next (struct mbuif_state *ps, const char *iter)
+{
+  #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, strnlen1 (iter, ps->cur_max), &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.  */
+          /* Whether to set ps->in_shift = false and reset ps->state or not is
+             not important; the string end is reached anyway.  */
+          return (mbchar_t) { .ptr = iter, .bytes = strlen (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 mbuif_state mbuif_state_t;
+#if !GNULIB_MBRTOC32_REGULAR
+#define mbuif_init(st) \
+  ((st).in_shift = false, mbszero (&(st).state), \
+   (st).cur_max = MB_CUR_MAX)
+#else
+/* Optimized: no in_shift.  */
+#define mbuif_init(st) \
+  (mbszero (&(st).state), \
+   (st).cur_max = MB_CUR_MAX)
+#endif
+#if !GNULIB_MBRTOC32_REGULAR
+#define mbuif_avail(st, iter) ((st).in_shift || (*(iter) != '\0'))
+#else
+/* Optimized: no in_shift.  */
+#define mbuif_avail(st, iter) (*(iter) != '\0')
+#endif
+#define mbuif_next(st, iter) \
+  mbuiterf_next (&(st), (iter))
+
+_GL_INLINE_HEADER_END
+
+#endif /* _MBUITERF_H */
diff --git a/modules/mbuiterf b/modules/mbuiterf
new file mode 100644
index 0000000000..b9c49de8ef
--- /dev/null
+++ b/modules/mbuiterf
@@ -0,0 +1,38 @@
+Description:
+Iterating through multibyte strings, faster.
+
+Files:
+lib/mbuiterf.h
+lib/mbuiterf.c
+m4/mbiter.m4
+m4/mbrtowc.m4
+
+Depends-on:
+extern-inline
+mbchar
+mbrtoc32
+mbsinit
+mbszero
+uchar
+stdbool
+strnlen1
+
+configure.ac:
+gl_MBITER
+
+Makefile.am:
+lib_SOURCES += mbuiterf.h mbuiterf.c
+
+Include:
+"mbuiterf.h"
+
+Link:
+$(LTLIBUNISTRING) when linking with libtool, $(LIBUNISTRING) otherwise
+$(MBRTOWC_LIB)
+$(LTLIBC32CONV) when linking with libtool, $(LIBC32CONV) otherwise
+
+License:
+LGPL
+
+Maintainer:
+all
-- 
2.34.1

>From 00b03b7a073a5503f1627f2cc085a95703949c85 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:25:43 +0200
Subject: [PATCH 02/12] mbuiterf: Add a benchmark.

* tests/bench-mbuiterf.c: New file, based on tests/bench-mbuiter.c.
* modules/mbuiterf-bench-tests: New file, based on
modules/mbuiter-bench-tests.
---
 ChangeLog                    |   5 ++
 modules/mbuiterf-bench-tests |  18 +++++
 tests/bench-mbuiterf.c       | 136 +++++++++++++++++++++++++++++++++++
 3 files changed, 159 insertions(+)
 create mode 100644 modules/mbuiterf-bench-tests
 create mode 100644 tests/bench-mbuiterf.c

diff --git a/ChangeLog b/ChangeLog
index 0445b2f3c9..6380a3cbc0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbuiterf: Add a benchmark.
+	* tests/bench-mbuiterf.c: New file, based on tests/bench-mbuiter.c.
+	* modules/mbuiterf-bench-tests: New file, based on
+	modules/mbuiter-bench-tests.
+
 	mbuiterf: New module.
 	* lib/mbuiterf.h: New file, based on lib/mbuiter.h.
 	* lib/mbuiterf.c: New file, based on lib/mbuiter.c.
diff --git a/modules/mbuiterf-bench-tests b/modules/mbuiterf-bench-tests
new file mode 100644
index 0000000000..910a4a7bae
--- /dev/null
+++ b/modules/mbuiterf-bench-tests
@@ -0,0 +1,18 @@
+Files:
+tests/bench-mbuiterf.c
+tests/bench-multibyte.h
+tests/bench.h
+
+Depends-on:
+mbrtoc32-regular
+mbuiterf
+setlocale
+striconv
+getrusage
+gettimeofday
+
+configure.ac:
+
+Makefile.am:
+noinst_PROGRAMS += bench-mbuiterf
+bench_mbuiterf_LDADD = $(LDADD) $(LIBUNISTRING) $(SETLOCALE_LIB) $(MBRTOWC_LIB) $(LIBC32CONV)
diff --git a/tests/bench-mbuiterf.c b/tests/bench-mbuiterf.c
new file mode 100644
index 0000000000..20dbfbca64
--- /dev/null
+++ b/tests/bench-mbuiterf.c
@@ -0,0 +1,136 @@
+/* Benchmarks for the mbuiterf 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 "mbuiterf.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);
+
+      int count;
+      for (count = 0; count < repeat; count++)
+        {
+          unsigned long long sum = 0;
+          mbuif_state_t state;
+          const char *iter;
+          for (mbuif_init (state), iter = text; mbuif_avail (state, iter); )
+            {
+              mbchar_t cur = mbuif_next (state, iter);
+              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 1a81b69f648002b5b8e85f1bc57d3a8995a860fd Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:27:44 +0200
Subject: [PATCH 03/12] mbslen: Optimize.

* lib/mbslen.c: Include mbuiterf.h instead of mbuiter.h.
(mbslen): Use mbuif_* macros instead of mbui_* macros.
* modules/mbslen (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog      |  5 +++++
 lib/mbslen.c   | 18 +++++++++++-------
 modules/mbslen |  2 +-
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6380a3cbc0..d1b135958c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbslen: Optimize.
+	* lib/mbslen.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbslen): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbslen (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbuiterf: Add a benchmark.
 	* tests/bench-mbuiterf.c: New file, based on tests/bench-mbuiter.c.
 	* modules/mbuiterf-bench-tests: New file, based on
diff --git a/lib/mbslen.c b/lib/mbslen.c
index 54c20be02f..18642f55e9 100644
--- a/lib/mbslen.c
+++ b/lib/mbslen.c
@@ -22,7 +22,7 @@
 
 #include <stdlib.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 /* Return the number of multibyte characters in the character string STRING.  */
 size_t
@@ -30,12 +30,16 @@ mbslen (const char *string)
 {
   if (MB_CUR_MAX > 1)
     {
-      size_t count;
-      mbui_iterator_t iter;
-
-      count = 0;
-      for (mbui_init (iter, string); mbui_avail (iter); mbui_advance (iter))
-        count++;
+      size_t count = 0;
+
+      mbuif_state_t state;
+      const char *iter;
+      for (mbuif_init (state), iter = string; mbuif_avail (state, iter); )
+        {
+          mbchar_t cur = mbuif_next (state, iter);
+          count++;
+          iter += mb_len (cur);
+        }
 
       return count;
     }
diff --git a/modules/mbslen b/modules/mbslen
index 55993aa59c..6b6c6078e5 100644
--- a/modules/mbslen
+++ b/modules/mbslen
@@ -6,7 +6,7 @@ lib/mbslen.c
 m4/mbslen.m4
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 
 configure.ac:
-- 
2.34.1

>From f0c22a20ccc90955ba0009457025c9ff34889181 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:29:14 +0200
Subject: [PATCH 04/12] mbschr: Optimize.

* lib/mbschr.c: Include mbuiterf.h instead of mbuiter.h.
(mbschr): Use mbuif_* macros instead of mbui_* macros.
* modules/mbschr (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog      |  5 +++++
 lib/mbschr.c   | 17 +++++++++--------
 modules/mbschr |  2 +-
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d1b135958c..de7744f0ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbschr: Optimize.
+	* lib/mbschr.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbschr): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbschr (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbslen: Optimize.
 	* lib/mbslen.c: Include mbuiterf.h instead of mbuiter.h.
 	(mbslen): Use mbuif_* macros instead of mbui_* macros.
diff --git a/lib/mbschr.c b/lib/mbschr.c
index 81323b4f9d..330e3f1c75 100644
--- a/lib/mbschr.c
+++ b/lib/mbschr.c
@@ -20,7 +20,7 @@
 /* Specification.  */
 #include <string.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 /* Locate the first single-byte character C in the character string STRING,
    and return a pointer to it.  Return NULL if C is not found in STRING.  */
@@ -33,17 +33,18 @@ mbschr (const char *string, int c)
          the faster unibyte loop can be used.  */
       && (unsigned char) c >= 0x30)
     {
-      mbui_iterator_t iter;
-
-      for (mbui_init (iter, string);; mbui_advance (iter))
+      mbuif_state_t state;
+      const char *iter;
+      for (mbuif_init (state), iter = string;; )
         {
-          if (!mbui_avail (iter))
+          if (!mbuif_avail (state, iter))
             goto notfound;
-          if (mb_len (mbui_cur (iter)) == 1
-              && (unsigned char) * mbui_cur_ptr (iter) == (unsigned char) c)
+          mbchar_t cur = mbuif_next (state, iter);
+          if (mb_len (cur) == 1 && (unsigned char) *iter == (unsigned char) c)
             break;
+          iter += mb_len (cur);
         }
-      return (char *) mbui_cur_ptr (iter);
+      return (char *) iter;
      notfound:
       return NULL;
     }
diff --git a/modules/mbschr b/modules/mbschr
index e3382e08b4..e99a3caf6c 100644
--- a/modules/mbschr
+++ b/modules/mbschr
@@ -5,7 +5,7 @@ Files:
 lib/mbschr.c
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 
 configure.ac:
-- 
2.34.1

>From 727a6fd3c20fc8a5f175976b3b624b8f9ed3750e Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:30:18 +0200
Subject: [PATCH 05/12] mbsrchr: Optimize.

* lib/mbsrchr.c: Include mbuiterf.h instead of mbuiter.h.
(mbsrchr): Use mbuif_* macros instead of mbui_* macros.
* modules/mbsrchr (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog       |  5 +++++
 lib/mbsrchr.c   | 15 +++++++++------
 modules/mbsrchr |  2 +-
 3 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index de7744f0ef..c0288b7ebc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbsrchr: Optimize.
+	* lib/mbsrchr.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbsrchr): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbsrchr (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbschr: Optimize.
 	* lib/mbschr.c: Include mbuiterf.h instead of mbuiter.h.
 	(mbschr): Use mbuif_* macros instead of mbui_* macros.
diff --git a/lib/mbsrchr.c b/lib/mbsrchr.c
index a00b608fc8..4c4767462c 100644
--- a/lib/mbsrchr.c
+++ b/lib/mbsrchr.c
@@ -20,7 +20,7 @@
 /* Specification.  */
 #include <string.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 /* Locate the last single-byte character C in the character string STRING,
    and return a pointer to it.  Return NULL if C is not found in STRING.  */
@@ -34,14 +34,17 @@ mbsrchr (const char *string, int c)
       && (unsigned char) c >= 0x30)
     {
       const char *result = NULL;
-      mbui_iterator_t iter;
 
-      for (mbui_init (iter, string); mbui_avail (iter); mbui_advance (iter))
+      mbuif_state_t state;
+      const char *iter;
+      for (mbuif_init (state), iter = string; mbuif_avail (state, iter); )
         {
-          if (mb_len (mbui_cur (iter)) == 1
-              && (unsigned char) * mbui_cur_ptr (iter) == (unsigned char) c)
-            result = mbui_cur_ptr (iter);
+          mbchar_t cur = mbuif_next (state, iter);
+          if (mb_len (cur) == 1 && (unsigned char) *iter == (unsigned char) c)
+            result = iter;
+          iter += mb_len (cur);
         }
+
       return (char *) result;
     }
   else
diff --git a/modules/mbsrchr b/modules/mbsrchr
index fcf5681864..56b9ed9489 100644
--- a/modules/mbsrchr
+++ b/modules/mbsrchr
@@ -5,7 +5,7 @@ Files:
 lib/mbsrchr.c
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 
 configure.ac:
-- 
2.34.1

>From 51c2f5acd64ef87f1023d9907e9c47daad624e35 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:33:08 +0200
Subject: [PATCH 06/12] mbssep: Optimize.

* lib/mbssep.c: Include mbuiterf.h instead of mbuiter.h.
(mbssep): Use mbuif_* macros instead of mbui_* macros.
* modules/mbssep (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog      |  5 +++++
 lib/mbssep.c   | 13 ++++++-------
 modules/mbssep |  2 +-
 3 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c0288b7ebc..03a2465c0b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbssep: Optimize.
+	* lib/mbssep.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbssep): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbssep (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbsrchr: Optimize.
 	* lib/mbsrchr.c: Include mbuiterf.h instead of mbuiter.h.
 	(mbsrchr): Use mbuif_* macros instead of mbui_* macros.
diff --git a/lib/mbssep.c b/lib/mbssep.c
index 6158b55562..31df5d1cef 100644
--- a/lib/mbssep.c
+++ b/lib/mbssep.c
@@ -22,7 +22,7 @@
 
 #include <stdlib.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 char *
 mbssep (char **stringp, const char *delim)
@@ -47,14 +47,13 @@ mbssep (char **stringp, const char *delim)
         }
       else
         {
-          mbui_iterator_t iter;
-
-          mbui_init (iter, ptr);
-          if (!mbui_avail (iter))
+          mbuif_state_t state;
+          mbuif_init (state);
+          if (!mbuif_avail (state, ptr))
             abort ();
-          mbui_advance (iter);
+          mbchar_t cur = mbuif_next (state, ptr);
           *ptr = '\0';
-          *stringp = (char *) mbui_cur_ptr (iter);
+          *stringp = ptr + mb_len (cur);
           return start;
         }
     }
diff --git a/modules/mbssep b/modules/mbssep
index a79538e21e..6672d64641 100644
--- a/modules/mbssep
+++ b/modules/mbssep
@@ -5,7 +5,7 @@ Files:
 lib/mbssep.c
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 mbspbrk
 strsep
-- 
2.34.1

>From 1ed13c54d8e78b81da512b3bd37799557d6bd65d Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:35:10 +0200
Subject: [PATCH 07/12] mbscasecmp: Optimize.

* lib/mbscasecmp.c: Include mbuiterf.h instead of mbuiter.h.
(mbscasecmp): Use mbuif_* macros instead of mbui_* macros.
* modules/mbscasecmp (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog          |  5 +++++
 lib/mbscasecmp.c   | 28 +++++++++++++++++-----------
 modules/mbscasecmp |  2 +-
 3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 03a2465c0b..92d747f4e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbscasecmp: Optimize.
+	* lib/mbscasecmp.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbscasecmp): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbscasecmp (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbssep: Optimize.
 	* lib/mbssep.c: Include mbuiterf.h instead of mbuiter.h.
 	(mbssep): Use mbuif_* macros instead of mbui_* macros.
diff --git a/lib/mbscasecmp.c b/lib/mbscasecmp.c
index 03292a5cd7..58c0c7c56e 100644
--- a/lib/mbscasecmp.c
+++ b/lib/mbscasecmp.c
@@ -24,7 +24,7 @@
 #include <ctype.h>
 #include <limits.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
 
@@ -44,26 +44,32 @@ mbscasecmp (const char *s1, const char *s2)
      most often already in the very few first characters.  */
   if (MB_CUR_MAX > 1)
     {
-      mbui_iterator_t iter1;
-      mbui_iterator_t iter2;
+      mbuif_state_t state1;
+      const char *iter1;
+      mbuif_init (state1);
+      iter1 = s1;
 
-      mbui_init (iter1, s1);
-      mbui_init (iter2, s2);
+      mbuif_state_t state2;
+      const char *iter2;
+      mbuif_init (state2);
+      iter2 = s2;
 
-      while (mbui_avail (iter1) && mbui_avail (iter2))
+      while (mbuif_avail (state1, iter1) && mbuif_avail (state2, iter2))
         {
-          int cmp = mb_casecmp (mbui_cur (iter1), mbui_cur (iter2));
+          mbchar_t cur1 = mbuif_next (state1, iter1);
+          mbchar_t cur2 = mbuif_next (state2, iter2);
+          int cmp = mb_casecmp (cur1, cur2);
 
           if (cmp != 0)
             return cmp;
 
-          mbui_advance (iter1);
-          mbui_advance (iter2);
+          iter1 += mb_len (cur1);
+          iter2 += mb_len (cur2);
         }
-      if (mbui_avail (iter1))
+      if (mbuif_avail (state1, iter1))
         /* s2 terminated before s1.  */
         return 1;
-      if (mbui_avail (iter2))
+      if (mbuif_avail (state2, iter2))
         /* s1 terminated before s2.  */
         return -1;
       return 0;
diff --git a/modules/mbscasecmp b/modules/mbscasecmp
index d0dcdf6d29..234b7bc7a3 100644
--- a/modules/mbscasecmp
+++ b/modules/mbscasecmp
@@ -5,7 +5,7 @@ Files:
 lib/mbscasecmp.c
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 
 configure.ac:
-- 
2.34.1

>From d2865eb45ebe658c15019e464bc18abe3b6ecc07 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:36:00 +0200
Subject: [PATCH 08/12] mbsncasecmp: Optimize.

* lib/mbsncasecmp.c: Include mbuiterf.h instead of mbuiter.h.
(mbsncasecmp): Use mbuif_* macros instead of mbui_* macros.
* modules/mbsncasecmp (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog           |  5 +++++
 lib/mbsncasecmp.c   | 28 +++++++++++++++++-----------
 modules/mbsncasecmp |  2 +-
 3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 92d747f4e7..f7a201f46e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbsncasecmp: Optimize.
+	* lib/mbsncasecmp.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbsncasecmp): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbsncasecmp (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbscasecmp: Optimize.
 	* lib/mbscasecmp.c: Include mbuiterf.h instead of mbuiter.h.
 	(mbscasecmp): Use mbuif_* macros instead of mbui_* macros.
diff --git a/lib/mbsncasecmp.c b/lib/mbsncasecmp.c
index b2dcb81417..d7b71ad188 100644
--- a/lib/mbsncasecmp.c
+++ b/lib/mbsncasecmp.c
@@ -24,7 +24,7 @@
 #include <ctype.h>
 #include <limits.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
 
@@ -46,15 +46,21 @@ mbsncasecmp (const char *s1, const char *s2, size_t n)
      most often already in the very few first characters.  */
   if (MB_CUR_MAX > 1)
     {
-      mbui_iterator_t iter1;
-      mbui_iterator_t iter2;
+      mbuif_state_t state1;
+      const char *iter1;
+      mbuif_init (state1);
+      iter1 = s1;
 
-      mbui_init (iter1, s1);
-      mbui_init (iter2, s2);
+      mbuif_state_t state2;
+      const char *iter2;
+      mbuif_init (state2);
+      iter2 = s2;
 
-      while (mbui_avail (iter1) && mbui_avail (iter2))
+      while (mbuif_avail (state1, iter1) && mbuif_avail (state2, iter2))
         {
-          int cmp = mb_casecmp (mbui_cur (iter1), mbui_cur (iter2));
+          mbchar_t cur1 = mbuif_next (state1, iter1);
+          mbchar_t cur2 = mbuif_next (state2, iter2);
+          int cmp = mb_casecmp (cur1, cur2);
 
           if (cmp != 0)
             return cmp;
@@ -62,13 +68,13 @@ mbsncasecmp (const char *s1, const char *s2, size_t n)
           if (--n == 0)
             return 0;
 
-          mbui_advance (iter1);
-          mbui_advance (iter2);
+          iter1 += mb_len (cur1);
+          iter2 += mb_len (cur2);
         }
-      if (mbui_avail (iter1))
+      if (mbuif_avail (state1, iter1))
         /* s2 terminated before s1 and n.  */
         return 1;
-      if (mbui_avail (iter2))
+      if (mbuif_avail (state2, iter2))
         /* s1 terminated before s2 and n.  */
         return -1;
       return 0;
diff --git a/modules/mbsncasecmp b/modules/mbsncasecmp
index 6f4300d3b7..9d6e2af5ce 100644
--- a/modules/mbsncasecmp
+++ b/modules/mbsncasecmp
@@ -5,7 +5,7 @@ Files:
 lib/mbsncasecmp.c
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 
 configure.ac:
-- 
2.34.1

>From 056967bada64e9e4f79b8ad3aac1ce6db823b541 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:40:11 +0200
Subject: [PATCH 09/12] mbspcasecmp: Optimize.

* lib/mbspcasecmp.c: Include mbuiterf.h instead of mbuiter.h.
(mbspcasecmp): Use mbuif_* macros instead of mbui_* macros.
* modules/mbspcasecmp (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog           |  5 +++++
 lib/mbspcasecmp.c   | 28 +++++++++++++++++-----------
 modules/mbspcasecmp |  2 +-
 3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f7a201f46e..ec0fa50d61 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbspcasecmp: Optimize.
+	* lib/mbspcasecmp.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbspcasecmp): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbspcasecmp (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbsncasecmp: Optimize.
 	* lib/mbsncasecmp.c: Include mbuiterf.h instead of mbuiter.h.
 	(mbsncasecmp): Use mbuif_* macros instead of mbui_* macros.
diff --git a/lib/mbspcasecmp.c b/lib/mbspcasecmp.c
index 403d4ebb79..b7c3d85c96 100644
--- a/lib/mbspcasecmp.c
+++ b/lib/mbspcasecmp.c
@@ -22,7 +22,7 @@
 
 #include <ctype.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
 
@@ -46,25 +46,31 @@ mbspcasecmp (const char *string, const char *prefix)
      most often already in the very few first characters.  */
   if (MB_CUR_MAX > 1)
     {
-      mbui_iterator_t iter1;
-      mbui_iterator_t iter2;
+      mbuif_state_t state1;
+      const char *iter1;
+      mbuif_init (state1);
+      iter1 = string;
 
-      mbui_init (iter1, string);
-      mbui_init (iter2, prefix);
+      mbuif_state_t state2;
+      const char *iter2;
+      mbuif_init (state2);
+      iter2 = prefix;
 
-      while (mbui_avail (iter1) && mbui_avail (iter2))
+      while (mbuif_avail (state1, iter1) && mbuif_avail (state2, iter2))
         {
-          int cmp = mb_casecmp (mbui_cur (iter1), mbui_cur (iter2));
+          mbchar_t cur1 = mbuif_next (state1, iter1);
+          mbchar_t cur2 = mbuif_next (state2, iter2);
+          int cmp = mb_casecmp (cur1, cur2);
 
           if (cmp != 0)
             return NULL;
 
-          mbui_advance (iter1);
-          mbui_advance (iter2);
+          iter1 += mb_len (cur1);
+          iter2 += mb_len (cur2);
         }
-      if (!mbui_avail (iter2))
+      if (!mbuif_avail (state2, iter2))
         /* PREFIX equals STRING or is terminated before STRING.  */
-        return (char *) mbui_cur_ptr (iter1);
+        return (char *) iter1;
       else
         /* STRING terminated before PREFIX.  */
         return NULL;
diff --git a/modules/mbspcasecmp b/modules/mbspcasecmp
index 32f95024f8..7f2b463aaa 100644
--- a/modules/mbspcasecmp
+++ b/modules/mbspcasecmp
@@ -5,7 +5,7 @@ Files:
 lib/mbspcasecmp.c
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 
 configure.ac:
-- 
2.34.1

>From 8d9d6ad81916045d199acf1cd9ddc107ffd87544 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:43:38 +0200
Subject: [PATCH 10/12] mbspbrk: Optimize.

* lib/mbspbrk.c: Include mbuiterf.h instead of mbuiter.h.
(mbspbrk): Use mbuif_* macros instead of mbui_* macros.
* modules/mbspbrk (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog       |  5 +++++
 lib/mbspbrk.c   | 33 +++++++++++++++++++--------------
 modules/mbspbrk |  2 +-
 3 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ec0fa50d61..31ab6508b0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbspbrk: Optimize.
+	* lib/mbspbrk.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbspbrk): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbspbrk (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbspcasecmp: Optimize.
 	* lib/mbspcasecmp.c: Include mbuiterf.h instead of mbuiter.h.
 	(mbspcasecmp): Use mbuif_* macros instead of mbui_* macros.
diff --git a/lib/mbspbrk.c b/lib/mbspbrk.c
index 6132ec1489..9482eb00cb 100644
--- a/lib/mbspbrk.c
+++ b/lib/mbspbrk.c
@@ -20,7 +20,7 @@
 /* Specification.  */
 #include <string.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 /* Find the first occurrence in the character string STRING of any character
    in the character string ACCEPT.  Return the pointer to it, or NULL if none
@@ -36,25 +36,30 @@ mbspbrk (const char *string, const char *accept)
   /* General case.  */
   if (MB_CUR_MAX > 1)
     {
-      mbui_iterator_t iter;
-
-      for (mbui_init (iter, string); mbui_avail (iter); mbui_advance (iter))
+      mbuif_state_t state;
+      const char *iter;
+      for (mbuif_init (state), iter = string; mbuif_avail (state, iter); )
         {
-          if (mb_len (mbui_cur (iter)) == 1)
+          mbchar_t cur = mbuif_next (state, iter);
+          if (mb_len (cur) == 1)
             {
-              if (mbschr (accept, * mbui_cur_ptr (iter)))
-                return (char *) mbui_cur_ptr (iter);
+              if (mbschr (accept, *iter))
+                return (char *) iter;
             }
           else
             {
-              mbui_iterator_t aiter;
-
-              for (mbui_init (aiter, accept);
-                   mbui_avail (aiter);
-                   mbui_advance (aiter))
-                if (mb_equal (mbui_cur (aiter), mbui_cur (iter)))
-                  return (char *) mbui_cur_ptr (iter);
+              mbuif_state_t astate;
+              const char *aiter;
+              for (mbuif_init (astate), aiter = accept;
+                   mbuif_avail (astate, aiter); )
+                {
+                  mbchar_t acur = mbuif_next (astate, aiter);
+                  if (mb_equal (acur, cur))
+                    return (char *) iter;
+                  aiter += mb_len (acur);
+                }
             }
+          iter += mb_len (cur);
         }
       return NULL;
     }
diff --git a/modules/mbspbrk b/modules/mbspbrk
index 2841721312..158f55caa8 100644
--- a/modules/mbspbrk
+++ b/modules/mbspbrk
@@ -5,7 +5,7 @@ Files:
 lib/mbspbrk.c
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 mbschr
 strpbrk
-- 
2.34.1

>From eaa7397e70adeafce4afff9269ad5c438a584e2c Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:44:39 +0200
Subject: [PATCH 11/12] mbscspn: Optimize.

* lib/mbscspn.c: Include mbuiterf.h instead of mbuiter.h.
(mbscspn): Use mbuif_* macros instead of mbui_* macros.
* modules/mbscspn (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog       |  5 +++++
 lib/mbscspn.c   | 33 +++++++++++++++++++--------------
 modules/mbscspn |  2 +-
 3 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 31ab6508b0..daf6903642 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbscspn: Optimize.
+	* lib/mbscspn.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbscspn): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbscspn (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbspbrk: Optimize.
 	* lib/mbspbrk.c: Include mbuiterf.h instead of mbuiter.h.
 	(mbspbrk): Use mbuif_* macros instead of mbui_* macros.
diff --git a/lib/mbscspn.c b/lib/mbscspn.c
index 9cb0f451ba..f67a557f4b 100644
--- a/lib/mbscspn.c
+++ b/lib/mbscspn.c
@@ -20,7 +20,7 @@
 /* Specification.  */
 #include <string.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 /* Find the first occurrence in the character string STRING of any character
    in the character string ACCEPT.  Return the number of bytes from the
@@ -40,28 +40,33 @@ mbscspn (const char *string, const char *accept)
   /* General case.  */
   if (MB_CUR_MAX > 1)
     {
-      mbui_iterator_t iter;
-
-      for (mbui_init (iter, string); mbui_avail (iter); mbui_advance (iter))
+      mbuif_state_t state;
+      const char *iter;
+      for (mbuif_init (state), iter = string; mbuif_avail (state, iter); )
         {
-          if (mb_len (mbui_cur (iter)) == 1)
+          mbchar_t cur = mbuif_next (state, iter);
+          if (mb_len (cur) == 1)
             {
-              if (mbschr (accept, * mbui_cur_ptr (iter)))
+              if (mbschr (accept, *iter))
                 goto found;
             }
           else
             {
-              mbui_iterator_t aiter;
-
-              for (mbui_init (aiter, accept);
-                   mbui_avail (aiter);
-                   mbui_advance (aiter))
-                if (mb_equal (mbui_cur (aiter), mbui_cur (iter)))
-                  goto found;
+              mbuif_state_t astate;
+              const char *aiter;
+              for (mbuif_init (astate), aiter = accept;
+                   mbuif_avail (astate, aiter); )
+                {
+                  mbchar_t acur = mbuif_next (astate, aiter);
+                  if (mb_equal (acur, cur))
+                    goto found;
+                  aiter += mb_len (acur);
+                }
             }
+          iter += mb_len (cur);
         }
      found:
-      return mbui_cur_ptr (iter) - string;
+      return iter - string;
     }
   else
     return strcspn (string, accept);
diff --git a/modules/mbscspn b/modules/mbscspn
index 76f5748f12..c730f907a7 100644
--- a/modules/mbscspn
+++ b/modules/mbscspn
@@ -5,7 +5,7 @@ Files:
 lib/mbscspn.c
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 mbschr
 strcspn
-- 
2.34.1

>From 3c76b58750a5e5220484f1376eb087b97a2a4015 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 18 Jul 2023 13:46:29 +0200
Subject: [PATCH 12/12] mbsspn: Optimize.

* lib/mbsspn.c: Include mbuiterf.h instead of mbuiter.h.
(mbsspn): Use mbuif_* macros instead of mbui_* macros.
* modules/mbsspn (Depends-on): Add mbuiterf. Remove mbuiter.
---
 ChangeLog      |  5 +++++
 lib/mbsspn.c   | 45 ++++++++++++++++++++++++++-------------------
 modules/mbsspn |  2 +-
 3 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index daf6903642..2b7028c0b0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-07-18  Bruno Haible  <[email protected]>
 
+	mbsspn: Optimize.
+	* lib/mbsspn.c: Include mbuiterf.h instead of mbuiter.h.
+	(mbsspn): Use mbuif_* macros instead of mbui_* macros.
+	* modules/mbsspn (Depends-on): Add mbuiterf. Remove mbuiter.
+
 	mbscspn: Optimize.
 	* lib/mbscspn.c: Include mbuiterf.h instead of mbuiter.h.
 	(mbscspn): Use mbuif_* macros instead of mbui_* macros.
diff --git a/lib/mbsspn.c b/lib/mbsspn.c
index ee41181f7d..5e3832b72c 100644
--- a/lib/mbsspn.c
+++ b/lib/mbsspn.c
@@ -20,7 +20,7 @@
 /* Specification.  */
 #include <string.h>
 
-#include "mbuiter.h"
+#include "mbuiterf.h"
 
 /* Find the first occurrence in the character string STRING of any character
    not in the character string REJECT.  Return the number of bytes from the
@@ -38,13 +38,16 @@ mbsspn (const char *string, const char *reject)
 
       if (MB_CUR_MAX > 1)
         {
-          mbui_iterator_t iter;
-
-          for (mbui_init (iter, string); mbui_avail (iter); mbui_advance (iter))
-            if (!(mb_len (mbui_cur (iter)) == 1
-                  && (unsigned char) * mbui_cur_ptr (iter) == uc))
-              break;
-          return mbui_cur_ptr (iter) - string;
+          mbuif_state_t state;
+          const char *iter;
+          for (mbuif_init (state), iter = string; mbuif_avail (state, iter); )
+            {
+              mbchar_t cur = mbuif_next (state, iter);
+              if (!(mb_len (cur) == 1 && (unsigned char) *iter == uc))
+                break;
+              iter += mb_len (cur);
+            }
+          return iter - string;
         }
       else
         {
@@ -59,30 +62,34 @@ mbsspn (const char *string, const char *reject)
   /* General case.  */
   if (MB_CUR_MAX > 1)
     {
-      mbui_iterator_t iter;
-
-      for (mbui_init (iter, string); mbui_avail (iter); mbui_advance (iter))
+      mbuif_state_t state;
+      const char *iter;
+      for (mbuif_init (state), iter = string; mbuif_avail (state, iter); )
         {
-          if (mb_len (mbui_cur (iter)) == 1)
+          mbchar_t cur = mbuif_next (state, iter);
+          if (mb_len (cur) == 1)
             {
-              if (mbschr (reject, * mbui_cur_ptr (iter)) == NULL)
+              if (mbschr (reject, *iter) == NULL)
                 goto found;
             }
           else
             {
-              mbui_iterator_t aiter;
-
-              for (mbui_init (aiter, reject);; mbui_advance (aiter))
+              mbuif_state_t astate;
+              const char *aiter;
+              for (mbuif_init (astate), aiter = reject; ; )
                 {
-                  if (!mbui_avail (aiter))
+                  if (!mbuif_avail (astate, aiter))
                     goto found;
-                  if (mb_equal (mbui_cur (aiter), mbui_cur (iter)))
+                  mbchar_t acur = mbuif_next (astate, aiter);
+                  if (mb_equal (acur, cur))
                     break;
+                  aiter += mb_len (acur);
                 }
             }
+          iter += mb_len (cur);
         }
      found:
-      return mbui_cur_ptr (iter) - string;
+      return iter - string;
     }
   else
     return strspn (string, reject);
diff --git a/modules/mbsspn b/modules/mbsspn
index 5cc407299e..25cfd3f59f 100644
--- a/modules/mbsspn
+++ b/modules/mbsspn
@@ -5,7 +5,7 @@ Files:
 lib/mbsspn.c
 
 Depends-on:
-mbuiter
+mbuiterf
 string
 mbschr
 
-- 
2.34.1

Reply via email to