diff --git a/Makefile b/Makefile index dd5e43b..196b51f 100644 --- a/Makefile +++ b/Makefile @@ -13,9 +13,9 @@ SRC_CXX = $(shell find -O2 $(SRC)/ -type f -name \*.cpp -or -name \*.cxx) INCLUDE=include # Link to these libraries dynamicalls -SHARED_LIBS= +SHARED_LIBS=ssl sodium pthread # Link to these libraries statically -STATIC_LIBS= +STATIC_LIBS=fmt override __COMMA=, override __VERSION_SPLIT:= $(subst ., ,$(VERSION)) diff --git a/include/alloc.h b/include/alloc.h new file mode 100644 index 0000000..16e7d6c --- /dev/null +++ b/include/alloc.h @@ -0,0 +1,52 @@ +//! Custom allocation framekwork for frozen (RO) and/or secure allocations, shared allocations, aliased allocation, etc. (polymorphic.) +#ifndef _ALLOC_H +#define _ALLOC_H + +#ifdef __cplusplus +#include +#endif + +#include "types.h" +#include "macros.h" + +LINK_START(C) +typedef struct base_allocator alloc_t; + +//TODO: C API anonlogue for allocator interface below. + +LINK_END + +#if $CXX +extern "C" { + struct base_allocator { + //TODO: Allocator interface... + virtual ~base_allocator(); + } +} +namespace alloc { + class FrozenAllocator : public alloc_t { + struct _impl; + protected: + struct anon_raw_secmem; + /*struct anon_raw_secmem::deleter { + operator + };*/ + struct alloc_info; + struct alloc_value; + public: + template + FrozenAllocator(FrozenAllocator &&) noexcept; + FrozenAllocator& operator=(FrozenAllocator &&); + + FrozenAllocator(const FrozenAllocator&) = delete; + FrozenAllocator& operator=(const FrozenAllocator&) = delete; + virtual ~FrozenAllocator(); + private: + std::unique_ptr<_impl> inner_; + //std::shared_ptr m_manager; + //std::map> m_values; + }; +} +#endif + +#endif /* _ALLOC_H */ diff --git a/include/borrow.hh b/include/borrow.hh new file mode 100644 index 0000000..cb313a1 --- /dev/null +++ b/include/borrow.hh @@ -0,0 +1,22 @@ +#pragma once + +#include "constraints.hh" + +namespace borrow { +#if 0 +//TODO: Eh, rethink this when brain not fogged... + template P = T*> + struct Borrow { + using traits = std::pointer_traits

; + + using type = T; + using pointer_type = P; + using pointer = traits::pointer; + + + static_assert(std::is_same_v, "Invalid `deref_to P` (element_type != T)"); + + + }; +#endif +} diff --git a/include/constraints.hh b/include/constraints.hh new file mode 100644 index 0000000..ce30d3c --- /dev/null +++ b/include/constraints.hh @@ -0,0 +1,103 @@ +#pragma once + +#include +#include +#include + +#include "macros.hh" + +namespace where { +#if 0 +//XXX: I think this is fine? auto&& rvalue references seem to bind to const& references anyway? + constexpr auto const& as_const( auto& t ) noexcept { return std::as_const(FORWARD(t)); } + + constexpr auto const&& as_const( auto&& t ) noexcept { + using T = decltype(t); + static_assert(!std::is_reference_t, "Bad decltype(auto&&)"); + + return static_cast&&>(t); + } +#endif + template + using add_const_reference_t = decltype((std::as_const(std::declval()))); + + template + using add_const_pointer_t = decltype(std::addressof(std::as_const(std::declval()))); + + static_assert( + std::is_lvalue_reference_v> + and std::is_lvalue_reference_v> + and std::is_lvalue_reference_v + and std::is_lvalue_reference_v + and std::is_same_v + < add_const_reference_t&> + , std::unique_ptr const& + > + , "add_const_reference_t is not perfectly forwarding"); + template + concept pointer_like = requires { + typename std::pointer_traits

; + typename std::pointer_traits

::element_type; + typename std::pointer_traits

