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
|
||||
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
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_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
|
||||
|
|
|
@ -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