[libc][Obvious] Some clean work with memmove.

This commit is contained in:
Cheng Wang 2021-09-14 17:19:28 +08:00
parent 2d6829bbbe
commit 3582828748
3 changed files with 34 additions and 33 deletions

View File

@ -28,30 +28,30 @@ static inline void move_byte_backward(char *dest_m, const char *src_m,
}
LLVM_LIBC_FUNCTION(void *, memmove,
(void *dest, const void *src, size_t count)) {
char *dest_c = reinterpret_cast<char *>(dest);
(void *dst, const void *src, size_t count)) {
char *dest_c = reinterpret_cast<char *>(dst);
const char *src_c = reinterpret_cast<const char *>(src);
// If the distance between src_c and dest_c is equal to or greater
// than count (integerAbs(src_c - dest_c) >= count), they would not overlap.
// If the distance between `src_c` and `dest_c` is equal to or greater
// than `count` (integerAbs(src_c - dest_c) >= count), they would not overlap.
// e.g. greater equal overlapping
// [12345678] [12345678] [12345678]
// src_c: [_ab_____] [_ab_____] [_ab_____]
// dest_c:[_____yz_] [___yz___] [__yz____]
// Use memcpy if src_c and dest_c do not overlap.
// Call `memcpy` if `src_c` and `dest_c` do not overlap.
if (__llvm_libc::integerAbs(src_c - dest_c) >= static_cast<ptrdiff_t>(count))
return __llvm_libc::memcpy(dest_c, src_c, count);
// Overlap cases.
// If dest_c starts before src_c (dest_c < src_c), copy forward(pointer add 1)
// from beginning to end.
// If dest_c starts after src_c (dest_c > src_c), copy backward(pointer add
// -1) from end to beginning.
// If dest_c and src_c start at the same address (dest_c == src_c),
// Overlapping cases.
// If `dest_c` starts before `src_c` (dest_c < src_c), copy
// forward(pointer add 1) from beginning to end.
// If `dest_c` starts after `src_c` (dest_c > src_c), copy
// backward(pointer add -1) from end to beginning.
// If `dest_c` and `src_c` start at the same address (dest_c == src_c),
// just return dest.
// e.g. forward backward
// *--> <--*
// *-> <-*
// src_c : [___abcde_] [_abcde___]
// dest_c: [_abc--___] [___--cde_]
@ -60,7 +60,7 @@ LLVM_LIBC_FUNCTION(void *, memmove,
move_byte_forward(dest_c, src_c, count);
if (dest_c > src_c)
move_byte_backward(dest_c, src_c, count);
return dest;
return dst;
}
} // namespace __llvm_libc

View File

@ -13,7 +13,7 @@
namespace __llvm_libc {
void *memmove(void *dest, const void *src, size_t count);
void *memmove(void *dst, const void *src, size_t count);
} // namespace __llvm_libc

View File

@ -6,64 +6,65 @@
//
//===----------------------------------------------------------------------===//
#include "src/string/memcmp.h"
#include "src/string/memmove.h"
#include "utils/CPP/ArrayRef.h"
#include "utils/UnitTest/Test.h"
class LlvmLibcMemmoveTest : public __llvm_libc::testing::Test {
public:
void check_memmove(void *dest, const void *src, size_t count, const void *str,
void check_memmove(void *dst, const void *src, size_t count,
const unsigned char *str,
const __llvm_libc::cpp::ArrayRef<unsigned char> expected) {
void *result = __llvm_libc::memmove(dest, src, count);
// Making sure the pointer returned is same with dest.
EXPECT_EQ(result, dest);
// expected is designed according to str.
// dest and src might be part of str.
// Making sure the str is same with expected.
EXPECT_EQ(__llvm_libc::memcmp(str, expected.data(), expected.size()), 0);
void *result = __llvm_libc::memmove(dst, src, count);
// Making sure the pointer returned is same with `dst`.
EXPECT_EQ(result, dst);
// `expected` is designed according to `str`.
// `dst` and `src` might be part of `str`.
// Making sure `str` is same with `expected`.
for (size_t i = 0; i < expected.size(); ++i)
EXPECT_EQ(str[i], expected[i]);
}
};
TEST_F(LlvmLibcMemmoveTest, MoveZeroByte) {
unsigned char dest[] = {'a', 'b'};
unsigned char dst[] = {'a', 'b'};
const unsigned char src[] = {'y', 'z'};
const unsigned char expected[] = {'a', 'b'};
check_memmove(dest, src, 0, dest, expected);
check_memmove(dst, src, 0, dst, expected);
}
TEST_F(LlvmLibcMemmoveTest, OverlapThatDestAndSrcPointToSameAddress) {
TEST_F(LlvmLibcMemmoveTest, OverlapThatDstAndSrcPointToSameAddress) {
unsigned char str[] = {'a', 'b'};
const unsigned char expected[] = {'a', 'b'};
check_memmove(str, str, 1, str, expected);
}
TEST_F(LlvmLibcMemmoveTest, OverlapThatDestStartsBeforeSrc) {
TEST_F(LlvmLibcMemmoveTest, OverlapThatDstStartsBeforeSrc) {
// Set boundary at beginning and end for not overstepping when
// copy forward or backward.
unsigned char str[] = {'z', 'a', 'b', 'c', 'z'};
const unsigned char expected[] = {'z', 'b', 'c', 'c', 'z'};
// dest is &str[1].
// `dst` is `&str[1]`.
check_memmove(&str[1], &str[2], 2, str, expected);
}
TEST_F(LlvmLibcMemmoveTest, OverlapThatDestStartsAfterSrc) {
TEST_F(LlvmLibcMemmoveTest, OverlapThatDstStartsAfterSrc) {
unsigned char str[] = {'z', 'a', 'b', 'c', 'z'};
const unsigned char expected[] = {'z', 'a', 'a', 'b', 'z'};
check_memmove(&str[2], &str[1], 2, str, expected);
}
// e.g. dest follow src.
// e.g. `dst` follow `src`.
// str: [abcdefghij]
// [__src_____]
// [_____dest_]
TEST_F(LlvmLibcMemmoveTest, SrcFollowDest) {
// [_____dst__]
TEST_F(LlvmLibcMemmoveTest, SrcFollowDst) {
unsigned char str[] = {'z', 'a', 'b', 'z'};
const unsigned char expected[] = {'z', 'b', 'b', 'z'};
check_memmove(&str[1], &str[2], 1, str, expected);
}
TEST_F(LlvmLibcMemmoveTest, DestFollowSrc) {
TEST_F(LlvmLibcMemmoveTest, DstFollowSrc) {
unsigned char str[] = {'z', 'a', 'b', 'z'};
const unsigned char expected[] = {'z', 'a', 'a', 'z'};
check_memmove(&str[2], &str[1], 1, str, expected);