::pointer; + }; + + template + concept deref_to = pointer_like

+ and requires(P ptr) { + // element type can be assigned to `T`. + requires(std::is_convertible_v::element_type, T>); + + // Dereferencing the pointer can be assigned to `T`. + { *ptr } noexcept(Noexcept) -> std::convertible_to::element_type>; + + //{ ptr <=> nullptr } noexcept(Noexcept) -> std::convertible_to< + +// { std::as_const(*ptr) } noexcept(Noexcept) -> std::convertible_to>; +// { std::addressof(value) } -> std::convertible_to::pointer>; + }; + + template + concept may_deref_to = deref_to + and requires(P ptr) { + // The pointer is nullable + { ptr } noexcept(Noexcept) -> std::convertible_to; + { !ptr } noexcept(Noexcept) -> std::convertible_to; + + // The pointer can be constructed from `nullptr`. + //{ nullptr } noexcept(Noexcept) -> std::convertible_to

; + + // The pointer can be assigned `nullptr`. + //{ ptr = nullptr } noexcept(Noexcept); + + // The pointer is orderable. + //{ ptr == ptr } noexcept(Noexcept) -> std::convertible_to; + //{ ptr != ptr } noexcept(Noexcept) -> std::convertible_to; + + // The pointer is null-comparable + { ptr == nullptr } noexcept(Noexcept) -> std::convertible_to; + { ptr != nullptr } noexcept(Noexcept) -> std::convertible_to; + }; + // { std::as_const(*ptr) } noexcept -> std::convertible_to>; + // { std::addressof(value) } noexcept -> std::convertible_to

; + /*requires(std::is_convertible_v + < add_const_reference_t< std::pointer_traits

::element_type > + , add_const_reference_t< T > + >); + { std::as_const(*std::declval::pointer>()) } + -> std::convertible_to::element_type>; + //std::convertible_to< add_const_pointer_t<*/ + //}; + +#if 0 + (std::is_pointer_v

&& + // P = ?* + requires(P ptr) { + { ptr } -> std::convertible_to; + { static_cast(ptr) }; + } + ) + or requires(P ptr, T value) { + + }; +#endif +} diff --git a/include/error.hh b/include/error.hh new file mode 100644 index 0000000..c20c917 --- /dev/null +++ b/include/error.hh @@ -0,0 +1,20 @@ + +#include "macros.hh" + +namespace error { + struct Error { + DEFINE_INTERFACE(Error); + constexpr Error() noexcept = default; + + constexpr operator std::string_view() const noexcept { return message(); } + + constexpr virtual std::string_view message() const noexcept =0; + constexpr virtual Error const* inner() const noexcept { return nullptr; } + + // TODO: `borrow::Borrow (using std::pointer_traits<>) PtrType = T*>` (borrow.hh): essentially specialised `std::variant` + constexpr virtual borrow::Borrow report() const& { return borrow::Borrow{ nullptr }; } +// constexpr virtual borrow::Borrow report() & { return borrow::Borrow{ nullptr }; } + constexpr virtual borrow::Borrow report() & { return borrow::Borrow{ nullptr }; } + constexpr virtual borrow::Borrow:into_owned_t report() && { return borrow::Borrow{ nullptr }.into_owned(); } // <- Will initialise with `into_owned() &&` member function, which `std::move()`s the value from the pointer instead of just copying the pointer. XXX: How do we actually want this borrowing interface to behave, huh? + }; +} diff --git a/include/macros.h b/include/macros.h new file mode 100644 index 0000000..0b1dbaf --- /dev/null +++ b/include/macros.h @@ -0,0 +1,82 @@ +#ifndef _MACROS_H +#define _MACROS_H + +#ifdef __cplusplus +#include +#include + +#define $CXX 1 +#define $C 0 +#else +#include +#define $CXX 0 +#define $C 1 +#endif + +// Empty token +#define $NULL + +#if $CXX // C++ +#define LINK_START(C) extern #C { +#define LINK_END } +#define restrict __restrict__ +#define $auto __auto_type +#define typeof(...) decltype(__VA_ARGS__) +#define $typeof(...) __typeof__(__VA_ARGS__) +#define $LIKELY(expr) __builtin_expect(bool(expr), true) +#define $UNLIKELY(expr) __builtin_expect(bool(expr), false) +#else // C +#define $LIKELY(expr) __builtin_expect((bool)(expr), true) +#define $UNLIKELY(expr) __builtin_expect((bool)(expr), false) +#define auto __auto_type +#define $auto __auto_type +#define LINK_START(_) +#define LINK_END +#define nullptr ((void*)0) +#define $typeof __typeof__ +#define alignof _Alignof +#define static_assert _Static_assert +#define alignas(...) __attribute__((aligned(__VA_ARGS__))) +#endif + +#define unrestrict __attribute__((__may_alias__)) + +#if $CXX +#define $READ_ONCE_FROM(...) [&] () noexcept -> auto { using cvx_t = ::std::add_pointer_t<::std::add_const_t<::std::add_volatile_t>>; \ + return *static_cast(::std::addressof(__VA_ARGS__)); \ + }() +#define $WRITE_ONCE_TO(X, value) [&] () noexcept -> decltype(auto) { using vx_t = ::std::add_pointer_t<::std::add_volatile_t>; \ + static_assert(::std::is_convertible_v())>, "Cannot convert " #value " to assign to " #X); \ + return *static_cast(::std::addressof(X)) = ::std::forward(value); \ + }() +#else +#define $READ_ONCE_FROM(X) ({ $auto $__read_once_from = (X); *((const volatile $typeof($__read_once_from)*)(&$__read_once_from)); }) +#define $WRITE_ONCE_TO(X, value) ({ $auto $__write_once_to = (X); *((volatile $typeof($__write_once_to)*)(&$__write_once_to)) = (value); }) +#endif + +#define $identity_type(...) $typeof(__VA_ARGS__) + +#define $TRANSMUTE(T, expr) \ + ({ $auto $__expr_from = (expr); \ + static_assert(sizeof(typeof($__expr_from)) == sizeof(T) \ + && alignof(typeof($__expr_from)) == alignof(typeof($__expr_from)), "Transmute source type does not have identical layout to dest type " #T); \ + union { typeof($__expr_from) from; $typeof(T) to; } $__rec = { .from = $__expr_from; }; \ + $__rec.to; }) + +#if $CXX +#define TRANSMUTE(T, ...) ::std::bit_cast<$typeof(T)>(__VA_ARGS__) +#else +#define TRANSMUTE(T, ...) $TRANSMUTE(T, __VA_ARGS__) +#endif + +#define $__int_width_ + +#define $int(N) $identity_type(_BitInt(N)) +#define $sint(N) $identity_type(signed _BitInt(N)) +#define $uint(N) $identity_type(unsigned _BitInt(N)) + +#if !defined(_MACROS_HH) && defined(__cplusplus) +#include "macros.hh" +#endif + +#endif /* _MACROS_H */ diff --git a/include/macros.hh b/include/macros.hh new file mode 100644 index 0000000..eafc3b7 --- /dev/null +++ b/include/macros.hh @@ -0,0 +1,45 @@ +#ifndef _MACROS_HH +#define _MACROS_HH +#ifdef __cplusplus +#include +#include + +#ifndef NOTHING +#define NOTHING +#endif + +#define _DEFINE_CLASS(NAME, constexpr, virtual, noexcept, dtor, copy, move, copy_assign, move_assign, ...) + constexpr NAME(NAME &&) noexcept move + constexpr NAME(NAME const&) noexcept copy + constexpr NAME & operator=(NAME &&) noexcept move_assign + constexpr NAME & operator=(NAME const&) noexcept copy_assign + constexpr virtual ~NAME() dtor + + +#define DEFINE_INTERFACE(...) \ + _DEFINE_CLASS(__VA_ARGS__, constexpr, virtual, noexcept, =default, =default;, =default;, =default;, =default;, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING) + +#define DEFINE_MOVE_INTERFACE(...) \ + _DEFINE_CLASS(__VA_ARGS__, constexpr, virtual, noexcept, =default, =delete;, =default;, =delete;, =default;, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING) + +#define FORWARD(T) ::std::forward(T) + +#define $L(...) { return __VA_ARGS__; } +#define $L_(...) { __VA_ARGS__; } + +//#define $CLASS + +#define $impl $CLASS:: + +#define $ctor $CLASS::$CLASS +#define $dtor $CLASS::~$CLASS +#define $ctor_cpoy(n) $ctor($CLASS const& n) +#define $ctor_move(n) $ctor($CLASS && n) +#define $assign $CLASS & operator= +#define $assign_copy(n) $CLASS & $CLASS::operator=($CLASS const& n) +#define $assign_move(n) $CLASS & $CLASS::operator=($CLASS && n) + +#elif defined(DEBUG) +#warn "Included C++ header to C TU" +#endif +#endif diff --git a/include/types.h b/include/types.h new file mode 100644 index 0000000..76147f6 --- /dev/null +++ b/include/types.h @@ -0,0 +1,125 @@ +#ifndef _TYPES_H +#define _TYPES_H + +#include +#include +#include + +#ifdef $int +#define $__bit_int(X) $int(X) +#else +#define $__bit_int(X) _BitInt(X) +#else + +#endif + +#define $__defint_x(N) \ + typedef signed $__bit_int(N) i ## N; \ + typedef unsigned $__bit_int(N) u ## N + +#define $__defint(N) \ + typedef int ## N ## _t i ## N; \ + typedef uint ## N ## _T u ## N + +#define $__INTS_8 \ + $__defint_x(00); \ + $__defint_x(01); \ + $__defint_x(02); \ + $__defint_x(03); \ + $__defint_x(04); \ + $__defint_x(05); \ + $__defint_x(06); \ + $__defint_x(07); \ + $__defint(8) + +#define $__INTS_16 \ + $__defint_x(0x9); \ + $__defint_x(0xa); \ + $__defint_x(0xb); \ + $__defint_x(0xc); \ + $__defint_x(0xd); \ + $__defint_x(0xe); \ + $__defint_x(0xf); \ + $__defint(16) + + +#define $__INTS_CHUNK_8F(N, ...) \ + /*$__defint_x(0 ## N ## 0);*/ \ + $__defint_x(0 ## N ## 1); \ + $__defint_x(0 ## N ## 2); \ + $__defint_x(0 ## N ## 3); \ + $__defint_x(0 ## N ## 4); \ + $__defint_x(0 ## N ## 5); \ + $__defint_x(0 ## N ## 6); \ + $__defint_x(0 ## N ## 7) \ + __VA_OPT__(; $__defint(__VA_ARGS__)) + +#define $__INTS_CHUNK_8(N) \ + $__defint_x(0 ## N ## 0); \ + $__defint_x(0 ## N ## 1); \ + $__defint_x(0 ## N ## 2); \ + $__defint_x(0 ## N ## 3); \ + $__defint_x(0 ## N ## 4); \ + $__defint_x(0 ## N ## 5); \ + $__defint_x(0 ## N ## 6); \ + $__defint_x(0 ## N ## 7) + +#define $__INTS_CHUNK_16(N) \ + $__defint_x(0x ## N ## 0); \ + $__defint_x(0x ## N ## 1); \ + $__defint_x(0x ## N ## 2); \ + $__defint_x(0x ## N ## 3); \ + $__defint_x(0x ## N ## 4); \ + $__defint_x(0x ## N ## 5); \ + $__defint_x(0x ## N ## 6); \ + $__defint_x(0x ## N ## 7); \ + $__defint_x(0x ## N ## 8); \ + $__defint_x(0x ## N ## 9); \ + $__defint_x(0x ## N ## a); \ + $__defint_x(0x ## N ## b); \ + $__defint_x(0x ## N ## c); \ + $__defint_x(0x ## N ## d); \ + $__defint_x(0x ## N ## e); \ + $__defint_x(0x ## N ## f) + +#define $__INTS_CHUNK_16F(N, d) \ + $__defint_x(0x ## N ## 1); \ + $__defint_x(0x ## N ## 2); \ + $__defint_x(0x ## N ## 3); \ + $__defint_x(0x ## N ## 4); \ + $__defint_x(0x ## N ## 5); \ + $__defint_x(0x ## N ## 6); \ + $__defint_x(0x ## N ## 7); \ + $__defint_x(0x ## N ## 8); \ + $__defint_x(0x ## N ## 9); \ + $__defint_x(0x ## N ## a); \ + $__defint_x(0x ## N ## b); \ + $__defint_x(0x ## N ## c); \ + $__defint_x(0x ## N ## d); \ + $__defint_x(0x ## N ## e); \ + $__defint_x(0x ## N ## f); \ + $__defint(d) + +// Define `{i,u}{0...128}` +$__INTS_8; +$__INTS_16; +$__INTS_CHUNK_8F(1); //24 +$__INTS_CHUNK_16(1);//, 32); +$__INTS_CHUNK_16(2);//, 48); +$__INTS_CHUNK_16(3);//, 64); +$__INTS_CHUNK_16(4);//, 80); +$__INTS_CHUNK_16(5);//, 96); +$__INTS_CHUNK_16(6)//, 128); + +typedef signed __int128 i128; +typedef unsigned __int128 u128; + +typedef size_t usize; +typedef ssize_t isize; + +typedef _Float16 f16; +typedef float f32; +typedef double f64; +typedef long double f128; + +#endif /* _TYPES_H */ diff --git a/src/alloc.cpp b/src/alloc.cpp new file mode 100644 index 0000000..1e56466 --- /dev/null +++ b/src/alloc.cpp @@ -0,0 +1,51 @@ + + +#include + +#include + +extern "C" { + base_allocator::~base_allocator() {} +} + +namespace alloc { + // This is the *true manager* of the allocation arena, when it is destroyed, the memory is cleared + struct FrozenAllocator::anon_raw_secmem { + // Base class for all deallocations that happen within an `anon_raw_secmem` (managed, static, polymorphic, unmanaged, etc.) (TODO: See below, the base should be moved into the header so typed children can be templated...) + struct deleter { //XXX: TODO: How to define this type in the header file? It should be the virt base of all templated deleters, + //TODO: XXX: Rework this design, the deleter must be typed for the value it is deleting... This virtual base should be in the header, and should just contain the shared_ptr reference to anon_raw_secmem. + virtual ~deleter() = default; + protected: + // To prevent anon_raw_secmem being destroyed while there are still allocated values, the base class for the deleter for those values contains a refcount. e.g: `std::unique_ptr>` where: `deleter_for final : public deleter { virtual ~deleter_for(); ... };`, or `std::shared_ptr`, where: `std::shared_ptr>` aliases-ctor(`old, old->value_ptr()`) -> `std::shared_ptr` + std::shared_ptr m_manager_ref; + }; + ~anon_raw_secmem() { + //TODO: Clear and `munmap()` the used page(s) + //XXX: Due to how this is managed via `shared_ptr<>`, it is UB for this to be called *before* all actual allocation of the memory are unallocated (via `deleter`, which they must *all* be managed by. + } + }; + + struct FrozenAllocator::alloc_info { + + }; + struct FrozenAllocator::alloc_value { + + }; + + struct FrozenAllocator::_impl { + std::shared_ptr m_manager; + std::map> m_values; + }; + +#define $CLASS FrozenAllocator + $ctor_move(m) noexcept + : inner_(std::move(m.inner_)) {} + $assign_move(m) { + if($LIKELY(this != &m)) + inner_ = std::move(m.inner_); + return *this; + } + $dtor() {} +#undef $CLASS /* FrozenAllocator */ + +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..0f0863c --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,19 @@ + +#include + +#include +#include + +int main(int argc, char** argv) try { + init::ensure(); + + return 0; +} catch(error::Fatal& fatal) { + +} catch(error::Error& err) { + +} catch(std::exception& se) { + +} catch(...) { + +}