axl_memmove

This commit is contained in:
NukeBird 2025-12-03 17:37:53 +03:00
parent e535c2f9bf
commit f1f44f0d6d
3 changed files with 192 additions and 29 deletions

View file

@ -254,6 +254,37 @@ void* axl_memchr(const void* ptr, u8 value, u32 n)
return NULL; return NULL;
} }
void* axl_memmove(void* dst, const void* src, u32 n)
{
if(!dst || !src || !n)
{
return dst;
}
const u8* s = (const u8*)src;
u8* d = (u8*)dst;
if(d > s)
{
s += n - 1;
d += n - 1;
while(n--)
{
*d-- = *s--;
}
}
else
{
while(n--)
{
*d++ = *s++;
}
}
return dst;
}
void axl_free(void* ptr) void axl_free(void* ptr)
{ {
if(!ptr) if(!ptr)

View file

@ -14,6 +14,7 @@ void* axl_memset(void* ptr, i8 c, u32 n);
void* axl_memcpy(void* dst, const void* src, u32 count); void* axl_memcpy(void* dst, const void* src, u32 count);
i32 axl_memcmp(const void* s1, const void* s2, u32 n); i32 axl_memcmp(const void* s1, const void* s2, u32 n);
void* axl_memchr(const void* ptr, u8 value, u32 n); void* axl_memchr(const void* ptr, u8 value, u32 n);
void* axl_memmove(void* dst, const void* src, u32 n);
void axl_free(void* ptr); void axl_free(void* ptr);
#endif #endif

View file

@ -1,7 +1,6 @@
/* /*
* axl_memory_tests.c Comprehensive unit tests for axl_memory.h * axl_memory_tests.c Comprehensive unit tests for axl_memory.h
*/ */
#include "axl_memory.h" #include "axl_memory.h"
#include "axl_koan.h" #include "axl_koan.h"
#include <string.h> #include <string.h>
@ -26,7 +25,7 @@ KOAN(malloc_returns_different_pointers)
KOAN(malloc_exhaustion_returns_null) KOAN(malloc_exhaustion_returns_null)
{ {
void* p = axl_malloc(AXL_HEAP_SIZE + 4096); void* p = axl_malloc(AXL_HEAP_SIZE + 4096);
ASSERT_NULL(p); ASSERT_NULL(p);
} }
@ -44,7 +43,6 @@ KOAN(realloc_zero_size_frees_and_returns_null_or_valid)
ASSERT_NOT_NULL(p); ASSERT_NOT_NULL(p);
void* q = axl_realloc(p, 0); void* q = axl_realloc(p, 0);
if (q != NULL) axl_free(q); if (q != NULL) axl_free(q);
} }
KOAN(realloc_enlarge_preserves_content) KOAN(realloc_enlarge_preserves_content)
@ -72,10 +70,8 @@ KOAN(realloc_shrink_preserves_prefix)
KOAN(realloc_same_size_returns_same_or_equivalent) KOAN(realloc_same_size_returns_same_or_equivalent)
{ {
void* p = axl_malloc(100); void* p = axl_malloc(100);
p = axl_realloc(p, 100); p = axl_realloc(p, 100);
ASSERT_NOT_NULL(p); ASSERT_NOT_NULL(p);
axl_free(p); axl_free(p);
} }
@ -92,7 +88,7 @@ KOAN(memset_zero_bytes_is_nop)
{ {
void* p = axl_malloc(16); void* p = axl_malloc(16);
axl_memset(p, 0xFF, 16); axl_memset(p, 0xFF, 16);
axl_memset(p, 0x00, 0); axl_memset(p, 0x00, 0);
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
ASSERT_INT_EQ(0xFF, ((u8*)p)[i]); ASSERT_INT_EQ(0xFF, ((u8*)p)[i]);
axl_free(p); axl_free(p);
@ -113,7 +109,7 @@ KOAN(memcpy_zero_bytes_is_nop)
u8 data[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; u8 data[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
void* p = axl_malloc(16); void* p = axl_malloc(16);
axl_memcpy(p, data, 16); axl_memcpy(p, data, 16);
axl_memcpy(p, "junk", 0); axl_memcpy(p, "junk", 0);
ASSERT_INT_EQ(0, memcmp(p, data, 16)); ASSERT_INT_EQ(0, memcmp(p, data, 16));
axl_free(p); axl_free(p);
} }
@ -123,7 +119,6 @@ KOAN(memcmp_returns_correct_sign)
u8 a[] = {0, 0, 0, 0}; u8 a[] = {0, 0, 0, 0};
u8 b[] = {0, 0, 0, 1}; u8 b[] = {0, 0, 0, 1};
u8 c[] = {0, 0, 1, 0}; u8 c[] = {0, 0, 1, 0};
ASSERT_INT_EQ(0, axl_memcmp(a, a, 4)); ASSERT_INT_EQ(0, axl_memcmp(a, a, 4));
ASSERT_TRUE(axl_memcmp(a, b, 4) < 0); ASSERT_TRUE(axl_memcmp(a, b, 4) < 0);
ASSERT_TRUE(axl_memcmp(b, a, 4) > 0); ASSERT_TRUE(axl_memcmp(b, a, 4) > 0);
@ -160,7 +155,7 @@ KOAN(memchr_finds_first_occurrence)
u8 buffer[] = {0xAA, 0xBB, 0xCC, 0xBB, 0xDD}; u8 buffer[] = {0xAA, 0xBB, 0xCC, 0xBB, 0xDD};
void* result = axl_memchr(buffer, 0xBB, sizeof(buffer)); void* result = axl_memchr(buffer, 0xBB, sizeof(buffer));
ASSERT_NOT_NULL(result); ASSERT_NOT_NULL(result);
ASSERT_TRUE(result == &buffer[1]); ASSERT_TRUE(result == &buffer[1]);
} }
KOAN(memchr_finds_at_beginning) KOAN(memchr_finds_at_beginning)
@ -189,11 +184,8 @@ KOAN(memchr_zero_length_returns_null)
KOAN(memchr_stops_at_specified_length) KOAN(memchr_stops_at_specified_length)
{ {
u8 buffer[] = {0x10, 0x20, 0x30, 0x40, 0x50}; u8 buffer[] = {0x10, 0x20, 0x30, 0x40, 0x50};
void* result = axl_memchr(buffer, 0x40, 3); void* result = axl_memchr(buffer, 0x40, 3);
ASSERT_NULL(result); ASSERT_NULL(result);
result = axl_memchr(buffer, 0x40, 4); result = axl_memchr(buffer, 0x40, 4);
ASSERT_NOT_NULL(result); ASSERT_NOT_NULL(result);
ASSERT_TRUE(result == &buffer[3]); ASSERT_TRUE(result == &buffer[3]);
@ -202,12 +194,12 @@ KOAN(memchr_stops_at_specified_length)
KOAN(memchr_handles_all_byte_values) KOAN(memchr_handles_all_byte_values)
{ {
u8 buffer[256]; u8 buffer[256];
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++)
{
buffer[i] = (u8)i; buffer[i] = (u8)i;
} }
for (int i = 0; i < 256; i++)
{
for (int i = 0; i < 256; i++) {
void* result = axl_memchr(buffer, (u8)i, sizeof(buffer)); void* result = axl_memchr(buffer, (u8)i, sizeof(buffer));
ASSERT_NOT_NULL(result); ASSERT_NOT_NULL(result);
ASSERT_TRUE(result == &buffer[i]); ASSERT_TRUE(result == &buffer[i]);
@ -217,38 +209,175 @@ KOAN(memchr_handles_all_byte_values)
KOAN(memchr_matches_standard_memchr) KOAN(memchr_matches_standard_memchr)
{ {
u8 buffer[100]; u8 buffer[100];
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++)
{
buffer[i] = (u8)(i * 3); buffer[i] = (u8)(i * 3);
} }
for (int val = 0; val < 256; val += 17)
{
for (int val = 0; val < 256; val += 17) {
void* axl_result = axl_memchr(buffer, (u8)val, sizeof(buffer)); void* axl_result = axl_memchr(buffer, (u8)val, sizeof(buffer));
void* std_result = memchr(buffer, (u8)val, sizeof(buffer)); void* std_result = memchr(buffer, (u8)val, sizeof(buffer));
if (std_result == NULL)
{
if (std_result == NULL) {
ASSERT_NULL(axl_result); ASSERT_NULL(axl_result);
} else { }
else
{
ASSERT_NOT_NULL(axl_result); ASSERT_NOT_NULL(axl_result);
ASSERT_TRUE(axl_result == std_result); ASSERT_TRUE(axl_result == std_result);
} }
} }
} }
KOAN(memmove_basic_copy)
{
u8 src[64];
u8 dst[64];
for (int i = 0; i < 64; i++)
{
src[i] = (u8)(i + 1);
}
axl_memmove(dst, src, 64);
for (int i = 0; i < 64; i++)
{
ASSERT_INT_EQ(src[i], dst[i]);
}
}
KOAN(memmove_zero_bytes_is_nop)
{
u8 data[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
u8 copy[16];
axl_memcpy(copy, data, 16);
axl_memmove(copy, NULL, 0);
for (int i = 0; i < 16; i++)
{
ASSERT_INT_EQ(data[i], copy[i]);
}
}
KOAN(memmove_overlap_forward)
{
u8 buffer[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
u8 expected[32];
memcpy(expected, buffer, 32);
memmove(expected + 8, expected + 4, 16);
axl_memmove(buffer + 8, buffer + 4, 16);
for (int i = 0; i < 32; i++)
{
ASSERT_INT_EQ(expected[i], buffer[i]);
}
}
KOAN(memmove_overlap_backward)
{
u8 buffer[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
u8 expected[32];
memcpy(expected, buffer, 32);
memmove(expected + 4, expected + 8, 16);
axl_memmove(buffer + 4, buffer + 8, 16);
for (int i = 0; i < 32; i++)
{
ASSERT_INT_EQ(expected[i], buffer[i]);
}
}
KOAN(memmove_overlap_same_region)
{
u8 buffer[32];
for (int i = 0; i < 32; i++)
{
buffer[i] = (u8)i;
}
u8 expected[32];
memcpy(expected, buffer, 32);
axl_memmove(buffer, buffer, 32);
for (int i = 0; i < 32; i++)
{
ASSERT_INT_EQ(expected[i], buffer[i]);
}
}
KOAN(memmove_overlap_single_byte)
{
u8 buffer[8] = {0,1,2,3,4,5,6,7};
u8 expected[8];
memcpy(expected, buffer, 8);
memmove(expected + 1, expected, 7);
axl_memmove(buffer + 1, buffer, 7);
for (int i = 0; i < 8; i++)
{
ASSERT_INT_EQ(expected[i], buffer[i]);
}
}
KOAN(memmove_matches_standard_memmove)
{
u8 src[128];
u8 dst_axl[128];
u8 dst_std[128];
for (int i = 0; i < 128; i++)
{
src[i] = (u8)(i * 7);
}
for (int offset = -16; offset <= 16; offset++)
{
memcpy(dst_axl, src, 128);
memcpy(dst_std, src, 128);
int src_offset = 32;
int dst_offset = 32 + offset;
int copy_size = 64;
axl_memmove(dst_axl + dst_offset, dst_axl + src_offset, copy_size);
memmove(dst_std + dst_offset, dst_std + src_offset, copy_size);
for (int i = 0; i < 128; i++)
{
ASSERT_INT_EQ(dst_std[i], dst_axl[i]);
}
}
}
KOAN(memmove_small_overlap)
{
u8 buffer[10] = {0,1,2,3,4,5,6,7,8,9};
u8 expected[10];
memcpy(expected, buffer, 10);
memmove(expected + 2, expected, 5);
axl_memmove(buffer + 2, buffer, 5);
for (int i = 0; i < 10; i++)
{
ASSERT_INT_EQ(expected[i], buffer[i]);
}
}
KOAN(memmove_large_non_overlap)
{
u8 src[256];
u8 dst[256];
for (int i = 0; i < 256; i++)
{
src[i] = (u8)(255 - i);
}
axl_memmove(dst, src, 256);
for (int i = 0; i < 256; i++)
{
ASSERT_INT_EQ(src[i], dst[i]);
}
}
KOAN(double_free_does_not_crash) KOAN(double_free_does_not_crash)
{ {
void* p = axl_malloc(64); void* p = axl_malloc(64);
ASSERT_NOT_NULL(p); ASSERT_NOT_NULL(p);
axl_free(p); axl_free(p);
axl_free(p); axl_free(p);
} }
KOAN(large_allocation_near_heap_limit) KOAN(large_allocation_near_heap_limit)
{ {
void* p = axl_malloc(AXL_HEAP_SIZE - 1024); void* p = axl_malloc(AXL_HEAP_SIZE - 1024);
ASSERT_NOT_NULL(p); ASSERT_NOT_NULL(p);
if (p) axl_free(p); if (p) axl_free(p);
} }
@ -262,12 +391,14 @@ KOAN(many_small_allocations)
{ {
#define N 1000 #define N 1000
void* ptrs[N]; void* ptrs[N];
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++)
{
ptrs[i] = axl_malloc(16); ptrs[i] = axl_malloc(16);
ASSERT_NOT_NULL(ptrs[i]); ASSERT_NOT_NULL(ptrs[i]);
*(u32*)ptrs[i] = 0xDEADBEEF; *(u32*)ptrs[i] = 0xDEADBEEF;
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++)
{
ASSERT_INT_EQ(0xDEADBEEF, *(u32*)ptrs[i]); ASSERT_INT_EQ(0xDEADBEEF, *(u32*)ptrs[i]);
axl_free(ptrs[i]); axl_free(ptrs[i]);
} }