forked from OSchip/llvm-project
[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
This commit is contained in:
parent
0fcda9ae57
commit
db8a88fef8
|
@ -23,10 +23,12 @@ set(TARGET_LIBC_ENTRYPOINTS
|
||||||
# string.h entrypoints
|
# string.h entrypoints
|
||||||
libc.src.string.bcmp
|
libc.src.string.bcmp
|
||||||
libc.src.string.bzero
|
libc.src.string.bzero
|
||||||
|
libc.src.string.memccpy
|
||||||
libc.src.string.memchr
|
libc.src.string.memchr
|
||||||
libc.src.string.memcmp
|
libc.src.string.memcmp
|
||||||
libc.src.string.memcpy
|
libc.src.string.memcpy
|
||||||
libc.src.string.memmove
|
libc.src.string.memmove
|
||||||
|
libc.src.string.mempcpy
|
||||||
libc.src.string.memrchr
|
libc.src.string.memrchr
|
||||||
libc.src.string.memset
|
libc.src.string.memset
|
||||||
libc.src.string.strcat
|
libc.src.string.strcat
|
||||||
|
|
|
@ -220,6 +220,21 @@ def POSIX : StandardSpec<"POSIX"> {
|
||||||
],
|
],
|
||||||
[], // Enumerations
|
[], // Enumerations
|
||||||
[
|
[
|
||||||
|
FunctionSpec<
|
||||||
|
"memccpy",
|
||||||
|
RetValSpec<VoidPtr>,
|
||||||
|
[ArgSpec<VoidRestrictedPtr>,
|
||||||
|
ArgSpec<ConstVoidRestrictedPtr>,
|
||||||
|
ArgSpec<IntType>,
|
||||||
|
ArgSpec<SizeTType>]
|
||||||
|
>,
|
||||||
|
FunctionSpec<
|
||||||
|
"mempcpy",
|
||||||
|
RetValSpec<VoidPtr>,
|
||||||
|
[ArgSpec<VoidRestrictedPtr>,
|
||||||
|
ArgSpec<ConstVoidRestrictedPtr>,
|
||||||
|
ArgSpec<SizeTType>]
|
||||||
|
>,
|
||||||
FunctionSpec<
|
FunctionSpec<
|
||||||
"strnlen",
|
"strnlen",
|
||||||
RetValSpec<SizeTType>,
|
RetValSpec<SizeTType>,
|
||||||
|
|
|
@ -8,6 +8,25 @@ add_header_library(
|
||||||
libc.utils.CPP.standalone_cpp
|
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(
|
add_entrypoint_object(
|
||||||
memchr
|
memchr
|
||||||
SRCS
|
SRCS
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -2,6 +2,26 @@ add_libc_testsuite(libc_string_unittests)
|
||||||
|
|
||||||
add_subdirectory(memory_utils)
|
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(
|
add_libc_unittest(
|
||||||
memchr_test
|
memchr_test
|
||||||
SUITE
|
SUITE
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue