Squash commits for public release
This commit is contained in:
94
libs/libc/string/routines/arm32/memset.S
Normal file
94
libs/libc/string/routines/arm32/memset.S
Normal file
@@ -0,0 +1,94 @@
|
||||
// Target ARMv7
|
||||
|
||||
.global memset
|
||||
|
||||
// r0 - dest
|
||||
// r1 - ch
|
||||
// r2 - len
|
||||
memset:
|
||||
mov r3, r0
|
||||
|
||||
cmp r2, #0
|
||||
beq memset_exit
|
||||
|
||||
tst r3, #3 // Will set N
|
||||
beq memset_4bytes_aligned_entry
|
||||
|
||||
memset_byte:
|
||||
subs r2, r2, #1
|
||||
strb r1, [r3], #1
|
||||
|
||||
cmp r2, #0
|
||||
beq memset_exit
|
||||
|
||||
tst r3, #3
|
||||
bne memset_byte
|
||||
|
||||
memset_4bytes_aligned_entry:
|
||||
cmp r2, #4
|
||||
blt memset_byte_2
|
||||
|
||||
and r1, #0xFF
|
||||
orr r1, r1, r1, lsl#8
|
||||
orr r1, r1, r1, lsl#16
|
||||
|
||||
tst r3, #15
|
||||
beq memset_16bytes_aligned_entry
|
||||
|
||||
memset_4bytes_aligned_loop:
|
||||
subs r2, r2, #4
|
||||
str r1, [r3], #4
|
||||
|
||||
cmp r2, #0
|
||||
beq memset_exit
|
||||
|
||||
cmp r2, #4
|
||||
blt memset_byte_2
|
||||
|
||||
tst r3, #15 // Test if we can put 16bytes block.
|
||||
bne memset_4bytes_aligned_loop // If not repeat 4 byte block again.
|
||||
|
||||
memset_16bytes_aligned_entry:
|
||||
push {r5, r6, r7}
|
||||
cmp r2, #16
|
||||
blt memset_16bytes_aligned_exit
|
||||
|
||||
memset_16bytes_aligned_preloop:
|
||||
// Load ch into all bytes of 32bit r1 register
|
||||
mov r5, r1
|
||||
mov r6, r1
|
||||
mov r7, r1
|
||||
|
||||
memset_16bytes_aligned_loop:
|
||||
subs r2, r2, #16
|
||||
stmia r3!,{r1,r5,r6,r7}
|
||||
|
||||
cmp r2, #16
|
||||
bge memset_16bytes_aligned_loop
|
||||
|
||||
memset_16bytes_aligned_exit:
|
||||
pop {r5, r6, r7}
|
||||
cmp r2, #0
|
||||
beq memset_exit
|
||||
|
||||
memset_4bytes_aligned_entry_2:
|
||||
cmp r2, #4
|
||||
blt memset_byte_2
|
||||
|
||||
memset_4bytes_aligned_loop_2:
|
||||
subs r2, r2, #4
|
||||
str r1, [r3], #4
|
||||
|
||||
cmp r2, #0
|
||||
beq memset_exit
|
||||
|
||||
cmp r2, #4
|
||||
bge memset_4bytes_aligned_loop_2
|
||||
|
||||
memset_byte_2:
|
||||
subs r2, r2, #1
|
||||
strb r1, [r3], #1
|
||||
bne memset_byte_2
|
||||
|
||||
memset_exit:
|
||||
bx lr
|
||||
277
libs/libc/string/string.c
Normal file
277
libs/libc/string/string.c
Normal file
@@ -0,0 +1,277 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef __arm__
|
||||
void* memset(void* dest, int fill, size_t nbytes)
|
||||
{
|
||||
for (int i = 0; i < nbytes; ++i)
|
||||
((uint8_t*)dest)[i] = fill;
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif //__arm__
|
||||
|
||||
void* memmove(void* dest, const void* src, size_t nbytes)
|
||||
{
|
||||
if (src > dest) {
|
||||
memcpy(dest, src, nbytes);
|
||||
return dest;
|
||||
}
|
||||
|
||||
for (int i = nbytes - 1; i >= 0; --i)
|
||||
((uint8_t*)dest)[i] = ((uint8_t*)src)[i];
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* This optimized version of memcpy uses 32 bit chunks to copy over data on
|
||||
the 32 bit architecture this library is built for. If this function gets
|
||||
used on a 64 bit arch, be sure to use 8 byte chunks so each chunk fits
|
||||
in a single register. The important part is this should be compiled with
|
||||
atleast -O1 or -Os, because -O0 just makes this function too big for what
|
||||
it does.
|
||||
|
||||
GCC does a better job at optimizing this if the pointers are restricted,
|
||||
making the copying part have less instructions. Clang on the other hand
|
||||
does not really change anything if the pointers are restricted or not. */
|
||||
void* memcpy(void* __restrict dest, const void* __restrict src, size_t nbytes)
|
||||
{
|
||||
size_t chunks, rest, i;
|
||||
|
||||
rest = nbytes % 4;
|
||||
chunks = (nbytes - rest) >> 2;
|
||||
|
||||
if (!chunks)
|
||||
goto skip_chunks;
|
||||
|
||||
for (i = 0; i < chunks; i++)
|
||||
((uint32_t*)dest)[i] = ((uint32_t*)src)[i];
|
||||
|
||||
skip_chunks:
|
||||
|
||||
/* Multiplying chunks by 4 will give us the offset of the 'rest' bytes,
|
||||
which were not copied over along with the 4 byte chunks. */
|
||||
chunks <<= 2;
|
||||
|
||||
for (i = 0; i < rest; i++)
|
||||
((uint8_t*)dest)[chunks + i] = ((uint8_t*)src)[chunks + i];
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void* memccpy(void* dest, const void* src, int stop, size_t nbytes)
|
||||
{
|
||||
for (int i = 0; i < nbytes; i++) {
|
||||
*((uint8_t*)dest + i) = *((uint8_t*)src + i);
|
||||
|
||||
if (*((uint8_t*)src + i) == stop)
|
||||
return ((uint8_t*)dest + i + 1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int memcmp(const void* src1, const void* src2, size_t nbytes)
|
||||
{
|
||||
const uint8_t* first = src1;
|
||||
const uint8_t* second = src2;
|
||||
|
||||
for (int i = 0; i < nbytes; i++) {
|
||||
/* Return the difference if the byte does not match. */
|
||||
if (first[i] != second[i])
|
||||
return (int)first[i] - (int)second[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* memchr(const void* ptr, int c, size_t size)
|
||||
{
|
||||
char ch = c;
|
||||
const char* cptr = (const char*)ptr;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (cptr[i] == ch) {
|
||||
return (char*)(cptr + i);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int strcmp(const char* a, const char* b)
|
||||
{
|
||||
while (*a == *b && *a != '\0' && *b != '\0') {
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
|
||||
if (*a < *b) {
|
||||
return -1;
|
||||
}
|
||||
if (*a > *b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strncmp(const char* a, const char* b, size_t num)
|
||||
{
|
||||
while (*a == *b && *a != 0 && *b != 0 && num) {
|
||||
a++;
|
||||
b++;
|
||||
num--;
|
||||
}
|
||||
|
||||
if (!num) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*a < *b) {
|
||||
return -1;
|
||||
}
|
||||
if (*a > *b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t strlen(const char* str)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (str[i])
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
char* strcpy(char* dest, const char* src)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; src[i] != 0; i++)
|
||||
dest[i] = src[i];
|
||||
|
||||
dest[i] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
char* strncpy(char* dest, const char* src, size_t nbytes)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nbytes && src[i] != 0; i++)
|
||||
dest[i] = src[i];
|
||||
|
||||
/* Fill the rest with null bytes */
|
||||
for (; i < nbytes; i++)
|
||||
dest[i] = 0;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
char* strchr(const char* s, int c)
|
||||
{
|
||||
for (;; s++) {
|
||||
if (*s == c) {
|
||||
return (char*)s;
|
||||
}
|
||||
if (!(*s)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* strtok_r(char* str, const char* delim, char** saveptr)
|
||||
{
|
||||
if (!str) {
|
||||
if (!saveptr) {
|
||||
return NULL;
|
||||
}
|
||||
str = *saveptr;
|
||||
}
|
||||
|
||||
size_t start = 0;
|
||||
size_t end = 0;
|
||||
size_t n = strlen(str);
|
||||
size_t m = strlen(delim);
|
||||
bool ok = false;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
ok = false;
|
||||
for (size_t j = 0; j < m; j++) {
|
||||
if (str[i] == delim[j]) {
|
||||
if (end - start == 0) {
|
||||
start++;
|
||||
break;
|
||||
}
|
||||
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
break;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
|
||||
if (str[start] == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (end == 0) {
|
||||
*saveptr = NULL;
|
||||
return &str[start];
|
||||
}
|
||||
|
||||
if (str[end] == '\0') {
|
||||
*saveptr = &str[end];
|
||||
} else {
|
||||
*saveptr = &str[end + 1];
|
||||
}
|
||||
|
||||
str[end] = '\0';
|
||||
return &str[start];
|
||||
}
|
||||
|
||||
char* strtok(char* str, const char* delim)
|
||||
{
|
||||
static char* saveptr;
|
||||
return strtok_r(str, delim, &saveptr);
|
||||
}
|
||||
|
||||
char* strstr(const char* haystack, const char* needle)
|
||||
{
|
||||
size_t n = strlen(needle);
|
||||
|
||||
while (*haystack) {
|
||||
if (!memcmp(haystack, needle, n)) {
|
||||
return (char*)haystack;
|
||||
}
|
||||
haystack++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* strcat(char* dest, const char* src)
|
||||
{
|
||||
size_t dest_len = strlen(dest);
|
||||
size_t i = 0;
|
||||
|
||||
while (src[i] != '\0') {
|
||||
dest[dest_len + i] = src[i];
|
||||
i++;
|
||||
}
|
||||
dest[dest_len + i] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
char* strrchr(const char* str, int ch)
|
||||
{
|
||||
char c;
|
||||
char* last = NULL;
|
||||
|
||||
while ((c = *str)) {
|
||||
if (c == ch) {
|
||||
last = (char*)(str);
|
||||
}
|
||||
str++;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
Reference in New Issue
Block a user