aboutsummaryrefslogtreecommitdiff
path: root/lib/libk/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libk/stdlib')
-rw-r--r--lib/libk/stdlib/linked_list_allocator.c15
-rw-r--r--lib/libk/stdlib/memcpy.c2
-rw-r--r--lib/libk/stdlib/memset.c3
-rw-r--r--lib/libk/stdlib/test_allocator.hh22
-rw-r--r--lib/libk/stdlib/test_linked_list_allocator.cc98
-rw-r--r--lib/libk/stdlib/test_mem.cc29
6 files changed, 161 insertions, 8 deletions
diff --git a/lib/libk/stdlib/linked_list_allocator.c b/lib/libk/stdlib/linked_list_allocator.c
index 66c63d1..bcec580 100644
--- a/lib/libk/stdlib/linked_list_allocator.c
+++ b/lib/libk/stdlib/linked_list_allocator.c
@@ -31,13 +31,14 @@ alloc_init(void *mem, size_t size)
void *
malloc(size_t size)
{
+ struct Chunk *iter;
if (begin == NULL) return NULL;
- // find free chunk that is at least (size + sizeof(struct Chunk))
- for (struct Chunk *iter = begin; iter != NULL; iter = iter->next) {
+ /* find free chunk that is at least (size + sizeof(struct Chunk)) */
+ for (iter = begin; iter != NULL; iter = iter->next) {
if (iter->used != 0 || iter->size < size) continue;
- // if there's at least sizeof(struct Chunk) bytes left over, create a new Chunk
+ /* if there's at least sizeof(struct Chunk) bytes left over, create a new Chunk */
if (iter->size >= (size + 2 * sizeof(struct Chunk))) {
struct Chunk *next = (struct Chunk *)((uintptr_t)iter + sizeof(struct Chunk) + size);
Chunk_ctor(next, iter->size - size - sizeof(struct Chunk));
@@ -57,18 +58,20 @@ malloc(size_t size)
void
free(void *ptr)
{
+ struct Chunk *chunk;
if (ptr == NULL) return;
- struct Chunk *chunk = (struct Chunk *)((uintptr_t)ptr - sizeof(struct Chunk));
+
+ chunk = (struct Chunk *)((uintptr_t)ptr - sizeof(struct Chunk));
chunk->used = 0;
- // merge next chunk
+ /* merge next chunk */
if (chunk->next != NULL && chunk->next->used == 0) {
chunk->size += chunk->next->size + sizeof(struct Chunk);
chunk->next = chunk->next->next;
if (chunk->next != NULL) chunk->next->prev = chunk;
}
- // merge into prev chunk
+ /* merge into prev chunk */
if (chunk->prev != NULL && chunk->prev->used == 0) {
chunk->prev->size += chunk->size + sizeof(struct Chunk);
chunk->prev->next = chunk->next;
diff --git a/lib/libk/stdlib/memcpy.c b/lib/libk/stdlib/memcpy.c
index 90470d5..db7d21e 100644
--- a/lib/libk/stdlib/memcpy.c
+++ b/lib/libk/stdlib/memcpy.c
@@ -1,5 +1,5 @@
void *
-memcpy(void *restrict dest, const void *restrict src, long unsigned n)
+memcpy(void *__restrict__ dest, const void *__restrict__ src, long unsigned n)
{
char *pDest = (char *)dest;
const char *pSrc = (const char *)src;
diff --git a/lib/libk/stdlib/memset.c b/lib/libk/stdlib/memset.c
index a16bd05..2a86f8e 100644
--- a/lib/libk/stdlib/memset.c
+++ b/lib/libk/stdlib/memset.c
@@ -1,7 +1,8 @@
void *
memset(void *s, int c, long unsigned n)
{
+ unsigned i;
char *pDest = (char *)s;
- for (unsigned i = 0; i < n; ++i) pDest[i] = (char)c;
+ for (i = 0; i < n; ++i) pDest[i] = (char)c;
return s;
}
diff --git a/lib/libk/stdlib/test_allocator.hh b/lib/libk/stdlib/test_allocator.hh
new file mode 100644
index 0000000..3bc1715
--- /dev/null
+++ b/lib/libk/stdlib/test_allocator.hh
@@ -0,0 +1,22 @@
+#pragma once
+
+class TestAllocator : public ::testing::Test {
+protected:
+ void
+ SetUp() override
+ {
+ memory = malloc(memory_size);
+ libk::alloc_init(memory, memory_size);
+ ASSERT_EQ(libk::begin, memory);
+ }
+
+ void
+ TearDown() override
+ {
+ free(memory);
+ libk::begin = nullptr;
+ }
+
+ const size_t memory_size = 4096;
+ void *memory = nullptr;
+};
diff --git a/lib/libk/stdlib/test_linked_list_allocator.cc b/lib/libk/stdlib/test_linked_list_allocator.cc
new file mode 100644
index 0000000..5963ce1
--- /dev/null
+++ b/lib/libk/stdlib/test_linked_list_allocator.cc
@@ -0,0 +1,98 @@
+#include <gtest/gtest.h>
+#include <iomanip>
+#include <iostream>
+
+namespace libk {
+#include "linked_list_allocator.c"
+
+std::ostream &
+operator<<(std::ostream &os, const Chunk &b)
+{
+ for (const Chunk *iter = &b; iter != nullptr; iter = iter->next) {
+ os << iter << " used=" << iter->used << " size=" << std::setw(4) << iter->size << " next=" << iter->next
+ << std::endl;
+ }
+ return os;
+}
+}; // namespace libk
+
+#include "test_allocator.hh"
+
+TEST(UninitializedAllocator, malloc) { EXPECT_EQ(libk::malloc(1024), nullptr); }
+
+TEST_F(TestAllocator, mallocMoreThanAvialable)
+{
+ void *ptr = libk::malloc(memory_size);
+ EXPECT_EQ(ptr, nullptr) << *libk::begin;
+}
+
+TEST_F(TestAllocator, mallocExactlyAvialable)
+{
+ void *ptr = libk::malloc(memory_size - sizeof(libk::Chunk));
+ EXPECT_NE(ptr, nullptr) << *libk::begin;
+}
+
+TEST_F(TestAllocator, malloc)
+{
+ libk::Chunk *begin = libk::begin;
+
+ void *ptr0 = libk::malloc(1024);
+ EXPECT_NE(ptr0, nullptr) << *libk::begin;
+ EXPECT_EQ(reinterpret_cast<std::uintptr_t>(ptr0),
+ reinterpret_cast<std::uintptr_t>(libk::begin) + sizeof(libk::Chunk));
+ EXPECT_EQ(begin->used, 1);
+ EXPECT_EQ(begin->size, 1024);
+ ASSERT_NE(begin->next, nullptr);
+ begin = begin->next;
+
+ void *ptr1 = libk::malloc(512);
+ EXPECT_NE(ptr1, nullptr) << *libk::begin;
+ EXPECT_EQ(reinterpret_cast<std::uintptr_t>(ptr1),
+ reinterpret_cast<std::uintptr_t>(libk::begin) + 2 * sizeof(libk::Chunk) + 1024);
+ EXPECT_EQ(begin->used, 1);
+ EXPECT_EQ(begin->size, 512);
+ ASSERT_NE(begin->next, nullptr);
+}
+
+TEST_F(TestAllocator, freeNullptr)
+{
+ void *ptr0 = libk::malloc(1024);
+ EXPECT_NE(ptr0, nullptr) << *libk::begin;
+ void *ptr1 = libk::malloc(512);
+ EXPECT_NE(ptr1, nullptr) << *libk::begin;
+
+ libk::free(nullptr);
+ libk::Chunk *begin = libk::begin;
+ EXPECT_EQ(begin->used, 1);
+ EXPECT_NE(begin->next, nullptr);
+ begin = begin->next;
+ EXPECT_EQ(begin->used, 1);
+ EXPECT_NE(begin->next, nullptr);
+ begin = begin->next;
+ EXPECT_EQ(begin->used, 0);
+ EXPECT_EQ(begin->next, nullptr);
+}
+
+TEST_F(TestAllocator, free)
+{
+ void *ptr0 = libk::malloc(1024);
+ EXPECT_NE(ptr0, nullptr) << *libk::begin;
+ void *ptr1 = libk::malloc(512);
+ EXPECT_NE(ptr1, nullptr) << *libk::begin;
+
+ libk::free(ptr0);
+ libk::Chunk *begin = libk::begin;
+ EXPECT_EQ(begin->used, 0) << ptr0 << ": ptr0" << std::endl << *libk::begin;
+ EXPECT_NE(begin->next, nullptr);
+ begin = begin->next;
+ EXPECT_EQ(begin->used, 1);
+ EXPECT_NE(begin->next, nullptr);
+ begin = begin->next;
+ EXPECT_EQ(begin->used, 0);
+ EXPECT_EQ(begin->next, nullptr);
+
+ libk::free(ptr1);
+ begin = libk::begin;
+ EXPECT_EQ(begin->used, 0) << ptr0 << ": ptr0" << std::endl << *libk::begin;
+ EXPECT_EQ(begin->next, nullptr);
+}
diff --git a/lib/libk/stdlib/test_mem.cc b/lib/libk/stdlib/test_mem.cc
new file mode 100644
index 0000000..f8a5e18
--- /dev/null
+++ b/lib/libk/stdlib/test_mem.cc
@@ -0,0 +1,29 @@
+#include <gtest/gtest.h>
+
+#define restrict __restrict__
+
+namespace libk {
+#include "memcpy.c"
+#include "memset.c"
+} // namespace libk
+
+TEST(mem, memset)
+{
+ auto *buffer = new unsigned char[2048];
+
+ libk::memset(buffer, 0xae, sizeof(buffer));
+ for (unsigned i = 0; i < sizeof(buffer); ++i) EXPECT_EQ(buffer[i], 0xae);
+
+ delete[] buffer;
+}
+
+TEST(mem, memcpy)
+{
+ const unsigned char data[] = {0xde, 0xca, 0xfa, 0xde};
+ auto *buffer = new unsigned char[sizeof(data)];
+
+ memcpy(buffer, data, sizeof(data));
+ for (unsigned i = 0; i < sizeof(data); ++i) EXPECT_EQ(buffer[i], data[i]);
+
+ delete[] buffer;
+}