FxLibcTest/src/string/core.c

289 lines
7.2 KiB
C

#include <ft/test.h>
#include <ft/all-tests.h>
#include <string.h>
#include "memarray.h"
//---
// Utilities
//---
/* Fill buffer with non-zero and position-sensitive data */
static void fill(uint8_t *buf, int size, int start)
{
for(int i = 0; i < size; i++) buf[i] = start+i;
}
/* Clear buffer */
static void clear(uint8_t *buf, int size, int value)
{
for(int i = 0; i < size; i++) buf[i] = value;
}
/* Check buffer equality (returns zero on equal) */
static int cmp(uint8_t *left, uint8_t *right, int size)
{
for(int i = 0; i < size; i++) if(left[i] != right[i]) return 1;
return 0;
}
//---
// Naive functions (baseline)
//---
static void *naive_memcpy(void *_dst, void const *_src, size_t len)
{
uint8_t *dst = _dst;
uint8_t const *src = _src;
while(len--) *dst++ = *src++;
return _dst;
}
static void *naive_memset(void *_dst, int byte, size_t len)
{
uint8_t *dst = _dst;
while(len--) *dst++ = byte;
return _dst;
}
static void *naive_memmove(void *dst, void const *src, size_t len)
{
uint8_t tmp[len];
naive_memcpy(tmp, src, len);
naive_memcpy(dst, tmp, len);
return dst;
}
static int naive_memcmp(void const *_s1, void const *_s2, size_t len)
{
uint8_t const *s1 = _s1, *s2 = _s2;
for(size_t i = 0; i < len; i++)
{
if(s1[i] != s2[i]) return s1[i] - s2[i];
}
return 0;
}
//---
// memset
//---
static int _string_memset_func(memarray_args_t const *args)
{
fill(args->full_buf1, args->full_size, 0);
fill(args->full_buf2, args->full_size, 0);
memset(args->buf1, 0, args->size);
naive_memset(args->buf2, 0, args->size);
return cmp(args->full_buf1, args->full_buf2, args->full_size);
}
uint8_t _string_memset_rc[MEMARRAY_RC_SINGLE];
static void _string_memset(ft_test *t)
{
memarray_single(_string_memset_rc, _string_memset_func);
memarray_assert(_string_memset_rc, t);
}
static jwidget *_string_memset_widget(GUNUSED ft_test *t)
{
return memarray_widget(_string_memset_rc);
}
ft_test ft_string_memset = {
.name = "Configurations of memset",
.function = _string_memset,
.widget = _string_memset_widget,
};
//---
// memcpy
//---
static int _string_memcpy_func(memarray_args_t const *args)
{
fill(args->full_left1, args->full_size, 0);
fill(args->full_left2, args->full_size, 0);
clear(args->full_right1, args->full_size, 0);
clear(args->full_right2, args->full_size, 0);
memcpy(args->right1, args->left1, args->size);
naive_memcpy(args->right2, args->left2, args->size);
return cmp(args->full_right1, args->full_right2, args->full_size);
}
uint8_t _string_memcpy_rc[MEMARRAY_RC_DOUBLE];
static void _string_memcpy(ft_test *t)
{
memarray_double(_string_memcpy_rc, false, _string_memcpy_func);
memarray_assert(_string_memcpy_rc, t);
}
static jwidget *_string_memcpy_widget(GUNUSED ft_test *t)
{
return memarray_widget(_string_memcpy_rc);
}
ft_test ft_string_memcpy = {
.name = "Configurations of memcpy",
.function = _string_memcpy,
.widget = _string_memcpy_widget,
};
//---
// memmove
//---
static int _string_memmove_func(memarray_args_t const *args)
{
fill(args->full_left1, args->full_size, 0);
fill(args->full_left2, args->full_size, 0);
fill(args->full_right1, args->full_size, 0);
fill(args->full_right2, args->full_size, 0);
memmove(args->right1, args->left1, args->size);
naive_memmove(args->right2, args->left2, args->size);
return cmp(args->full_right1, args->full_right2, args->full_size);
}
uint8_t _string_memmove_rc[MEMARRAY_RC_DOUBLE_OVERLAP];
static void _string_memmove(ft_test *t)
{
memarray_double(_string_memmove_rc, true, _string_memmove_func);
memarray_assert(_string_memmove_rc, t);
}
static jwidget *_string_memmove_widget(GUNUSED ft_test *t)
{
return memarray_widget(_string_memmove_rc);
}
ft_test ft_string_memmove = {
.name = "Configurations of memmove",
.function = _string_memmove,
.widget = _string_memmove_widget,
};
//---
// memcmp
//---
static int _string_memcmp_func(memarray_args_t const *args)
{
/* Create data that matches in the given regions */
fill(args->full_left1, args->full_size, args->left1 - args->full_left1);
fill(args->full_right1, args->full_size, args->right1 - args->full_right1);
/* Check equality */
if(memcmp(args->left1, args->right1, args->size) !=
naive_memcmp(args->left1, args->right1, args->size)) return 1;
/* Check that changing single bytes changes the result */
for(size_t i = 0; i < args->size / 4; i++) {
((uint8_t *)args->right1)[i] ^= 0xff;
if(memcmp(args->left1, args->right1, args->size) !=
naive_memcmp(args->left1, args->right1, args->size)) return 1;
((uint8_t *)args->right1)[i] ^= 0xff;
}
return 0;
}
uint8_t _string_memcmp_rc[MEMARRAY_RC_DOUBLE];
static void _string_memcmp(ft_test *t)
{
memarray_double(_string_memcmp_rc, false, _string_memcmp_func);
memarray_assert(_string_memcmp_rc, t);
}
static jwidget *_string_memcmp_widget(GUNUSED ft_test *t)
{
return memarray_widget(_string_memcmp_rc);
}
ft_test ft_string_memcmp = {
.name = "Configurations of memcmp",
.function = _string_memcmp,
.widget = _string_memcmp_widget,
};
//---
// memchr
//---
static int _string_memchr_func(memarray_args_t const *args)
{
/* Start at 2, and search for byte 1 (inserted manually). Fill the region
around with 1s to make sure they are ignored */
clear(args->full_buf1, args->full_size, 0);
fill(args->buf1, args->size, 2);
/* Check that no byte is found initially */
if(memchr(args->buf1, 0x01, args->size)) return 1;
/* We'll try bytes at all of these locations */
char *p1 = (char *)args->buf1;
char *p2 = (char *)args->buf1 + (args->size / 4);
char *p3 = (char *)args->buf1 + (3 * args->size / 4);
char *p4 = (char *)args->buf1 + (args->size - 1);
*p1 = 0x01;
*p2 = 0x01;
*p3 = 0x01;
*p4 = 0x01;
/* First byte in the area */
if(memchr(args->buf1, 0x01, args->size) != p1) return 1;
*p1 = 0x02;
/* First quarter */
if(memchr(args->buf1, 0x01, args->size) != p2) return 1;
*p2 = 0x02;
/* Third quarter */
if(memchr(args->buf1, 0x01, args->size) != p3) return 1;
*p3 = 0x02;
/* Last byte */
if(memchr(args->buf1, 0x01, args->size) != p4) return 1;
*p4 = 0x02;
return 0;
}
uint8_t _string_memchr_rc[MEMARRAY_RC_SINGLE];
static void _string_memchr(ft_test *t)
{
#define memchr_dist(str, byte, size) ({ \
void const *_str = (str); \
memchr(_str, byte, size) - _str; \
})
ft_assert(t, memchr("xyztu", 'x', 0) == NULL);
ft_assert(t, memchr_dist("xyztu", 'x', 5) == 0);
ft_assert(t, memchr_dist("xyztu", 'y', 5) == 1);
ft_assert(t, memchr_dist("xyztu", 'z', 5) == 2);
ft_assert(t, memchr_dist("xyztu", 't', 5) == 3);
ft_assert(t, memchr_dist("xyztu", 'u', 5) == 4);
ft_assert(t, memchr("xyztu", 'v', 5) == NULL);
memarray_single(_string_memchr_rc, _string_memchr_func);
memarray_assert(_string_memchr_rc, t);
}
static jwidget *_string_memchr_widget(GUNUSED ft_test *t)
{
return memarray_widget(_string_memchr_rc);
}
ft_test ft_string_memchr = {
.name = "Configurations of memchr",
.function = _string_memchr,
.widget = _string_memchr_widget,
};