This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit f45a02c9382a7f8581cae51a650433eb12a5ea72
Author: Justin Hammond <[email protected]>
AuthorDate: Sat Aug 15 16:20:30 2026 +0800

    testing/libc/arch_libc: Test memccpy and stpncpy.
    
    Neither is covered here, and both are overridable, so a machine or libc
    implementation of either goes in unmeasured and unchecked.
    
    memccpy is checked with the search character present, where the copy
    stops just past it and the result points there, and absent, where the
    whole length is copied and the result is NULL.  stpncpy is checked
    against every capacity from zero to four past the length, for the
    content, the zero padding beyond the terminator, and the returned
    pointer, which is the terminator when the string fits and one past the
    end when it does not.
    
    Both sweep all sixty four source and destination alignment pairs, and
    both are added to the benchmark, which now covers nineteen functions.
    
    Assisted-by: Claude:claude-opus-5
    Signed-off-by: Justin Hammond <[email protected]>
---
 testing/libc/arch_libc/Kconfig               |   8 ++
 testing/libc/arch_libc/arch_libc_bench.c     |  10 ++
 testing/libc/arch_libc/arch_libc_test_main.c | 189 +++++++++++++++++++++++++++
 3 files changed, 207 insertions(+)

diff --git a/testing/libc/arch_libc/Kconfig b/testing/libc/arch_libc/Kconfig
index fec4ba9c1..b90019a7f 100644
--- a/testing/libc/arch_libc/Kconfig
+++ b/testing/libc/arch_libc/Kconfig
@@ -43,6 +43,14 @@ config TESTING_ARCH_LIBC_STRCPY
        bool "test strcpy"
        default y
 
+config TESTING_ARCH_LIBC_MEMCCPY
+       bool "test memccpy"
+       default y
+
+config TESTING_ARCH_LIBC_STPNCPY
+       bool "test stpncpy"
+       default y
+
 config TESTING_ARCH_LIBC_STRLCPY
        bool "test strlcpy"
        default y
diff --git a/testing/libc/arch_libc/arch_libc_bench.c 
b/testing/libc/arch_libc/arch_libc_bench.c
index d73fd48f9..af5bb4dd9 100644
--- a/testing/libc/arch_libc/arch_libc_bench.c
+++ b/testing/libc/arch_libc/arch_libc_bench.c
@@ -92,6 +92,8 @@
 #define OP_STPCPY    14
 #define OP_STRNCPY   15
 #define OP_STRCAT    16
