Add allocator, start work on box

This commit is contained in:
2024-11-19 00:08:33 +01:00
parent 58200ce939
commit d241eaf1b2
16 changed files with 172 additions and 60 deletions

View File

@ -1,8 +1,10 @@
cc_library( cc_library(
name = "asl", name = "asl",
hdrs = [ hdrs = [
"allocator.hpp",
"annotations.hpp", "annotations.hpp",
"assert.hpp", "assert.hpp",
"box.hpp",
"config.hpp", "config.hpp",
"format.hpp", "format.hpp",
"functional.hpp", "functional.hpp",
@ -19,6 +21,7 @@ cc_library(
"utility.hpp", "utility.hpp",
], ],
srcs = [ srcs = [
"allocator.cpp",
"format.cpp", "format.cpp",
"print.cpp", "print.cpp",
], ],
@ -36,6 +39,7 @@ cc_library(
"//asl/testing", "//asl/testing",
], ],
) for name in [ ) for name in [
"box",
"format", "format",
"functional", "functional",
"integers", "integers",

38
asl/allocator.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "asl/allocator.hpp"
#include "asl/assert.hpp"
#include "asl/utility.hpp"
#include "asl/memory.hpp"
#include <cstdlib>
// @Todo zalloc
// @Todo Cookies
// @Todo Debug values
void* asl::GlobalHeap::alloc(const layout& layout)
{
void* ptr = ::_aligned_malloc(
static_cast<size_t>(layout.size),
static_cast<size_t>(layout.align));
ASL_ASSERT(ptr != nullptr); // @Todo panic
return ptr;
}
void* asl::GlobalHeap::realloc(void* old_ptr, const layout& old_layout, const layout& new_layout)
{
if (new_layout.align <= old_layout.align)
{
void* new_ptr = ::realloc(old_ptr, static_cast<size_t>(new_layout.size));
ASL_ASSERT(new_ptr != nullptr); // @Todo panic
return new_ptr;
}
void* new_ptr = alloc(new_layout);
asl::memcpy(new_ptr, old_ptr, asl::min(old_layout.size, new_layout.size));
return new_ptr;
}
void asl::GlobalHeap::dealloc(void* ptr, const layout&)
{
::free(ptr);
}

28
asl/allocator.hpp Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include "asl/layout.hpp"
#include "asl/meta.hpp"
namespace asl
{
template<typename T>
concept allocator = requires(T& alloc, layout layout, void* ptr)
{
{ alloc.alloc(layout) } -> same_as<void*>;
{ alloc.realloc(ptr, layout, layout) } -> same_as<void*>;
alloc.dealloc(ptr, layout);
};
class GlobalHeap
{
public:
static void* alloc(const layout&);
static void* realloc(void* ptr, const layout& old, const layout& new_layout);
static void dealloc(void* ptr, const layout&);
};
static_assert(allocator<GlobalHeap>);
using DefaultAllocator = GlobalHeap;
} // namespace asl

19
asl/box.hpp Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "asl/allocator.hpp"
#include "asl/annotations.hpp"
namespace asl
{
template<is_object T, allocator Allocator = DefaultAllocator>
class box
{
T* m_ptr;
ASL_NO_UNIQUE_ADDRESS Allocator m_alloc;
public:
};
} // namespace asl

View File

@ -4,11 +4,11 @@
#include "asl/memory.hpp" #include "asl/memory.hpp"
void asl::format_internals::format( void asl::format_internals::format(
writer* writer, Writer* writer,
string_view fmt, string_view fmt,
span<const type_erased_arg> args) span<const type_erased_arg> args)
{ {
formatter f(writer); Formatter f(writer);
const auto* arg_it = args.begin(); const auto* arg_it = args.begin();
const auto* arg_end = args.end(); const auto* arg_end = args.end();
@ -74,22 +74,22 @@ void asl::format_internals::format(
f.write(fmt); f.write(fmt);
} }
void asl::AslFormat(formatter& f, const char* str) void asl::AslFormat(Formatter& f, const char* str)
{ {
f.write({str, asl::strlen(str)}); f.write({str, asl::strlen(str)});
} }
void asl::AslFormat(formatter& f, float) void asl::AslFormat(Formatter& f, float)
{ {
f.write("<FLOAT>"); // @Todo Float formatting f.write("<FLOAT>"); // @Todo Float formatting
} }
void asl::AslFormat(formatter& f, double) void asl::AslFormat(Formatter& f, double)
{ {
f.write("<DOUBLE>"); // @Todo Float formatting f.write("<DOUBLE>"); // @Todo Float formatting
} }
void asl::AslFormat(formatter& f, bool v) void asl::AslFormat(Formatter& f, bool v)
{ {
if (v) if (v)
{ {
@ -101,22 +101,22 @@ void asl::AslFormat(formatter& f, bool v)
} }
} }
void asl::AslFormat(formatter& f, uint8_t v) void asl::AslFormat(Formatter& f, uint8_t v)
{ {
AslFormat(f, static_cast<uint64_t>(v)); AslFormat(f, static_cast<uint64_t>(v));
} }
void asl::AslFormat(formatter& f, uint16_t v) void asl::AslFormat(Formatter& f, uint16_t v)
{ {
AslFormat(f, static_cast<uint64_t>(v)); AslFormat(f, static_cast<uint64_t>(v));
} }
void asl::AslFormat(formatter& f, uint32_t v) void asl::AslFormat(Formatter& f, uint32_t v)
{ {
AslFormat(f, static_cast<uint64_t>(v)); AslFormat(f, static_cast<uint64_t>(v));
} }
void asl::AslFormat(formatter& f, uint64_t v) void asl::AslFormat(Formatter& f, uint64_t v)
{ {
static constexpr char s_pairs_storage[] = { static constexpr char s_pairs_storage[] = {
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
@ -180,22 +180,22 @@ void asl::AslFormat(formatter& f, uint64_t v)
f.write(string_view(buffer, kMaxDigits).substr(cursor)); f.write(string_view(buffer, kMaxDigits).substr(cursor));
} }
void asl::AslFormat(formatter& f, int8_t v) void asl::AslFormat(Formatter& f, int8_t v)
{ {
AslFormat(f, static_cast<int64_t>(v)); AslFormat(f, static_cast<int64_t>(v));
} }
void asl::AslFormat(formatter& f, int16_t v) void asl::AslFormat(Formatter& f, int16_t v)
{ {
AslFormat(f, static_cast<int64_t>(v)); AslFormat(f, static_cast<int64_t>(v));
} }
void asl::AslFormat(formatter& f, int32_t v) void asl::AslFormat(Formatter& f, int32_t v)
{ {
AslFormat(f, static_cast<int64_t>(v)); AslFormat(f, static_cast<int64_t>(v));
} }
void asl::AslFormat(formatter& f, int64_t v) void asl::AslFormat(Formatter& f, int64_t v)
{ {
if (v < 0) if (v < 0)
{ {

View File

@ -9,10 +9,10 @@
namespace asl namespace asl
{ {
class formatter; class Formatter;
template<typename T> template<typename T>
concept formattable = requires (formatter& f, const T& value) concept formattable = requires (Formatter& f, const T& value)
{ {
AslFormat(f, value); AslFormat(f, value);
}; };
@ -23,10 +23,10 @@ namespace format_internals
struct type_erased_arg struct type_erased_arg
{ {
const void* data; const void* data;
void (*fn)(formatter&, const void*); void (*fn)(Formatter&, const void*);
template<formattable T> template<formattable T>
static constexpr void erased_fn(formatter& f, const void* data) static constexpr void erased_fn(Formatter& f, const void* data)
{ {
AslFormat(f, *reinterpret_cast<const T*>(data)); AslFormat(f, *reinterpret_cast<const T*>(data));
} }
@ -38,16 +38,16 @@ struct type_erased_arg
{} {}
}; };
void format(writer*, string_view fmt, span<const type_erased_arg> args); void format(Writer*, string_view fmt, span<const type_erased_arg> args);
} // namespace internals } // namespace internals
class formatter class Formatter
{ {
writer* m_writer; Writer* m_writer;
public: public:
explicit constexpr formatter(writer* writer) explicit constexpr Formatter(Writer* writer)
: m_writer{writer} : m_writer{writer}
{} {}
@ -58,7 +58,7 @@ public:
}; };
template<formattable... Args> template<formattable... Args>
void format(writer* w, string_view fmt, const Args&... args) void format(Writer* w, string_view fmt, const Args&... args)
{ {
if constexpr (types_count<Args...> > 0) if constexpr (types_count<Args...> > 0)
{ {
@ -75,26 +75,26 @@ void format(writer* w, string_view fmt, const Args&... args)
} }
template<isize_t N> template<isize_t N>
void AslFormat(formatter& f, const char (&str)[N]) void AslFormat(Formatter& f, const char (&str)[N])
{ {
f.write(str, N - 1); f.write(str, N - 1);
} }
void AslFormat(formatter& f, const char* str); void AslFormat(Formatter& f, const char* str);
void AslFormat(formatter& f, float); void AslFormat(Formatter& f, float);
void AslFormat(formatter& f, double); void AslFormat(Formatter& f, double);
void AslFormat(formatter& f, bool); void AslFormat(Formatter& f, bool);
void AslFormat(formatter& f, uint8_t); void AslFormat(Formatter& f, uint8_t);
void AslFormat(formatter& f, uint16_t); void AslFormat(Formatter& f, uint16_t);
void AslFormat(formatter& f, uint32_t); void AslFormat(Formatter& f, uint32_t);
void AslFormat(formatter& f, uint64_t); void AslFormat(Formatter& f, uint64_t);
void AslFormat(formatter& f, int8_t); void AslFormat(Formatter& f, int8_t);
void AslFormat(formatter& f, int16_t); void AslFormat(Formatter& f, int16_t);
void AslFormat(formatter& f, int32_t); void AslFormat(Formatter& f, int32_t);
void AslFormat(formatter& f, int64_t); void AslFormat(Formatter& f, int64_t);
} // namespace asl } // namespace asl

View File

@ -7,12 +7,12 @@
namespace asl namespace asl
{ {
class writer class Writer
{ {
public: public:
writer() = default; Writer() = default;
ASL_DELETE_COPY_MOVE(writer); ASL_DELETE_COPY_MOVE(Writer);
virtual ~writer() = default; virtual ~Writer() = default;
virtual void write(span<const byte>) = 0; virtual void write(span<const byte>) = 0;
}; };

View File

@ -24,6 +24,12 @@ struct layout
{ {
return layout{ size_of<T>, align_of<T> }; return layout{ size_of<T>, align_of<T> };
} }
template<is_object T>
static constexpr layout array(isize_t size)
{
return layout{ size_of<T> * size, align_of<T> };
}
}; };
} // namespace asl } // namespace asl

View File

@ -15,6 +15,11 @@ constexpr isize_t memcmp(const void* a, const void* b, isize_t size)
return __builtin_memcmp(a, b, static_cast<size_t>(size)); return __builtin_memcmp(a, b, static_cast<size_t>(size));
} }
constexpr void memcpy(void* dst, const void* src, isize_t size)
{
__builtin_memcpy(dst, src, static_cast<size_t>(size));
}
constexpr isize_t strlen(const char* s) constexpr isize_t strlen(const char* s)
{ {
return static_cast<isize_t>(__builtin_strlen(s)); return static_cast<isize_t>(__builtin_strlen(s));

View File

@ -21,10 +21,10 @@ template<typename U, typename V> struct _select_helper<true, U, V>
template<bool kSelect, typename U, typename V> using select_t = _select_helper<kSelect, U, V>::type; template<bool kSelect, typename U, typename V> using select_t = _select_helper<kSelect, U, V>::type;
template<typename U, typename V> struct _is_same_helper : false_type {}; template<typename U, typename V> struct _same_as_helper : false_type {};
template<typename T> struct _is_same_helper<T, T> : true_type {}; template<typename T> struct _same_as_helper<T, T> : true_type {};
template<typename U, typename V> concept same_as = _is_same_helper<U, V>::value && _is_same_helper<V, U>::value; template<typename U, typename V> concept same_as = _same_as_helper<U, V>::value && _same_as_helper<V, U>::value;
template<typename T> auto _as_lref_helper(int) -> id<T&>; template<typename T> auto _as_lref_helper(int) -> id<T&>;
template<typename T> auto _as_lref_helper(...) -> id<T>; template<typename T> auto _as_lref_helper(...) -> id<T>;

View File

@ -3,7 +3,7 @@
#include <cstdio> #include <cstdio>
// @Todo Optimize this, maybe make buffered // @Todo Optimize this, maybe make buffered
class ConsoleWriter : public asl::writer class ConsoleWriter : public asl::Writer
{ {
FILE* m_handle; FILE* m_handle;
@ -18,13 +18,13 @@ public:
} }
}; };
asl::writer* asl::print_internals::get_stdout_writer() asl::Writer* asl::print_internals::get_stdout_writer()
{ {
static ConsoleWriter s_writer{stdout}; static ConsoleWriter s_writer{stdout};
return &s_writer; return &s_writer;
} }
asl::writer* asl::print_internals::get_stderr_writer() asl::Writer* asl::print_internals::get_stderr_writer()
{ {
static ConsoleWriter s_writer{stderr}; static ConsoleWriter s_writer{stderr};
return &s_writer; return &s_writer;

View File

@ -9,8 +9,8 @@ namespace print_internals
{ {
// @Todo Make print writers thread safe // @Todo Make print writers thread safe
writer* get_stdout_writer(); Writer* get_stdout_writer();
writer* get_stderr_writer(); Writer* get_stderr_writer();
} // namespace print_internals } // namespace print_internals

6
asl/tests/box_tests.cpp Normal file
View File

@ -0,0 +1,6 @@
#include "asl/box.hpp"
#include "asl/testing/testing.hpp"
static_assert(sizeof(asl::box<int>) == sizeof(int*));

View File

@ -1,26 +1,25 @@
#include "asl/format.hpp" #include "asl/format.hpp"
#include "asl/testing/testing.hpp" #include "asl/testing/testing.hpp"
#include "asl/print.hpp" #include "asl/allocator.hpp"
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cstdio>
// @Todo Improve this to use our utilities, not the C stdlib
static_assert(asl::formattable<decltype("Hello")>); static_assert(asl::formattable<decltype("Hello")>);
class StringSink : public asl::writer class StringSink : public asl::Writer
{ {
// @Todo Use string, once we have it, or a buffer
isize_t m_current_len{}; isize_t m_current_len{};
char* m_data{}; char* m_data{};
public: public:
void write(asl::span<const asl::byte> str) override void write(asl::span<const asl::byte> str) override
{ {
m_data = (char*)realloc(m_data, (size_t)(m_current_len + str.size())); m_data = reinterpret_cast<char*>(asl::GlobalHeap::realloc(
memcpy(m_data + m_current_len, str.data(), (size_t)str.size()); m_data,
asl::layout::array<char>(m_current_len),
asl::layout::array<char>(m_current_len + str.size())));
asl::memcpy(m_data + m_current_len, str.data(), str.size());
m_current_len += str.size(); m_current_len += str.size();
} }
@ -29,7 +28,7 @@ public:
void reset() void reset()
{ {
m_current_len = 0; m_current_len = 0;
free(m_data); asl::GlobalHeap::dealloc(m_data, asl::layout::array<char>(m_current_len));
m_data = nullptr; m_data = nullptr;
} }
}; };

View File

@ -35,6 +35,7 @@ static_assert(!asl::trivially_copy_constructible<NonCopyConstructible>);
static_assert(asl::move_constructible<int>); static_assert(asl::move_constructible<int>);
static_assert(asl::move_constructible<TriviallyMoveConstructible>); static_assert(asl::move_constructible<TriviallyMoveConstructible>);
static_assert(asl::move_constructible<MoveConstructible>); static_assert(asl::move_constructible<MoveConstructible>);
static_assert(asl::move_constructible<CopyConstructible>);
static_assert(!asl::move_constructible<NonMoveConstructible>); static_assert(!asl::move_constructible<NonMoveConstructible>);
static_assert(asl::trivially_move_constructible<int>); static_assert(asl::trivially_move_constructible<int>);

View File

@ -24,6 +24,12 @@ constexpr U bit_cast(T value) requires (size_of<T> == size_of<U>)
return __builtin_bit_cast(U, value); return __builtin_bit_cast(U, value);
} }
template<typename T>
T min(T a, T b)
{
return (a <= b) ? a : b;
}
#define ASL_DELETE_COPY(T) \ #define ASL_DELETE_COPY(T) \
T(const T&) = delete; \ T(const T&) = delete; \
T& operator=(const T&) = delete; T& operator=(const T&) = delete;