[libc-commits] [libc] db8a88f - [libc] add memccpy and mempcpy
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Thu Oct 14 16:38:06 PDT 2021
Author: Michael Jones
Date: 2021-10-14T16:38:00-07:00
New Revision: db8a88fef87e921c331c71503f73a76337c121c9
URL: https://github.com/llvm/llvm-project/commit/db8a88fef87e921c331c71503f73a76337c121c9
DIFF: https://github.com/llvm/llvm-project/commit/db8a88fef87e921c331c71503f73a76337c121c9.diff
LOG: [libc] add memccpy and mempcpy
Add an implementation for memccpy and mempcpy. These functions are
posix extensions for the moment.
Reviewed By: lntue
Differential Revision: https://reviews.llvm.org/D111762
Added:
libc/src/string/memccpy.cpp
libc/src/string/memccpy.h
libc/src/string/mempcpy.cpp
libc/src/string/mempcpy.h
libc/test/src/string/memccpy_test.cpp
libc/test/src/string/mempcpy_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/spec/posix.td
libc/src/string/CMakeLists.txt
libc/test/src/string/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 56ae31d1550fb..1f40545cde3f1 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -23,10 +23,12 @@ set(TARGET_LIBC_ENTRYPOINTS
# string.h entrypoints
libc.src.string.bcmp
libc.src.string.bzero
+ libc.src.string.memccpy
libc.src.string.memchr
libc.src.string.memcmp
libc.src.string.memcpy
libc.src.string.memmove
+ libc.src.string.mempcpy
libc.src.string.memrchr
libc.src.string.memset
libc.src.string.strcat
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 32f6ef5844b14..45d12fa239922 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -220,6 +220,21 @@ def POSIX : StandardSpec<"POSIX"> {
],
[], // Enumerations
[
+ FunctionSpec<
+ "memccpy",
+ RetValSpec<VoidPtr>,
+ [ArgSpec<VoidRestrictedPtr>,
+ ArgSpec<ConstVoidRestrictedPtr>,
+ ArgSpec<IntType>,
+ ArgSpec<SizeTType>]
+ >,
+ FunctionSpec<
+ "mempcpy",
+ RetValSpec<VoidPtr>,
+ [ArgSpec<VoidRestrictedPtr>,
+ ArgSpec<ConstVoidRestrictedPtr>,
+ ArgSpec<SizeTType>]
+ >,
FunctionSpec<
"strnlen",
RetValSpec<SizeTType>,
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index e5d6ebc2c1054..05edd49900217 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -8,6 +8,25 @@ add_header_library(
libc.utils.CPP.standalone_cpp
)
+add_entrypoint_object(
+ memccpy
+ SRCS
+ memccpy.cpp
+ HDRS
+ memccpy.h
+)
+
+
+add_entrypoint_object(
+ mempcpy
+ SRCS
+ mempcpy.cpp
+ HDRS
+ mempcpy.h
+ DEPENDS
+ libc.src.string.memcpy
+)
+
add_entrypoint_object(
memchr
SRCS
diff --git a/libc/src/string/memccpy.cpp b/libc/src/string/memccpy.cpp
new file mode 100644
index 0000000000000..782beee947636
--- /dev/null
+++ b/libc/src/string/memccpy.cpp
@@ -0,0 +1,35 @@
+//===-- Implementation of memccpy ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/memccpy.h"
+
+#include "src/__support/common.h"
+#include <stddef.h> // For size_t.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(void *, memccpy,
+ (void *__restrict dest, const void *__restrict src, int c,
+ size_t count)) {
+ unsigned char end = static_cast<unsigned char>(c);
+ const unsigned char *ucSrc = static_cast<const unsigned char *>(src);
+ unsigned char *ucDest = static_cast<unsigned char *>(dest);
+ size_t i = 0;
+ // Copy up until end is found.
+ for (; i < count && ucSrc[i] != end; ++i)
+ ucDest[i] = ucSrc[i];
+ // if i < count, then end must have been found, so copy end into dest and
+ // return the byte after.
+ if (i < count) {
+ ucDest[i] = ucSrc[i];
+ return ucDest + i + 1;
+ }
+ return nullptr;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/string/memccpy.h b/libc/src/string/memccpy.h
new file mode 100644
index 0000000000000..38a80b1d69115
--- /dev/null
+++ b/libc/src/string/memccpy.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for memccpy -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_MEMCCPY_H
+#define LLVM_LIBC_SRC_STRING_MEMCCPY_H
+
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+void *memccpy(void *__restrict dest, const void *__restrict src, int c,
+ size_t count);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_MEMCCPY_H
diff --git a/libc/src/string/mempcpy.cpp b/libc/src/string/mempcpy.cpp
new file mode 100644
index 0000000000000..08b2b80efe12e
--- /dev/null
+++ b/libc/src/string/mempcpy.cpp
@@ -0,0 +1,26 @@
+//===-- Implementation of mempcpy ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/mempcpy.h"
+#include "src/string/memcpy.h"
+
+#include "src/__support/common.h"
+#include <stddef.h> // For size_t.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(void *, mempcpy,
+ (void *__restrict dest, const void *__restrict src,
+ size_t count)) {
+ void *result = __llvm_libc::memcpy(dest, src, count);
+ return result == nullptr
+ ? result
+ : static_cast<void *>(static_cast<char *>(result) + count);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/string/mempcpy.h b/libc/src/string/mempcpy.h
new file mode 100644
index 0000000000000..6000761e177a8
--- /dev/null
+++ b/libc/src/string/mempcpy.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for mempcpy -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_MEMPCPY_H
+#define LLVM_LIBC_SRC_STRING_MEMPCPY_H
+
+#include <stddef.h>
+
+namespace __llvm_libc {
+
+void *mempcpy(void *__restrict dest, const void *__restrict src, size_t count);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_MEMPCPY_H
diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt
index 2d6d9199b5e16..2c8d6627a68d7 100644
--- a/libc/test/src/string/CMakeLists.txt
+++ b/libc/test/src/string/CMakeLists.txt
@@ -2,6 +2,26 @@ add_libc_testsuite(libc_string_unittests)
add_subdirectory(memory_utils)
+add_libc_unittest(
+ memccpy_test
+ SUITE
+ libc_string_unittests
+ SRCS
+ memccpy_test.cpp
+ DEPENDS
+ libc.src.string.memccpy
+)
+
+add_libc_unittest(
+ mempcpy_test
+ SUITE
+ libc_string_unittests
+ SRCS
+ mempcpy_test.cpp
+ DEPENDS
+ libc.src.string.mempcpy
+)
+
add_libc_unittest(
memchr_test
SUITE
diff --git a/libc/test/src/string/memccpy_test.cpp b/libc/test/src/string/memccpy_test.cpp
new file mode 100644
index 0000000000000..980c3a0ae5f35
--- /dev/null
+++ b/libc/test/src/string/memccpy_test.cpp
@@ -0,0 +1,80 @@
+//===-- Unittests for memccpy ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/memccpy.h"
+#include "utils/CPP/ArrayRef.h"
+#include "utils/UnitTest/Test.h"
+#include <stddef.h> // For size_t.
+
+class LlvmLibcMemccpyTest : public __llvm_libc::testing::Test {
+public:
+ void check_memccpy(__llvm_libc::cpp::MutableArrayRef<char> dst,
+ const __llvm_libc::cpp::ArrayRef<char> src, int end,
+ size_t count,
+ const __llvm_libc::cpp::ArrayRef<char> expected,
+ size_t expectedCopied, bool shouldReturnNull = false) {
+ // Making sure we don't overflow buffer.
+ ASSERT_GE(dst.size(), count);
+ // Making sure memccpy returns dst.
+ void *result = __llvm_libc::memccpy(dst.data(), src.data(), end, count);
+
+ if (shouldReturnNull) {
+ ASSERT_EQ(result, static_cast<void *>(nullptr));
+ } else {
+ ASSERT_EQ(result, static_cast<void *>(dst.data() + expectedCopied));
+ }
+
+ // Expected must be of the same size as dst.
+ ASSERT_EQ(dst.size(), expected.size());
+ // Expected and dst are the same.
+ for (size_t i = 0; i < expected.size(); ++i)
+ ASSERT_EQ(expected[i], dst[i]);
+ }
+};
+
+TEST_F(LlvmLibcMemccpyTest, UntouchedUnrelatedEnd) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', '\0'};
+ const char expected[] = {'a', 'b'};
+ check_memccpy(dst, src, 'z', 0, expected, 0, true);
+}
+
+TEST_F(LlvmLibcMemccpyTest, UntouchedStartsWithEnd) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', '\0'};
+ const char expected[] = {'a', 'b'};
+ check_memccpy(dst, src, 'x', 0, expected, 0, true);
+}
+
+TEST_F(LlvmLibcMemccpyTest, CopyOneUnrelatedEnd) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', 'y'};
+ const char expected[] = {'x', 'b'};
+ check_memccpy(dst, src, 'z', 1, expected, 1, true);
+}
+
+TEST_F(LlvmLibcMemccpyTest, CopyOneStartsWithEnd) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', 'y'};
+ const char expected[] = {'x', 'b'};
+ check_memccpy(dst, src, 'x', 1, expected, 1);
+}
+
+TEST_F(LlvmLibcMemccpyTest, CopyTwoUnrelatedEnd) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', 'y'};
+ const char expected[] = {'x', 'y'};
+ check_memccpy(dst, src, 'z', 2, expected, 2, true);
+}
+
+TEST_F(LlvmLibcMemccpyTest, CopyTwoStartsWithEnd) {
+ char dst[] = {'a', 'b'};
+ const char src[] = {'x', 'y'};
+ const char expected[] = {'x', 'b'};
+ check_memccpy(dst, src, 'x', 2, expected, 1);
+}
diff --git a/libc/test/src/string/mempcpy_test.cpp b/libc/test/src/string/mempcpy_test.cpp
new file mode 100644
index 0000000000000..9f95db56b84cc
--- /dev/null
+++ b/libc/test/src/string/mempcpy_test.cpp
@@ -0,0 +1,28 @@
+//===-- Unittests for mempcpy ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/mempcpy.h"
+#include "utils/UnitTest/Test.h"
+
+// Since this function just calls out to memcpy, and memcpy has its own unit
+// tests, it is assumed that memcpy works. These tests are just for the specific
+// mempcpy behavior (returning the end of what was copied).
+TEST(LlvmLibcMempcpyTest, Simple) {
+ const char *src = "12345";
+ char dest[10];
+ void *result = __llvm_libc::mempcpy(dest, src, 6);
+ ASSERT_EQ(static_cast<char *>(result), dest + 6);
+ ASSERT_STREQ(src, dest);
+}
+
+TEST(LlvmLibcMempcpyTest, ZeroCount) {
+ const char *src = "12345";
+ char dest[10];
+ void *result = __llvm_libc::mempcpy(dest, src, 0);
+ ASSERT_EQ(static_cast<char *>(result), dest);
+}
More information about the libc-commits
mailing list