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(
name = "asl",
hdrs = [
"allocator.hpp",
"annotations.hpp",
"assert.hpp",
"box.hpp",
"config.hpp",
"format.hpp",
"functional.hpp",
@ -19,6 +21,7 @@ cc_library(
"utility.hpp",
],
srcs = [
"allocator.cpp",
"format.cpp",
"print.cpp",
],
@ -36,6 +39,7 @@ cc_library(
"//asl/testing",
],
) for name in [
"box",
"format",
"functional",
"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"
void asl::format_internals::format(
writer* writer,
Writer* writer,
string_view fmt,
span<const type_erased_arg> args)
{
formatter f(writer);
Formatter f(writer);
const auto* arg_it = args.begin();
const auto* arg_end = args.end();
@ -74,22 +74,22 @@ void asl::format_internals::format(
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)});
}
void asl::AslFormat(formatter& f, float)
void asl::AslFormat(Formatter& f, float)
{
f.write("<FLOAT>"); // @Todo Float formatting
}
void asl::AslFormat(formatter& f, double)
void asl::AslFormat(Formatter& f, double)
{
f.write("<DOUBLE>"); // @Todo Float formatting
}
void asl::AslFormat(formatter& f, bool v)
void asl::AslFormat(Formatter& f, bool 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));
}
void asl::AslFormat(formatter& f, uint16_t v)
void asl::AslFormat(Formatter& f, uint16_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));
}
void asl::AslFormat(formatter& f, uint64_t v)
void asl::AslFormat(Formatter& f, uint64_t v)
{
static constexpr char s_pairs_storage[] = {
'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));
}
void asl::AslFormat(formatter& f, int8_t v)
void asl::AslFormat(Formatter& f, int8_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));
}
void asl::AslFormat(formatter& f, int32_t v)
void asl::AslFormat(Formatter& f, int32_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)
{

View File

@ -9,10 +9,10 @@
namespace asl
{
class formatter;
class Formatter;
template<typename T>
concept formattable = requires (formatter& f, const T& value)
concept formattable = requires (Formatter& f, const T& value)
{
AslFormat(f, value);
};
@ -23,10 +23,10 @@ namespace format_internals
struct type_erased_arg
{
const void* data;
void (*fn)(formatter&, const void*);
void (*fn)(Formatter&, const void*);
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));
}
@ -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
class formatter
class Formatter
{
writer* m_writer;
Writer* m_writer;
public:
explicit constexpr formatter(writer* writer)
explicit constexpr Formatter(Writer* writer)
: m_writer{writer}
{}
@ -58,7 +58,7 @@ public:
};
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)
{
@ -75,26 +75,26 @@ void format(writer* w, string_view fmt, const Args&... args)
}
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);
}
void AslFormat(formatter& f, const char* str);
void AslFormat(Formatter& f, const char* str);
void AslFormat(formatter& f, float);
void AslFormat(formatter& f, double);
void AslFormat(Formatter& f, float);
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, uint16_t);
void AslFormat(formatter& f, uint32_t);
void AslFormat(formatter& f, uint64_t);
void AslFormat(Formatter& f, uint8_t);
void AslFormat(Formatter& f, uint16_t);
void AslFormat(Formatter& f, uint32_t);
void AslFormat(Formatter& f, uint64_t);
void AslFormat(formatter& f, int8_t);
void AslFormat(formatter& f, int16_t);
void AslFormat(formatter& f, int32_t);
void AslFormat(formatter& f, int64_t);
void AslFormat(Formatter& f, int8_t);
void AslFormat(Formatter& f, int16_t);
void AslFormat(Formatter& f, int32_t);
void AslFormat(Formatter& f, int64_t);
} // namespace asl

View File

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

View File

@ -24,6 +24,12 @@ struct layout
{
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

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));
}
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)
{
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<typename U, typename V> struct _is_same_helper : false_type {};
template<typename T> struct _is_same_helper<T, T> : true_type {};
template<typename U, typename V> struct _same_as_helper : false_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(...) -> id<T>;

View File

@ -3,7 +3,7 @@
#include <cstdio>
// @Todo Optimize this, maybe make buffered
class ConsoleWriter : public asl::writer
class ConsoleWriter : public asl::Writer
{
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};
return &s_writer;
}
asl::writer* asl::print_internals::get_stderr_writer()
asl::Writer* asl::print_internals::get_stderr_writer()
{
static ConsoleWriter s_writer{stderr};
return &s_writer;

View File

@ -9,8 +9,8 @@ namespace print_internals
{
// @Todo Make print writers thread safe
writer* get_stdout_writer();
writer* get_stderr_writer();
Writer* get_stdout_writer();
Writer* get_stderr_writer();
} // 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/testing/testing.hpp"
#include "asl/print.hpp"
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cstdio>
// @Todo Improve this to use our utilities, not the C stdlib
#include "asl/allocator.hpp"
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{};
char* m_data{};
public:
void write(asl::span<const asl::byte> str) override
{
m_data = (char*)realloc(m_data, (size_t)(m_current_len + str.size()));
memcpy(m_data + m_current_len, str.data(), (size_t)str.size());
m_data = reinterpret_cast<char*>(asl::GlobalHeap::realloc(
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();
}
@ -29,7 +28,7 @@ public:
void reset()
{
m_current_len = 0;
free(m_data);
asl::GlobalHeap::dealloc(m_data, asl::layout::array<char>(m_current_len));
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<TriviallyMoveConstructible>);
static_assert(asl::move_constructible<MoveConstructible>);
static_assert(asl::move_constructible<CopyConstructible>);
static_assert(!asl::move_constructible<NonMoveConstructible>);
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);
}
template<typename T>
T min(T a, T b)
{
return (a <= b) ? a : b;
}
#define ASL_DELETE_COPY(T) \
T(const T&) = delete; \
T& operator=(const T&) = delete;