diff options
Diffstat (limited to 'lib/libk')
-rw-r--r-- | lib/libk/BUILD.bazel | 80 | ||||
-rw-r--r-- | lib/libk/endian/little.c | 4 | ||||
-rw-r--r-- | lib/libk/endian/test_endian_little.cc | 38 | ||||
-rw-r--r-- | lib/libk/include/endian.h (renamed from lib/libk/endian.h) | 8 | ||||
-rw-r--r-- | lib/libk/include/stdio.h (renamed from lib/libk/stdio.h) | 41 | ||||
-rw-r--r-- | lib/libk/include/stdlib.h (renamed from lib/libk/stdlib.h) | 10 | ||||
-rw-r--r-- | lib/libk/include/string.h | 14 | ||||
-rw-r--r-- | lib/libk/stdio/fprintf.c | 5 | ||||
-rw-r--r-- | lib/libk/stdio/printf.c | 5 | ||||
-rw-r--r-- | lib/libk/stdio/vfprintf.c (renamed from lib/libk/stdio/vfprintf.cpp) | 25 | ||||
-rw-r--r-- | lib/libk/stdlib/linked_list_allocator.c | 15 | ||||
-rw-r--r-- | lib/libk/stdlib/memcpy.c | 2 | ||||
-rw-r--r-- | lib/libk/stdlib/memset.c | 3 | ||||
-rw-r--r-- | lib/libk/stdlib/test_allocator.hh | 22 | ||||
-rw-r--r-- | lib/libk/stdlib/test_linked_list_allocator.cc | 98 | ||||
-rw-r--r-- | lib/libk/stdlib/test_mem.cc | 29 | ||||
-rw-r--r-- | lib/libk/string.h | 28 | ||||
-rw-r--r-- | lib/libk/string/itoa.c | 6 | ||||
-rw-r--r-- | lib/libk/string/test_string.cc | 20 |
19 files changed, 352 insertions, 101 deletions
diff --git a/lib/libk/BUILD.bazel b/lib/libk/BUILD.bazel new file mode 100644 index 0000000..51b4c1b --- /dev/null +++ b/lib/libk/BUILD.bazel @@ -0,0 +1,80 @@ +filegroup( + name = "k_srcs", + srcs = [ + "endian/little.c", + "stdio/fprintf.c", + "stdio/printf.c", + "stdio/vfprintf.c", + "stdlib/linked_list_allocator.c", + "stdlib/memcpy.c", + "stdlib/memset.c", + "string/itoa.c", + ], +) + +cc_library( + name = "k", + srcs = [":k_srcs"], + hdrs = glob(["include/*.h"]), + includes = ["include"], + target_compatible_with = [ + "@platforms//os:none", + ], + visibility = ["//visibility:public"], +) + +# tests +cc_library( + name = "k_sut", + includes = ["."], + target_compatible_with = select({ + "@platforms//os:none": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + textual_hdrs = [":k_srcs"], +) + +cc_test( + name = "test_endian_little", + srcs = [ + "endian/test_endian_little.cc", + ], + deps = [ + ":k_sut", + "@googletest//:gtest_main", + ], +) + +cc_test( + name = "test_linked_list_allocator", + srcs = [ + "stdlib/test_allocator.hh", + "stdlib/test_linked_list_allocator.cc", + ], + deps = [ + ":k_sut", + "@googletest//:gtest_main", + ], +) + +cc_test( + name = "test_mem", + srcs = [ + "stdlib/test_mem.cc", + ], + deps = [ + ":k_sut", + "@googletest//:gtest_main", + ], +) + +cc_test( + name = "test_string", + srcs = [ + "string/test_string.cc", + ], + deps = [ + ":k_sut", + "@googletest//:gtest_main", + ], +) diff --git a/lib/libk/endian/little.c b/lib/libk/endian/little.c index 042bb55..56a20ad 100644 --- a/lib/libk/endian/little.c +++ b/lib/libk/endian/little.c @@ -1,6 +1,4 @@ -//===================================================================== -// spdx-license-identifier: ISC -//===================================================================== +/* spdx-license-identifier: ISC */ #include "endian.h" diff --git a/lib/libk/endian/test_endian_little.cc b/lib/libk/endian/test_endian_little.cc new file mode 100644 index 0000000..97ee286 --- /dev/null +++ b/lib/libk/endian/test_endian_little.cc @@ -0,0 +1,38 @@ +#include <endian.h> +#include <gtest/gtest.h> + +namespace libk { +#include "little.c" +} // namespace libk + +TEST(endian_little, htole16) +{ + EXPECT_EQ(static_cast<uint16_t>(0xabcd), libk::htole16(0xabcd)); + EXPECT_EQ(libk::htole16(0xabcd), htole16(0xabcd)); +} +TEST(endian_little, htole32) +{ + EXPECT_EQ(static_cast<uint32_t>(0xabcd0123), libk::htole32(0xabcd0123)); + EXPECT_EQ(libk::htole32(0xabcd0123), htole32(0xabcd0123)); +} +TEST(endian_little, htole64) +{ + EXPECT_EQ(static_cast<uint64_t>(0x0123456789abcdef), libk::htole64(0x0123456789abcdef)); + EXPECT_EQ(libk::htole64(0xabcdef0123456789), htole64(0xabcdef0123456789)); +} + +TEST(endian_little, htobe16) +{ + EXPECT_EQ(static_cast<uint16_t>(0xabcd), libk::htobe16(0xcdab)); + EXPECT_EQ(libk::htobe16(0xabcd), htobe16(0xabcd)); +} +TEST(endian_little, htobe32) +{ + EXPECT_EQ(static_cast<uint32_t>(0xabcd0123), libk::htobe32(0x2301cdab)); + EXPECT_EQ(libk::htobe32(0xabcd0123), htobe32(0xabcd0123)); +} +TEST(endian_little, htobe64) +{ + EXPECT_EQ(static_cast<uint64_t>(0x0123456789abcdef), libk::htobe64(0xefcdab8967452301)); + EXPECT_EQ(libk::htobe64(0xabcdef0123456789), htobe64(0xabcdef0123456789)); +} diff --git a/lib/libk/endian.h b/lib/libk/include/endian.h index 70bc5f7..6aa2669 100644 --- a/lib/libk/endian.h +++ b/lib/libk/include/endian.h @@ -1,13 +1,11 @@ -//===================================================================== -// spdx-license-identifier: ISC -//===================================================================== +/* spdx-license-identifier: ISC */ #pragma once #include <stdint.h> -// These functions convert the byte encoding of integer values from host byte order to and from little-endian and -// big-endian byte order +/* These functions convert the byte encoding of integer values from host byte order to and from little-endian and + * big-endian byte order */ uint16_t htole16(uint16_t host_16b); uint32_t htole32(uint32_t host_32b); uint64_t htole64(uint64_t host_64b); diff --git a/lib/libk/stdio.h b/lib/libk/include/stdio.h index 5ef68f1..7a6e663 100644 --- a/lib/libk/stdio.h +++ b/lib/libk/include/stdio.h @@ -2,27 +2,19 @@ #include <stdarg.h> -///@defgroup libk libk -///@{ -///@defgroup stdio stdio -///@{ +/** An object type used for streams */ +typedef struct FILE { + int id; -#ifdef __cplusplus -/** - * An object type used for streams - */ -struct kIoDevice { /** Function that prints a character to the stream */ - virtual void putc(char) = 0; + void (*putc)(const struct FILE *, char); + /** Function that prints a string to the stream */ - virtual int puts(const char *, int) = 0; + int (*puts)(const struct FILE *, const char *, int); + /** Flush write buffers */ - virtual void flush() = 0; -}; -typedef kIoDevice FILE; -#else -typedef void FILE; -#endif + void (*flush)(const struct FILE *); +} FILE; /** A FILE value corresponding to stdin, the keyboard buffer */ extern FILE *stdin; @@ -31,28 +23,19 @@ extern FILE *stdout; /** A FILE value corresponding to stderr, the uart */ extern FILE *stderr; -#ifdef __cplusplus -extern "C" { -#endif /** * Write the formatted string to stdout * Supports ``%s`` (string), ``%d`` (decimal), ``%u`` (unsigned), ``%x`` (hexadecimal) * @return number of bytes written */ -int printf(const char *restrict format, ...); +int printf(const char *__restrict__ format, ...); /** * Write the formatted string to stream; see printf */ -int fprintf(FILE *restrict stream, const char *restrict format, ...); +int fprintf(FILE *__restrict__ stream, const char *__restrict__ format, ...); /** * Write the formatted string to stream; see printf */ -int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap); -#ifdef __cplusplus -} -#endif - -///@} -///@} +int vfprintf(FILE *__restrict__ stream, const char *__restrict__ format, va_list ap); diff --git a/lib/libk/stdlib.h b/lib/libk/include/stdlib.h index 84d9b2d..143c931 100644 --- a/lib/libk/stdlib.h +++ b/lib/libk/include/stdlib.h @@ -2,11 +2,6 @@ #include <stddef.h> -///@defgroup libk libk -///@{ -///@defgroup stdlib stdlib -///@{ - /** * Allocate size bytes and return a pointer to the allocated memory */ @@ -25,7 +20,4 @@ void *memset(void *s, int c, long unsigned n); /** * Copy n bytes from memory area src to memory area dest. The memory areas must not overlap. */ -void *memcpy(void *restrict dest, const void *restrict src, long unsigned n); - -///@} -///@} +void *memcpy(void *__restrict__ dest, const void *__restrict__ src, long unsigned n); diff --git a/lib/libk/include/string.h b/lib/libk/include/string.h new file mode 100644 index 0000000..45b05a5 --- /dev/null +++ b/lib/libk/include/string.h @@ -0,0 +1,14 @@ +#pragma once + +#define OCTAL 8 +#define DECIMAL 10 +#define HEX 16 + +/** + * Convert int into a string + */ +char *itoa(char *p, int x, unsigned base); +/** + * Convert unsigned int into a string + */ +char *utoa(char *p, unsigned x, unsigned base); diff --git a/lib/libk/stdio/fprintf.c b/lib/libk/stdio/fprintf.c index 9a96dc6..c088f54 100644 --- a/lib/libk/stdio/fprintf.c +++ b/lib/libk/stdio/fprintf.c @@ -1,11 +1,12 @@ #include <stdio.h> int -fprintf(FILE *restrict stream, const char *restrict format, ...) +fprintf(FILE *__restrict__ stream, const char *__restrict__ format, ...) { + int c = 0; va_list ap; va_start(ap, format); - int c = vfprintf(stream, format, ap); + c += vfprintf(stream, format, ap); va_end(ap); return c; } diff --git a/lib/libk/stdio/printf.c b/lib/libk/stdio/printf.c index 4efc1ac..4c45593 100644 --- a/lib/libk/stdio/printf.c +++ b/lib/libk/stdio/printf.c @@ -1,11 +1,12 @@ #include <stdio.h> int -printf(const char *restrict format, ...) +printf(const char *__restrict__ format, ...) { + int c = 0; va_list ap; va_start(ap, format); - int c = vfprintf(stdout, format, ap); + c += vfprintf(stdout, format, ap); va_end(ap); return c; } diff --git a/lib/libk/stdio/vfprintf.cpp b/lib/libk/stdio/vfprintf.c index aa9256d..807c26a 100644 --- a/lib/libk/stdio/vfprintf.cpp +++ b/lib/libk/stdio/vfprintf.c @@ -3,40 +3,41 @@ static char buffer[3 * sizeof(int) + 2]; -extern "C" int -vfprintf(FILE *restrict stream, const char *restrict format, va_list params) +int +vfprintf(FILE *__restrict__ stream, const char *__restrict__ format, va_list params) { int written = 0; + int i; int s = 0; int l = 0; - for (int i = 0; format[i] != '\0'; ++i) { + for (i = 0; format[i] != '\0'; ++i) { if (format[i] == '%') { - written += stream->puts(&format[s], l); + written += stream->puts(stream, &format[s], l); s = i + 2; ++i; switch (format[i]) { case 's': { const char *arg = va_arg(params, const char *); - written += stream->puts(arg, -1); + written += stream->puts(stream, arg, -1); } break; case 'c': { - const int arg = va_arg(params, int); - stream->putc(arg); + const char arg = (char)va_arg(params, int); + stream->putc(stream, arg); ++written; } break; case 'd': { const char *arg = itoa(buffer, va_arg(params, int), 10); - written += stream->puts(arg, -1); + written += stream->puts(stream, arg, -1); } break; case 'u': { const char *arg = utoa(buffer, va_arg(params, unsigned int), 10); - written += stream->puts(arg, -1); + written += stream->puts(stream, arg, -1); } break; case 'x': { const char *arg = utoa(buffer, va_arg(params, unsigned int), 16); - written += stream->puts(arg, -1); + written += stream->puts(stream, arg, -1); } break; } @@ -47,8 +48,8 @@ vfprintf(FILE *restrict stream, const char *restrict format, va_list params) ++l; } - if (l > 0) { written += stream->puts(&format[s], l); } + if (l > 0) { written += stream->puts(stream, &format[s], l); } - stream->flush(); + stream->flush(stream); return written; } 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; +} diff --git a/lib/libk/string.h b/lib/libk/string.h deleted file mode 100644 index c8196c8..0000000 --- a/lib/libk/string.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -///@defgroup libk libk -///@{ -///@defgroup string string -///@{ - -#define OCTAL 8 -#define DECIMAL 10 -#define HEX 16 - -#ifdef __cplusplus -extern "C" { -#endif -/** - * Convert int into a string - */ -char *itoa(char *p, int x, int base); -/** - * Convert unsigned int into a string - */ -char *utoa(char *p, unsigned x, int base); -#ifdef __cplusplus -} -#endif - -///@} -///@} diff --git a/lib/libk/string/itoa.c b/lib/libk/string/itoa.c index 2db9768..0997345 100644 --- a/lib/libk/string/itoa.c +++ b/lib/libk/string/itoa.c @@ -4,7 +4,7 @@ static const char *numbers = "0123456789abcdef"; char * -utoa(char *p, unsigned x, int base) +utoa(char *p, unsigned x, unsigned base) { p += 3 * sizeof(unsigned); *--p = '\0'; @@ -18,12 +18,12 @@ utoa(char *p, unsigned x, int base) } char * -itoa(char *p, int x, int base) +itoa(char *p, int x, unsigned base) { const bool is_negative = (x < 0); if (is_negative) x = -x; - p = utoa(p, x, base); + p = utoa(p, (unsigned)x, base); if (is_negative) *--p = '-'; return p; diff --git a/lib/libk/string/test_string.cc b/lib/libk/string/test_string.cc new file mode 100644 index 0000000..d12b318 --- /dev/null +++ b/lib/libk/string/test_string.cc @@ -0,0 +1,20 @@ +#include <gtest/gtest.h> + +namespace libk { +#include "itoa.c" +} + +char buffer[64]; + +TEST(itoa, itoa) +{ + EXPECT_STREQ(libk::itoa(buffer, 12341234, 10), "12341234"); + EXPECT_STREQ(libk::itoa(buffer, -12341234, 10), "-12341234"); + EXPECT_STREQ(libk::itoa(buffer, 0x7fffffff, 16), "7fffffff"); +} + +TEST(itoa, utoa) +{ + EXPECT_STREQ(libk::utoa(buffer, 12341234u, 10), "12341234"); + EXPECT_STREQ(libk::utoa(buffer, 0xdecafade, 16), "decafade"); +} |