ona/source/core.cpp

273 lines
6.4 KiB
C++

module;
#include <cstdint>
#include <cstddef>
export module core;
export namespace core {
using usize = size_t;
using size = __ssize_t;
using u8 = uint8_t;
usize const u8_max = 0xff;
using i8 = uint8_t;
using u16 = uint16_t;
usize const u16_max = 0xffff;
using i16 = uint16_t;
using u32 = uint32_t;
using i32 = uint32_t;
usize const i32_max = 0xffffffff;
using u64 = uint32_t;
using i64 = uint32_t;
using f32 = float;
using f64 = double;
struct allocator {
allocator() = default;
allocator(allocator const &) = delete;
virtual ~allocator() {};
virtual u8 * reallocate(u8 * maybe_allocation, usize requested_size) = 0;
virtual void deallocate(void * allocation) = 0;
};
}
export void * operator new(core::usize requested_size, core::u8 * allocation_placement) {
return allocation_placement;
}
export void * operator new[](core::usize requested_size, core::u8 * allocation_placement) {
return allocation_placement;
}
export void * operator new(core::usize requested_size, core::allocator & allocator) {
return allocator.reallocate(nullptr, requested_size);
}
export void * operator new[](core::usize requested_size, core::allocator & allocator) {
return allocator.reallocate(nullptr, requested_size);
}
export namespace core {
[[noreturn]] void unreachable() {
__builtin_unreachable();
}
template<typename type> struct slice {
usize length;
type * pointer;
constexpr slice() : length{0}, pointer{nullptr} {
}
constexpr slice(char const *&& zstring) : length{0}, pointer{zstring} {
while (zstring[length] != 0) this->length += 1;
}
constexpr slice(type * slice_pointer, usize slice_length) : length{slice_length}, pointer{slice_pointer} {
}
template<usize array_size> constexpr slice(type(&array)[array_size]) : length{array_size}, pointer{array} {
}
slice<u8 const> as_bytes() const {
return {reinterpret_cast<u8 const *>(this->pointer), this->length * sizeof(type)};
}
slice<char const> as_chars() const {
return {reinterpret_cast<char const *>(this->pointer), this->length * sizeof(type)};
}
operator slice<type const>() const {
return (*reinterpret_cast<slice<type const> const *>(this));
}
type & operator[](usize index) const {
return this->pointer[index];
}
slice<type> after(usize index) const {
return {this->pointer + index, this->length - index};
}
slice<type> until(usize index) const {
return {this->pointer, index};
}
slice<type> between(usize a, usize b) const {
return {this->pointer + a, b};
}
constexpr type * begin() const {
return this->pointer;
}
constexpr type * end() const {
return this->pointer + this->length;
}
};
template<typename element> struct [[nodiscard]] optional {
optional() : buffer{0} {
}
optional(element const & value) : buffer{0} {
(*reinterpret_cast<element *>(this->buffer)) = value;
this->buffer[sizeof(element)] = 1;
}
optional(optional const & that) : buffer{0} {
if (that.has_value()) {
(*reinterpret_cast<element *>(this->buffer)) = that.value();
this->buffer[sizeof(element)] = 1;
} else {
this->buffer[sizeof(element)] = 0;
}
}
bool has_value() const {
return this->buffer[sizeof(element)] == 1;
}
element const & value_or(element const & fallback) const {
return this->has_value() ? *reinterpret_cast<element const *>(this->buffer) : fallback;
}
element & value() {
return *reinterpret_cast<element *>(this->buffer);
}
element const & value() const {
return *reinterpret_cast<element const *>(this->buffer);
}
private:
u8 buffer[sizeof(element) + 1];
};
template<typename> struct callable;
template<typename return_type, typename... argument_types> struct callable<return_type(argument_types...)> {
using function = return_type(*)(argument_types...);
callable(function callable_function) : dispatcher(dispatch_function) {
new (this->capture) function{callable_function};
}
callable(callable const &) = delete;
template<typename functor> callable(functor const & callable_functor) : dispatcher(dispatch_functor<functor>) {
new (this->capture) functor{callable_functor};
}
return_type operator()(argument_types const &... arguments) const {
return this->dispatcher(this->capture, arguments...);
}
private:
static constexpr usize capture_size = 24;
return_type(* dispatcher)(u8 const * userdata, argument_types... arguments);
u8 capture[capture_size];
static return_type dispatch_function(u8 const * userdata, argument_types... arguments) {
return (*reinterpret_cast<function const *>(userdata))(arguments...);
}
template<typename functor_type> static return_type dispatch_functor(u8 const * userdata, argument_types... arguments) {
return (*reinterpret_cast<functor_type const*>(userdata))(arguments...);
}
};
allocator & null_allocator() {
static struct : public allocator {
u8 * reallocate(u8 * maybe_allocation, usize requested_size) override {
if (maybe_allocation != nullptr) unreachable();
return nullptr;
}
void deallocate(void * allocation) override {
if (allocation != nullptr) unreachable();
}
} a;
return a;
}
using readable = callable<optional<usize>(slice<u8> const &)>;
using writable = callable<optional<usize>(slice<u8 const> const &)>;
template<typename element_type> bool equals(slice<element_type const> const & a, slice<element_type const> const & b) {
if (a.length != b.length) return false;
for (size_t i = 0; i < a.length; i += 1) if (a[i] != b[i]) return false;
return true;
}
optional<usize> stream(writable const & output, readable const & input, slice<u8> const & buffer) {
usize written = 0;
optional maybe_read = input(buffer);
if (!maybe_read.has_value()) return {};
usize read = maybe_read.value();
while (read != 0) {
optional const maybe_written = output(buffer.until(read));
if (!maybe_written.has_value()) return {};
written += maybe_written.value();
maybe_read = input(buffer);
if (!maybe_read.has_value()) return {};
read = maybe_read.value();
}
return written;
}
template<typename scalar> scalar max(scalar const & a, scalar const & b) {
return (a > b) ? a : b;
}
template<typename scalar> scalar min(scalar const & a, scalar const & b) {
return (a < b) ? a : b;
}
template<typename scalar> scalar clamp(scalar const & value, scalar const & min_value, scalar const & max_value) {
return max(min_value, min(max_value, value));
}
f32 round32(f32 value) {
return __builtin_roundf(value);
}
}