Added macros, types, constraints, Rust-like Borrow interface (TODO: rework that) Fortune for readpass's current commit: Future blessing − 末吉master
parent
d11d82c9b7
commit
8ac56c862f
@ -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 <memory>
|
||||
#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<typename T>
|
||||
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<anon_raw_secmem> m_manager;
|
||||
//std::map<alloc_info, std::unique_ptr<alloc_value>> m_values;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ALLOC_H */
|
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "constraints.hh"
|
||||
|
||||
namespace borrow {
|
||||
#if 0
|
||||
//TODO: Eh, rethink this when brain not fogged...
|
||||
template<typename T, where::deref_to<T> P = T*>
|
||||
struct Borrow {
|
||||
using traits = std::pointer_traits<P>;
|
||||
|
||||
using type = T;
|
||||
using pointer_type = P;
|
||||
using pointer = traits::pointer;
|
||||
|
||||
|
||||
static_assert(std::is_same_v<T, traits::element_type>, "Invalid `deref_to<T> P` (element_type != T)");
|
||||
|
||||
|
||||
};
|
||||
#endif
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
|
||||
#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<T>, "Bad decltype(auto&&)");
|
||||
|
||||
return static_cast<std::add_const_t<T>&&>(t);
|
||||
}
|
||||
#endif
|
||||
template<typename T>
|
||||
using add_const_reference_t = decltype((std::as_const(std::declval<T>())));
|
||||
|
||||
template<typename T>
|
||||
using add_const_pointer_t = decltype(std::addressof(std::as_const(std::declval<T>())));
|
||||
|
||||
static_assert(
|
||||
std::is_lvalue_reference_v<add_const_reference_t<int>>
|
||||
and std::is_lvalue_reference_v<add_const_reference_t<int const&>>
|
||||
and std::is_lvalue_reference_v<add_const_reference_t<int &&>
|
||||
and std::is_lvalue_reference_v<add_const_reference_t<int const&&>
|
||||
and std::is_same_v
|
||||
< add_const_reference_t<std::unique_ptr<int>&>
|
||||
, std::unique_ptr<int> const&
|
||||
>
|
||||
, "add_const_reference_t is not perfectly forwarding");
|
||||
template<typename P>
|
||||
concept pointer_like = requires {
|
||||
typename std::pointer_traits<P>;
|
||||
typename std::pointer_traits<P>::element_type;
|
||||
typename std::pointer_traits<P>::pointer;
|
||||
};
|
||||
|
||||
template<typename P, typename T, bool Noexcept = true>
|
||||
concept deref_to = pointer_like<P>
|
||||
and requires(P ptr) {
|
||||
// element type can be assigned to `T`.
|
||||
requires(std::is_convertible_v<std::pointer_traits<P>::element_type, T>);
|
||||
|
||||
// Dereferencing the pointer can be assigned to `T`.
|
||||
{ *ptr } noexcept(Noexcept) -> std::convertible_to<std::pointer_traits<P>::element_type>;
|
||||
|
||||
//{ ptr <=> nullptr } noexcept(Noexcept) -> std::convertible_to<
|
||||
|
||||
// { std::as_const(*ptr) } noexcept(Noexcept) -> std::convertible_to<add_const_reference_t<T>>;
|
||||
// { std::addressof(value) } -> std::convertible_to<std::pointer_traits<P>::pointer>;
|
||||
};
|
||||
|
||||
template<typename P, typename T, bool Noexcept = true>
|
||||
concept may_deref_to = deref_to<P, T, Noexcept>
|
||||
and requires(P ptr) {
|
||||
// The pointer is nullable
|
||||
{ ptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
||||
{ !ptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
||||
|
||||
// The pointer can be constructed from `nullptr`.
|
||||
//{ nullptr } noexcept(Noexcept) -> std::convertible_to<P>;
|
||||
|
||||
// The pointer can be assigned `nullptr`.
|
||||
//{ ptr = nullptr } noexcept(Noexcept);
|
||||
|
||||
// The pointer is orderable.
|
||||
//{ ptr == ptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
||||
//{ ptr != ptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
||||
|
||||
// The pointer is null-comparable
|
||||
{ ptr == nullptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
||||
{ ptr != nullptr } noexcept(Noexcept) -> std::convertible_to<bool>;
|
||||
};
|
||||
// { std::as_const(*ptr) } noexcept -> std::convertible_to<add_const_reference_t<T>>;
|
||||
// { std::addressof(value) } noexcept -> std::convertible_to<P>;
|
||||
/*requires(std::is_convertible_v
|
||||
< add_const_reference_t< std::pointer_traits<P>::element_type >
|
||||
, add_const_reference_t< T >
|
||||
>);
|
||||
{ std::as_const(*std::declval<std::pointer_traits<P>::pointer>()) }
|
||||
-> std::convertible_to<std::pointer_traits<P>::element_type>;
|
||||
//std::convertible_to< add_const_pointer_t<*/
|
||||
//};
|
||||
|
||||
#if 0
|
||||
(std::is_pointer_v<P> &&
|
||||
// P = ?*
|
||||
requires(P ptr) {
|
||||
{ ptr } -> std::convertible_to<T const*>;
|
||||
{ static_cast<T*>(ptr) };
|
||||
}
|
||||
)
|
||||
or requires(P ptr, T value) {
|
||||
|
||||
};
|
||||
#endif
|
||||
}
|
@ -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<typename T, where::deref_to<T> (using std::pointer_traits<>) PtrType = T*>` (borrow.hh): essentially specialised `std::variant<T, PtrType>`
|
||||
constexpr virtual borrow::Borrow<const Report> report() const& { return borrow::Borrow{ nullptr }; }
|
||||
// constexpr virtual borrow::Borrow<const Report> report() & { return borrow::Borrow{ nullptr }; }
|
||||
constexpr virtual borrow::Borrow<Report> report() & { return borrow::Borrow{ nullptr }; }
|
||||
constexpr virtual borrow::Borrow<Report>: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?
|
||||
};
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
#ifndef _MACROS_H
|
||||
#define _MACROS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#define $CXX 1
|
||||
#define $C 0
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#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<decltype(__VA_ARGS__)>>>; \
|
||||
return *static_cast<cvx_t>(::std::addressof(__VA_ARGS__)); \
|
||||
}()
|
||||
#define $WRITE_ONCE_TO(X, value) [&] () noexcept -> decltype(auto) { using vx_t = ::std::add_pointer_t<::std::add_volatile_t<decltype(X)>>; \
|
||||
static_assert(::std::is_convertible_v<decltype(value), decltype(*::std::declval<vx_t>())>, "Cannot convert " #value " to assign to " #X); \
|
||||
return *static_cast<vx_t>(::std::addressof(X)) = ::std::forward<decltype(value)>(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 */
|
@ -0,0 +1,45 @@
|
||||
#ifndef _MACROS_HH
|
||||
#define _MACROS_HH
|
||||
#ifdef __cplusplus
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#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<decltype(T)>(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
|
@ -0,0 +1,125 @@
|
||||
#ifndef _TYPES_H
|
||||
#define _TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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 */
|
@ -0,0 +1,51 @@
|
||||
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <alloc.h>
|
||||
|
||||
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<T, deleter_for<T>>` where: `deleter_for<T> final : public deleter { virtual ~deleter_for(); ... };`, or `std::shared_ptr<T>`, where: `std::shared_ptr<value_with_deleter<T>>` aliases-ctor(`old, old->value_ptr()`) -> `std::shared_ptr<T>`
|
||||
std::shared_ptr<anon_raw_secmem> 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<anon_raw_secmem> m_manager;
|
||||
std::map<alloc_info, std::unique_ptr<alloc_value>> 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 */
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <error.hh>
|
||||
#include <init.hh>
|
||||
|
||||
int main(int argc, char** argv) try {
|
||||
init::ensure();
|
||||
|
||||
return 0;
|
||||
} catch(error::Fatal& fatal) {
|
||||
|
||||
} catch(error::Error& err) {
|
||||
|
||||
} catch(std::exception& se) {
|
||||
|
||||
} catch(...) {
|
||||
|
||||
}
|
Loading…
Reference in new issue