Add libc strncpy implementation.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Thanks for the patch. I have few nits and a question inline.
libc/src/string/strncpy.cpp | ||
---|---|---|
20 | WDYT about a memcpy followed by a memset (for the null characters)? Both these functions in libcs are optimized in some manner so we will be leveraging that. We will need an additional strlen operation though. | |
libc/test/src/string/strncpy_test.cpp | ||
2 | Nit: Fix this. You probably need a space after strncpy. | |
13 | Nit: May be name it SameSrcSizeAndCopySize instead of ReturnRightValue? | |
21 | Nit: May be name it CopySizeNotEqualToSrcSize instead of OffsetDest. |
Thanks Siva.
libc/src/string/strncpy.cpp | ||
---|---|---|
20 | By referring to strcpy, I used memcpy and strlen at first.
I am not sure whick method is more appropriate. So I upload it for suggestions. |
Thanks for your patience.
libc/src/string/strncpy.cpp | ||
---|---|---|
20 |
I am not opposed to any approach. At the same time, I do not feel qualified enough to drive an opinion. So, adding @gchatelet for guidance. |
Thx for the patch!
libc/src/string/strncpy.cpp | ||
---|---|---|
20 | It's hard to be assertive on which one is best here. It certainly depends on how strncpy is used (buffer sizes, value of n, size of the zeroing, ...). | |
23 | There are two modes for computing strncpy:
You can only ever go from 1 to 2, never the opposite. So it seems to me that you don't need j, you can just use i. I've been fiddling a bit with different implementations (https://godbolt.org/z/Eb9xq9) and the following one seems simple and nice char *strncpy(char *__restrict dest, const char *__restrict src, size_t n) { size_t i = 0; for (; i < n && src[i] != '\0'; ++i) dest[i] = src[i]; for (; i < n; ++i) dest[i] = '\0'; return dest; } Added bonus, the compiler recognizes for (; i < n; ++i) dest[i] = '\0'; as a memset which lowers this function's footprint. IMHO the filling with zero part is not the most used part of the algorithm so it's nice to outline it. | |
25 | Can you use dest[i] instead of *(dest + i)? I believe it's more readable. | |
libc/test/src/string/strncpy_test.cpp | ||
45 | Would you mind splitting this into 3 tests to ease readability? struct StrncpyFixture : public __llvm_libc::testing::Test { void check_strncpy(__llvm_libc::cpp::MutableArrayRef<char> dst, __llvm_libc::cpp::ArrayRef<char> src, size_t n, __llvm_libc::cpp::ArrayRef<char> expected) { // Making sure we don't overflow buffer. ASSERT_GE(dst.size(), n); // Making sure strncpy returns dst. ASSERT_EQ(__llvm_libc::strncpy(dst.data(), src.data(), n), dst.data()); // Expected must be of the same size as Dest. ASSERT_EQ(dst.size(), expected.size()); for (size_t i = 0; i < expected.size(); ++i) ASSERT_EQ(expected[i], dst[i]); } }; TEST_F(StrncpyFixture, Untouched) { char dst[] = {'a', 'b'}; char src[] = {'x', '\0'}; char expected[] = {'a', 'b'}; check_strncpy(dst, src, 0, expected); } TEST_F(StrncpyFixture, CopyOne) { char dst[] = {'a', 'b'}; char src[] = {'x', 'y'}; char expected[] = {'x', 'b'}; // no \0 is appended check_strncpy(dst, src, 1, expected); } TEST_F(StrncpyFixture, CopyNull) { char dst[] = {'a', 'b'}; char src[] = {'\0', 'y'}; char expected[] = {'\0', 'b'}; check_strncpy(dst, src, 1, expected); } TEST_F(StrncpyFixture, CopyPastSrc) { char dst[] = {'a', 'b'}; char src[] = {'\0', 'y'}; char expected[] = {'\0', '\0'}; check_strncpy(dst, src, 2, expected); } |
I am sorry to occupy too much time of you both. I initially just want to optimize it a little bit.
WDYT about a memcpy followed by a memset (for the null characters)? Both these functions in libcs are optimized in some manner so we will be leveraging that. We will need an additional strlen operation though.