+#define OP_MEMCCPY   17
+#define OP_STPNCPY   18
 
 /****************************************************************************
  * Private Types
@@ -134,6 +136,8 @@ static const struct bench_op_s g_ops[] =
   {"stpcpy",  OP_STPCPY,  true,  true},
   {"strncpy", OP_STRNCPY, true,  true},
   {"strcat",  OP_STRCAT,  true,  true},
+  {"memccpy", OP_MEMCCPY, true,  false},
+  {"stpncpy", OP_STPNCPY, true,  true},
 };
 
 static const size_t g_sizes[] =
@@ -324,6 +328,12 @@ static void bench_one(FAR const struct bench_op_s *o, 
size_t n,
               case OP_STRNCPY:
                 strncpy(d, s, n);
                 break;
+              case OP_MEMCCPY:
+                g_sink += (uintptr_t)memccpy(d, s, '~', n);
+                break;
+              case OP_STPNCPY:
+                g_sink += (uintptr_t)stpncpy(d, s, n);
+                break;
               case OP_STRCAT:
 
                 /* Appending to what the last turn appended would grow the
diff --git a/testing/libc/arch_libc/arch_libc_test_main.c 
b/testing/libc/arch_libc/arch_libc_test_main.c
index 0f14f967c..1382bd62e 100644
--- a/testing/libc/arch_libc/arch_libc_test_main.c
+++ b/testing/libc/arch_libc/arch_libc_test_main.c
@@ -792,6 +792,183 @@ static void speed_strlcpy(void)
 #endif
 #endif
 
+/****************************************************************************
+ * Name: test_memccpy
+ ****************************************************************************/
+
+#ifdef CONFIG_TESTING_ARCH_LIBC_MEMCCPY
+static int test_memccpy(void)
+{
+  int size;
+  int fail = 0;
+  int ai;
+  int i;
+
+  printf("Testing memccpy...\n");
+
+  for (ai = 0; ai < 64; ai++)
+    {
+      int da = ai / 8;
+      int sa = ai % 8;
+
+      for (size = 1; size <= 64; size++)
+        {
+          FAR char *p;
+          int at = size / 2;
+
+          fill_pattern(g_buf1 + sa, size);
+          g_buf1[sa + at] = '#';
+          memset(g_buf2, 0x5a, sizeof(g_buf2));
+
+          /* The character is present, so the copy stops just past it */
+
+          p = memccpy(g_buf2 + da, g_buf1 + sa, '#', size);
+          if (p != g_buf2 + da + at + 1 ||
+              memcmp(g_buf2 + da, g_buf1 + sa, at + 1) != 0 ||
+              (unsigned char)g_buf2[da + at + 1] != 0x5a)
+            {
+              printf("  FAIL found: sa=%d da=%d size=%d\n", sa, da, size);
+              fail++;
+            }
+
+          /* The character is absent, so the whole length is copied */
+
+          for (i = 0; i < size; i++)
+            {
+              g_buf1[sa + i] = 'A' + (i % 26);
+            }
+
+          memset(g_buf2, 0x5a, sizeof(g_buf2));
+          p = memccpy(g_buf2 + da, g_buf1 + sa, '#', size);
+          if (p != NULL || memcmp(g_buf2 + da, g_buf1 + sa, size) != 0 ||
+              (unsigned char)g_buf2[da + size] != 0x5a)
+            {
+              printf("  FAIL absent: sa=%d da=%d size=%d\n", sa, da, size);
+              fail++;
+            }
+        }
+    }
+
+  printf("memccpy: %s\n", fail ? "FAILED" : "PASSED");
+  return fail;
+}
+
+#ifdef ARCH_LIBC_HAVE_PERF
+static void speed_memccpy(void)
+{
+  clock_t start;
+  clock_t end;
+  int i;
+
+  fill_pattern(g_buf1, 128);
+  start = perf_gettime();
+  for (i = 0; i < TEST_REPEAT; i++)
+    {
+      g_sink = (uintptr_t)memccpy(g_buf2, g_buf1, '#', 128);
+    }
+
+  end = perf_gettime();
+  printf("memccpy(128) avg cycles: %ju\n",
+         (uintmax_t)(end - start) / TEST_REPEAT);
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: test_stpncpy
+ ****************************************************************************/
+
+#ifdef CONFIG_TESTING_ARCH_LIBC_STPNCPY
+static int test_stpncpy(void)
+{
+  int size;
+  int fail = 0;
+  int ai;
+  int cap;
+  int i;
+
+  printf("Testing stpncpy...\n");
+
+  for (ai = 0; ai < 64; ai++)
+    {
+      int da = ai / 8;
+      int sa = ai % 8;
+
+      for (size = 1; size <= 48; size++)
+        {
+          fill_pattern(g_buf1 + sa, size);
+          g_buf1[sa + size] = '\0';
+
+          for (cap = 0; cap <= size + 4; cap++)
+            {
+              FAR char *p;
+              FAR char *want;
+
+              memset(g_buf2, 0x5a, sizeof(g_buf2));
+              p = stpncpy(g_buf2 + da, g_buf1 + sa, cap);
+
+              /* Up to the terminator is copied, the rest is padded, and
+               * the result points at the terminator or one past the end.
+               */
+
+              want = size < cap ? g_buf2 + da + size : g_buf2 + da + cap;
+              if (p != want)
+                {
+                  printf("  FAIL ret: sa=%d da=%d size=%d cap=%d\n",
+                         sa, da, size, cap);
+                  fail++;
+                  continue;
+                }
+
+              for (i = 0; i < cap; i++)
+                {
+                  char expect = i < size ? g_buf1[sa + i] : '\0';
+
+                  if (g_buf2[da + i] != expect)
+                    {
+                      printf("  FAIL content: sa=%d da=%d size=%d cap=%d\n",
+                             sa, da, size, cap);
+                      fail++;
+                      break;
+                    }
+                }
+
+              if ((unsigned char)g_buf2[da + cap] != 0x5a)
+                {
+                  printf("  FAIL overrun: sa=%d da=%d size=%d cap=%d\n",
+                         sa, da, size, cap);
+                  fail++;
+                }
+            }
+        }
+    }
+
+  printf("stpncpy: %s\n", fail ? "FAILED" : "PASSED");
+  return fail;
+}
+
+#ifdef ARCH_LIBC_HAVE_PERF
+static void speed_stpncpy(void)
+{
+  clock_t start;
+  clock_t end;
+  int i;
+
+  fill_pattern(g_buf1, 128);
+  g_buf1[128] = '\0';
+  start = perf_gettime();
+  for (i = 0; i < TEST_REPEAT; i++)
+    {
+      g_sink = (uintptr_t)stpncpy(g_buf2, g_buf1, 128);
+    }
+
+  end = perf_gettime();
+  printf("stpncpy(128) avg cycles: %ju\n",
+         (uintmax_t)(end - start) / TEST_REPEAT);
+}
+#endif
+#endif
+
 /****************************************************************************
  * Name: test_strchr
  ****************************************************************************/
@@ -1545,6 +1722,18 @@ int main(int argc, FAR char *argv[])
   fail += test_strcpy();
   speed_strcpy();
 #endif
+#ifdef CONFIG_TESTING_ARCH_LIBC_MEMCCPY
+  fail += test_memccpy();
+#  ifdef ARCH_LIBC_HAVE_PERF
+  speed_memccpy();
+#  endif
+#endif
+#ifdef CONFIG_TESTING_ARCH_LIBC_STPNCPY
+  fail += test_stpncpy();
+#  ifdef ARCH_LIBC_HAVE_PERF
+  speed_stpncpy();
+#  endif
+#endif
 #ifdef CONFIG_TESTING_ARCH_LIBC_STRLCPY
   fail += test_strlcpy();
 #  ifdef ARCH_LIBC_HAVE_PERF

Reply via email to