Compare commits
10 Commits
Author | SHA1 | Date |
---|---|---|
Avril | 2458a2b969 | 1 year ago |
Avril | 295da7df02 | 1 year ago |
Avril | dd54a4823d | 1 year ago |
Avril | 0a0fb4555a | 1 year ago |
Avril | ef7f06e8e0 | 1 year ago |
Avril | 16ae82f05d | 1 year ago |
Avril | 454378acfe | 1 year ago |
Avril | ecf72a7526 | 1 year ago |
Avril | 3e3b5d1cf6 | 1 year ago |
Avril | f648646317 | 4 years ago |
@ -0,0 +1,36 @@
|
||||
#ifndef _ERROR_H
|
||||
#define _ERROR_H
|
||||
|
||||
#ifndef $PASTE
|
||||
# define $_PASTE(x,y) x ## y
|
||||
# define $PASTE(x,y) $_PASTE(x,y)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
constexpr inline bool is_noexcept=
|
||||
#if __cpp_exceptions
|
||||
#define EXCEPT 1
|
||||
//#define try try
|
||||
//#define catch(...) catch(__VA_ARGS__)
|
||||
false
|
||||
#else
|
||||
#define EXCEPT 0
|
||||
#define NOEXCEPT
|
||||
//#define catch(...) __try {} catch(__VA_ARGS__)
|
||||
//#define try if constexpr(!is_noexcept)
|
||||
//#define throw (void)0
|
||||
true
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ERROR_H */
|
@ -0,0 +1,406 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#ifndef __cplusplus
|
||||
#error "C++ header only"
|
||||
#endif
|
||||
|
||||
namespace pr {
|
||||
|
||||
namespace details [[gnu::visibility("internal")]] {
|
||||
/*
|
||||
template<template<typename...> typename P>
|
||||
struct generic_valid { template<typename... Args> constexpr static inline bool value = requires{ typename P<Args...>; }; };
|
||||
template<template<typename...> class P>
|
||||
struct generic : std::conditional_t<generic_valid<P>::value,
|
||||
std::true_type,
|
||||
std::false_type>
|
||||
{ template<typename... Args> using type = P<Args...>; };
|
||||
|
||||
template<template<typename> typename T, typename... Args>
|
||||
concept Generic = generic_valid<T>::template value<Args...>;
|
||||
|
||||
template<Generic T, typename... Args>
|
||||
using generic_t = generic<T>::template type<Args...>;
|
||||
|
||||
template<template<typename> template T>
|
||||
concept AnyGeneric = requires{ typename generic_valid<T>; };
|
||||
*/
|
||||
template<typename T>
|
||||
T* take(T*&& ptr) noexcept { return std::exchange(ptr, nullptr); }
|
||||
|
||||
/*
|
||||
template<template<typename U> Inst, typename T>
|
||||
struct is_inst_of { constexpr static inline bool value = std::is_same_v<T, Inst<U>>; };
|
||||
|
||||
template<typename T, typename I>
|
||||
constexpr inline bool is_inst_of_v = is_inst_of<I, T>::value;
|
||||
*/
|
||||
|
||||
template<typename U, typename T>
|
||||
constexpr std::unique_ptr<U> static_ucast(std::unique_ptr<T>&& from) noexcept
|
||||
{ return std::unique_ptr<U>{static_cast<U*>(std::move(from).release())}; }
|
||||
|
||||
template<typename U, typename T>
|
||||
constexpr std::shared_ptr<U> static_ucast(std::shared_ptr<T>&& from) noexcept
|
||||
{ return std::static_pointer_cast<U>(std::move(from)); }
|
||||
|
||||
|
||||
template<typename Ptr, typename From> requires(requires(From&& p) {
|
||||
{ p.release() };
|
||||
requires(std::is_constructible_v<Ptr, decltype(p.release())>);
|
||||
})
|
||||
constexpr Ptr static_pcast(From&& p) noexcept { return Ptr{p.release()}; }
|
||||
|
||||
}
|
||||
|
||||
using increment_t = long double;
|
||||
|
||||
template<typename T>
|
||||
concept Bar = requires(std::remove_const_t<std::remove_reference_t<T>>& v) {
|
||||
{ v.spin(increment_t(0)) };
|
||||
{ std::as_const(v).aux() } -> std::convertible_to<std::string_view>;
|
||||
//{ v.aux() } -> std::assignable_from<std::string_view>;
|
||||
{ (v.aux() = std::string{}) } -> std::same_as<std::add_lvalue_reference_t<decltype(v.aux())>>;
|
||||
//requires(std::assignable_from<std::add_lvalue_reference_t<decltype(v.aux())>, std::string_view>);
|
||||
{ v.aux() += std::string_view{} } -> std::convertible_to<decltype(v.aux())>;
|
||||
{ v.aux(std::declval<std::string&&>()) } -> std::convertible_to<std::string_view>;
|
||||
};
|
||||
|
||||
template<Bar>
|
||||
struct Carrier;
|
||||
|
||||
struct Dynamic {
|
||||
template<Bar> friend class Carrier;
|
||||
|
||||
constexpr auto make(Bar auto&& bar) noexcept(std::is_nothrow_move_constructible_v<std::remove_reference_t<decltype(bar)>>);
|
||||
|
||||
constexpr virtual void spin(increment_t) =0;
|
||||
constexpr virtual std::string& aux() =0;
|
||||
constexpr virtual std::string const& aux() const noexcept =0;
|
||||
constexpr virtual std::string aux(std::string&& s) { return std::exchange(aux(), std::move(s)); }
|
||||
|
||||
constexpr virtual ~Dynamic() {}
|
||||
private:
|
||||
constexpr Dynamic() noexcept {}
|
||||
};
|
||||
template<Bar B>
|
||||
struct Carrier : public virtual Dynamic {
|
||||
using held_type = B;
|
||||
|
||||
template<typename... Args> requires(std::constructible_from<B, Args...>)
|
||||
constexpr Carrier(Args&&... args) noexcept(std::is_nothrow_constructible_v<B, Args...>)
|
||||
: Dynamic(), member_(std::forward<decltype(args)>(args)...) {}
|
||||
constexpr Carrier(Carrier&& m) noexcept(std::is_nothrow_move_constructible_v<B>)
|
||||
requires(std::is_move_constructible_v<B>)
|
||||
: Dynamic(), member_(std::move(m.member_)) {}
|
||||
constexpr Carrier(Carrier const& c) noexcept(std::is_nothrow_copy_constructible_v<B>)
|
||||
requires(std::is_copy_constructible_v<B>)
|
||||
: Dynamic(), member_(c.member_) {}
|
||||
|
||||
constexpr Carrier& operator=(Carrier&& m) noexcept(std::is_nothrow_move_assignable_v<B>) requires(std::is_move_assignable_v<B>)
|
||||
{ if(this != &m) member_ = std::move(m.member_); return *this; }
|
||||
|
||||
constexpr Carrier& operator=(Carrier const& c) noexcept(std::is_nothrow_copy_assignable_v<B>) requires(std::is_copy_assignable_v<B>)
|
||||
{ if(this != &c) member_ = c.member_; return *this; }
|
||||
|
||||
constexpr void spin(increment_t a) override { member_.spin(a); }
|
||||
|
||||
constexpr std::string& aux() override { return member_.aux(); }
|
||||
constexpr std::string const& aux() const noexcept override { return member_.aux(); }
|
||||
constexpr std::string aux(std::string&& s) override { return member_.aux(std::move(s)); }
|
||||
|
||||
template<typename... Args> requires(std::is_invocable_v<B::spin, B&, increment_t, Args...>)
|
||||
constexpr void spin(increment_t a, Args&&... args) noexcept(std::is_nothrow_invocable_v<B::spin, B&, increment_t, decltype(args)...>)
|
||||
{ return member_.spin(a, std::forward<decltype(args)>(args)...); }
|
||||
|
||||
constexpr virtual ~Carrier() {}
|
||||
private:
|
||||
B member_;
|
||||
};
|
||||
template<Bar T>
|
||||
Carrier(T) -> Carrier<T>;
|
||||
template<Bar T>
|
||||
Carrier(T const&) -> Carrier<T>;
|
||||
template<Bar T>
|
||||
Carrier(T&&) -> Carrier<T>;
|
||||
|
||||
constexpr auto Dynamic::make(Bar auto&& bar) noexcept(std::is_nothrow_move_constructible_v<std::remove_reference_t<decltype(bar)>>) { return Carrier(std::move(bar)); }
|
||||
|
||||
template<Bar T, typename Ptr = std::unique_ptr<Dynamic>>
|
||||
constexpr Ptr make_dyn(T&& bar) noexcept(std::is_nothrow_move_constructible_v<T>)
|
||||
{
|
||||
using namespace details;
|
||||
if constexpr(requires{
|
||||
typename T::held_type;
|
||||
requires(std::is_same_v<Carrier<typename T::held_type>, T>);
|
||||
}) return static_pcast<Ptr>(static_ucast<Dynamic>(std::make_unique<T>(std::move(bar))));
|
||||
else return static_pcast<Ptr>(static_ucast<Dynamic>(std::make_unique<Carrier<T>>(std::move(bar))));
|
||||
}
|
||||
|
||||
template<Bar T, typename Ptr = std::unique_ptr<Dynamic>>
|
||||
constexpr Ptr make_dyn(T const& bar) noexcept(std::is_nothrow_move_constructible_v<T>)
|
||||
{
|
||||
if constexpr(std::is_copy_constructible_v<T>) {
|
||||
T nbar{bar};
|
||||
return make_dyn<T, Ptr>(std::move(nbar));
|
||||
} else {
|
||||
struct unsafe_ref {
|
||||
constexpr unsafe_ref(const T& ba) noexcept : b(std::addressof(ba)) {}
|
||||
constexpr unsafe_ref(const unsafe_ref&) noexcept = default;
|
||||
constexpr ~unsafe_ref() noexcept = default;
|
||||
constexpr unsafe_ref(unsafe_ref&& b) noexcept : b(std::exchange(b.b, nullptr)) {}
|
||||
|
||||
constexpr unsafe_ref& operator=(unsafe_ref const&) noexcept = default;
|
||||
constexpr unsafe_ref& operator=(unsafe_ref&& m) noexcept {
|
||||
if(this != &m)
|
||||
b = std::exchange(m.b, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T* b;
|
||||
|
||||
constexpr operator T const&() const noexcept { return *b; }
|
||||
};
|
||||
unsafe_ref re{bar};
|
||||
return make_dyn<unsafe_ref, Ptr>(std::move(re));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ptr> requires(requires(std::unique_ptr<Dynamic>&& p) { details::static_pcast<Ptr>(std::move(p)); })
|
||||
constexpr Ptr make_dyn_for(Bar auto&& bar) noexcept(std::is_nothrow_move_constructible_v<std::remove_reference_t<decltype(bar)>>)
|
||||
{ return make_dyn<decltype(bar), Ptr>(std::move(bar)); }
|
||||
|
||||
constexpr void spin(Bar auto& bar, std::convertible_to<increment_t> auto&& a) { return bar.spin(increment_t(a)); }
|
||||
|
||||
struct None {
|
||||
constexpr None() noexcept = default;
|
||||
constexpr ~None() noexcept = default;
|
||||
|
||||
constexpr void spin(increment_t) const noexcept {}
|
||||
constexpr auto aux() noexcept { return not_string(); }
|
||||
inline std::string const& aux() const noexcept { return none_; }
|
||||
constexpr std::string aux(std::convertible_to<std::string> auto&& s) const noexcept { return {}; } //{ return std::exchange(none_, std::string(std::move(s))); }
|
||||
private:
|
||||
struct not_string {
|
||||
constexpr not_string() noexcept= default;
|
||||
constexpr ~not_string() noexcept= default;
|
||||
|
||||
[[gnu::const]]
|
||||
constexpr not_string& operator+=(std::convertible_to<std::string_view> auto&&) { return *this; }
|
||||
[[gnu::const]]
|
||||
constexpr not_string& operator=(std::convertible_to<std::string> auto&&) { return *this; }
|
||||
|
||||
inline operator std::string&() noexcept { return none_; }
|
||||
inline operator std::string const&() const noexcept { return none_; }
|
||||
|
||||
};
|
||||
/*constinit*/ thread_local static inline std::string none_;
|
||||
};
|
||||
constexpr inline None disable{};
|
||||
|
||||
// A bounded progress-bar
|
||||
struct Progress {
|
||||
using fract_t = increment_t;
|
||||
constexpr static inline bool DEFAULT_WIDTH = 50;
|
||||
constexpr static inline fract_t DEFAULT_TERM_FRACT=1.0l/3.0l;
|
||||
|
||||
[[gnu::nonnull(1)]]
|
||||
Progress(FILE* p = stdout) noexcept;
|
||||
|
||||
Progress(const Progress& p) noexcept;
|
||||
Progress(Progress&& p) noexcept;
|
||||
|
||||
Progress& operator=(Progress const& c) noexcept;
|
||||
Progress& operator=(Progress&& m) noexcept;
|
||||
|
||||
virtual ~Progress();
|
||||
|
||||
inline std::string& aux() noexcept { return tag(); }
|
||||
inline std::string const& aux() const noexcept { return tag(); }
|
||||
inline std::string aux(std::convertible_to<std::string> auto&& s)
|
||||
{ return std::exchange(tag(), std::string(std::move(s))); }
|
||||
protected:
|
||||
std::string& tag() noexcept;
|
||||
const std::string& tag() const noexcept;
|
||||
public:
|
||||
FILE* output() const noexcept;
|
||||
FILE*& output() noexcept;
|
||||
|
||||
size_t& width() noexcept;
|
||||
size_t width() const noexcept;
|
||||
|
||||
fract_t& fraction() noexcept;
|
||||
fract_t fraction() const noexcept;
|
||||
|
||||
fract_t percentage() const noexcept;
|
||||
inline auto percentage() noexcept {
|
||||
struct v final {
|
||||
Progress* p_;
|
||||
v(Progress* p) noexcept : p_(p) {}
|
||||
|
||||
v(v&&) noexcept = default;
|
||||
v(v const&) noexcept = default;
|
||||
v& operator=(v const&) noexcept = default;
|
||||
v& operator=(v&&) noexcept = default;
|
||||
~v() noexcept = default;
|
||||
|
||||
const v& operator=(fract_t f) const noexcept { p_->percentage(f); return *this; }
|
||||
operator fract_t() const noexcept { return static_cast<const Progress*>(p_)->percentage(); }
|
||||
};
|
||||
return v(this);
|
||||
}
|
||||
|
||||
void spin(increment_t by, bool render=true, bool flush=true) noexcept;
|
||||
void render(bool flush = true) const noexcept;
|
||||
private:
|
||||
void percentage(fract_t fract) noexcept;
|
||||
|
||||
struct _impl;
|
||||
std::shared_ptr<_impl> inner_;
|
||||
};
|
||||
|
||||
|
||||
#ifdef SPINNER
|
||||
class Spinner {
|
||||
consteval static auto _GENERATE_MAP(auto const& map, size_t size) noexcept
|
||||
-> std::array<size_t, 256>
|
||||
{
|
||||
static_assert(sizeof(map) == size, "Bad map size");
|
||||
std::array<size_t, 256> out{};
|
||||
while( size --> 0 ) out[int(map[size])] = size;
|
||||
return out;
|
||||
}
|
||||
constexpr static increment_t range(increment_t by)
|
||||
{
|
||||
if(by < -1.0l) return -1.0l;
|
||||
else if(by > 1.0l) return 1.0l;
|
||||
return by;
|
||||
}
|
||||
public:
|
||||
constexpr static inline auto ROUTINE = "|/-\\|/-\\|";
|
||||
constexpr static inline auto ROUTINE_SIZE = sizeof(ROUTINE);
|
||||
constexpr static inline auto REVERSE_MAP = _GENERATE_MAP(ROUTINE, ROUTINE_SIZE);
|
||||
static_assert(ROUTINE_SIZE != sizeof(char*), "Invalid routine size");
|
||||
|
||||
constexpr ssize_t range(int sz) noexcept
|
||||
{
|
||||
/*if(__builtin_expect(sz < 0, false)) {
|
||||
|
||||
std::terminate(); // TODO: How to handle wrapping negatives?? Ugh.
|
||||
}*/
|
||||
return ssize_t(sz) % ssize_t(ROUTINE_SIZE);
|
||||
}
|
||||
constexpr Spinner(size_t n) noexcept
|
||||
: cur_(ROUTINE[range(n)]) {}
|
||||
constexpr Spinner(char c = ROUTINE[0]) noexcept
|
||||
: cur_(range(REVERSE_MAP[int(c)])) {}
|
||||
|
||||
constexpr Spinner(Spinner const&) noexcept = default;
|
||||
constexpr Spinner(Spinner &&) noexcept = default;
|
||||
~Spinner();
|
||||
|
||||
inline void spin(int by) noexcept
|
||||
{
|
||||
operator+=(by);
|
||||
render();
|
||||
}
|
||||
inline void spin(increment_by by) noexcept
|
||||
{
|
||||
spin(int(range(by) * increment_t(ROUTINE_SIZE)));
|
||||
}
|
||||
|
||||
inline Spinner& operator+=(int by) noexcept
|
||||
{
|
||||
cur_ = ROUTINE[size_t(ssize_t(REVERSE_MAP[int(cur_)]) + range(by))];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Spinner& operator++() noexcept { spin(1); return *this; }
|
||||
inline Spinner operator++(int) noexcept { Spinner s = *this; ++s; return *this; }
|
||||
constexpr Spinner& operator=(Spinner&&) noexcept = default;
|
||||
constexpr Spinner& operator=(Spinner const&) noexcept = default;
|
||||
|
||||
constexpr char& character() noexcept { return cur_; }
|
||||
constexpr char character() const noexcept { return cur_; }
|
||||
|
||||
void render(bool flush=true);
|
||||
private:
|
||||
char cur_ = '|';
|
||||
};
|
||||
//TODO: Spinny bar thing (unbounded)
|
||||
#endif
|
||||
|
||||
/*
|
||||
struct Bar {
|
||||
Bar() noexcept = default;
|
||||
Bar(const Bar&) noexcept = default;
|
||||
Bar(Bar&&) noexcept = default;
|
||||
Bar& operator=(const Bar&) noexcept = default;
|
||||
Bar& operator=(Bar&&) noexcept = default;
|
||||
virtual ~Bar() = default;
|
||||
|
||||
virtual void spin(int) =0;
|
||||
};
|
||||
|
||||
enum bar_kind {
|
||||
BRK_UNTRACKED,
|
||||
BRK_TRACKED,
|
||||
};
|
||||
|
||||
template<bar_kind = BRK_UNTRACKED>
|
||||
struct progress;
|
||||
|
||||
template<>
|
||||
struct progress<BRK_UNTRACKED>
|
||||
: public virtual Bar {
|
||||
|
||||
progress(FILE* to);
|
||||
progress(progress const&);
|
||||
inline progress(progress&& mv) noexcept
|
||||
: Bar()
|
||||
, _perc(mv._perc)
|
||||
, _output(details::take(mv._output)) {}
|
||||
|
||||
virtual ~progress();
|
||||
|
||||
void spin(int) override;
|
||||
|
||||
//TODO: this
|
||||
protected:
|
||||
union {
|
||||
double _perc;
|
||||
size_t _num; // not used here
|
||||
};
|
||||
FILE* _output;
|
||||
};
|
||||
|
||||
template<>
|
||||
class progress<BRK_TRACKED>
|
||||
: public progress<BRK_UNTRACKED> {
|
||||
using base_t = progress<BRK_UNTRACKED>;
|
||||
public:
|
||||
inline progress(FILE* to, size_t max) : base_t(to), _num(0), _max(max) {}
|
||||
progress(const progress&) = default;
|
||||
progress(progress&& m) : base_t(std::move(m)), _num(std::exchange(m._num, 0)), _max(m._max) {}
|
||||
|
||||
void spin(int) override;
|
||||
//TODO: this
|
||||
|
||||
virtual ~progress() {}
|
||||
|
||||
protected:
|
||||
using base_t::_output;
|
||||
private:
|
||||
using base_t::_num;
|
||||
size_t _max;
|
||||
};
|
||||
*/
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
|
@ -0,0 +1,31 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <panic.h>
|
||||
#include <map.h>
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
constexpr inline auto MEMFD_DEFAULT_FLAGS = MFD_CLOEXEC;
|
||||
int memfd_alloc(const char* name, size_t size = 0, int flags = MEMFD_DEFAULT_FLAGS)
|
||||
{
|
||||
int fd = memfd_create(name, flags);
|
||||
if(fd < 0) panic("memfd_create() failed");
|
||||
if(size)
|
||||
if(ftruncate(fd, size)) { close(fd); panic("ftruncate() failed"); }
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mm {
|
||||
vmap::vmap()
|
||||
: mmap(create_raw_fd(memfd_alloc(__PRETTY_FUNCTION__))) {}
|
||||
vmap::vmap(size_t sz)
|
||||
: mmap(create_raw_fd(memfd_alloc(__PRETTY_FUNCTION__, sz))) {}
|
||||
|
||||
}
|
@ -1,18 +1,41 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <panic.h>
|
||||
|
||||
#include <colours.h>
|
||||
|
||||
__attribute__((noreturn)) void _do_panic(struct panicinfo info, const char* fmt, ...)
|
||||
#ifndef DEFAULT_PANIC_HANDLER
|
||||
#if __cpp_exceptions || 1 /* XXX: Cannot detect this here */
|
||||
# define DEFAULT_PANIC_HANDLER "_panic__start_unwind_cxx"
|
||||
#else
|
||||
# define DEFAULT_PANIC_HANDLER "_panic__start_unwind_abort"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
extern void _panic__start_unwind_cxx(void);
|
||||
static void _panic__start_unwind_abort(void*)
|
||||
__attribute__((weakref("abort"), noreturn));
|
||||
|
||||
static void _panic__start_unwind(void* payload)
|
||||
__attribute__((noreturn, weakref(DEFAULT_PANIC_HANDLER)));
|
||||
|
||||
__attribute__((noreturn, weak)) void _do_panic(struct panicinfo info, const char* fmt, ...)
|
||||
{
|
||||
va_list li;
|
||||
va_start(li, fmt);
|
||||
fprintf(stderr, BOLD(UNDL(FRED("[!]"))) " (" BOLD("%s") "->" BOLD(FRED("%s")) ":" FYEL("%d") ") " BOLD(FRED("fatal error")) ": ", info.file, info.function, info.line);
|
||||
#define FMT_TTY BOLD(UNDL(FRED("[!]"))) " (" BOLD("%s") "->" BOLD(FRED("%s")) ":" FYEL("%d") ") " BOLD(FRED("fatal error")) ": "
|
||||
#define FMT_FIL "[!]" " (" "%s" "->" "%s" ":" "%d" ") " "fatal error" ": "
|
||||
fprintf(stderr, isatty(fileno(stderr))
|
||||
? FMT_TTY
|
||||
: FMT_FIL , info.file, info.function, info.line);
|
||||
vfprintf(stderr, fmt, li);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(li);
|
||||
abort();
|
||||
|
||||
_panic__start_unwind(&info);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
extern "C" {
|
||||
struct ErrorPayload {};
|
||||
}
|
||||
|
||||
struct FatalError {
|
||||
FatalError(void* payload)
|
||||
: payload(payload) {}
|
||||
FatalError(FatalError&& m)
|
||||
: payload(std::exchange(m.payload, nullptr)) {}
|
||||
|
||||
FatalError& operator=(FatalError&& m)
|
||||
{
|
||||
if(this != &m) {
|
||||
if(payload) destroy();
|
||||
payload = std::exchange(m.payload, nullptr);
|
||||
} return *this;
|
||||
}
|
||||
virtual ~FatalError() noexcept {
|
||||
destroy();
|
||||
}
|
||||
protected:
|
||||
virtual void destroy() noexcept
|
||||
{
|
||||
/*if(auto* p = dynamic_cast<ErrorPayload*>(payload))
|
||||
delete p;*/
|
||||
}
|
||||
public:
|
||||
void* payload;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
[[noreturn, gnu::weak]]
|
||||
void _panic__start_unwind_cxx(void* payload)
|
||||
{
|
||||
#if __EXCEPTIONS
|
||||
throw FatalError(payload);
|
||||
#else
|
||||
::abort();
|
||||
#endif
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <perc.h>
|
||||
|
||||
using fract_t = pr::Progress::fract_t;
|
||||
|
||||
namespace {
|
||||
using namespace pr;
|
||||
size_t twidth(int fd = STDIN_FILENO, size_t orr = Progress::DEFAULT_WIDTH) noexcept
|
||||
{
|
||||
struct winsize w;
|
||||
if(ioctl(fd, TIOCGWINSZ, &w) == -1) return orr;
|
||||
return size_t(w.ws_col);
|
||||
}
|
||||
|
||||
size_t def_bar_width(size_t tw) noexcept
|
||||
{
|
||||
return size_t(std::round(Progress::DEFAULT_TERM_FRACT * fract_t(tw)));
|
||||
}
|
||||
}
|
||||
|
||||
namespace pr {
|
||||
|
||||
struct Progress::_impl {
|
||||
Progress::fract_t fract; // 0..=1
|
||||
FILE* output;
|
||||
size_t width;
|
||||
std::string aux;
|
||||
};
|
||||
|
||||
size_t& Progress::width() noexcept { return inner_->width; }
|
||||
size_t Progress::width() const noexcept { return inner_->width; }
|
||||
|
||||
fract_t& Progress::fraction() noexcept { return inner_->fract; }
|
||||
fract_t Progress::fraction() const noexcept { return inner_->fract; }
|
||||
|
||||
fract_t Progress::percentage() const noexcept { return inner_->fract * 100.0l; }
|
||||
void Progress::percentage(fract_t fract) noexcept { inner_->fract = fract / 100.0l; }
|
||||
|
||||
std::string& Progress::tag() noexcept { return inner_->aux; }
|
||||
const std::string& Progress::tag() const noexcept { return inner_->aux; }
|
||||
|
||||
FILE* Progress::output() const noexcept { return inner_->output; }
|
||||
FILE*& Progress::output() noexcept { return inner_->output; }
|
||||
|
||||
void Progress::render(bool flush) const noexcept
|
||||
{
|
||||
constinit thread_local static std::vector<char> buffer{};
|
||||
|
||||
const auto& inner = *inner_;
|
||||
FILE* out = inner.output;
|
||||
auto wf = fract_t(inner.width) * inner.fract;
|
||||
auto perc = percentage();
|
||||
size_t cf = size_t(std::floor(wf));
|
||||
|
||||
|
||||
//auto print = []<typename F> (F f, auto&&... args) {
|
||||
#define print(...) fmt::format_to(std::back_inserter(buffer), __VA_ARGS__);
|
||||
//};
|
||||
|
||||
buffer.clear();
|
||||
// Render bar
|
||||
buffer.push_back('[');
|
||||
for(size_t i=0;i<inner.width;i++)
|
||||
if(i<=cf) buffer.push_back( '#' );
|
||||
else buffer.push_back( ' ' );
|
||||
buffer.push_back( ']' );
|
||||
print(": {:00.2}%", perc);
|
||||
if(inner.aux.size())
|
||||
print(" ({})", std::string_view(inner.aux));
|
||||
// Print bar
|
||||
fprintf(out, "\r%.*s", int(buffer.size() & INT_MAX), static_cast<const char*>(buffer.data()));
|
||||
// Flush output stream
|
||||
if(flush) fflush(out);
|
||||
#undef print
|
||||
}
|
||||
void Progress::spin(increment_t by, bool r, bool f) noexcept
|
||||
{
|
||||
auto& inner = *inner_;
|
||||
inner.fract=by;
|
||||
if(inner.fract > 1.0l)
|
||||
inner.fract=1.0l;
|
||||
if(r) this->render(f);
|
||||
}
|
||||
|
||||
[[gnu::nonnull(1)]]
|
||||
Progress::Progress(FILE* p) noexcept
|
||||
: inner_(std::make_unique<_impl>(0, p, def_bar_width(twidth(fileno(p))) )) {}
|
||||
|
||||
Progress::Progress(const Progress& p) noexcept
|
||||
: inner_(p.inner_ ? std::make_unique<_impl>(*p.inner_) : nullptr) {}
|
||||
|
||||
Progress::Progress(Progress&& p) noexcept
|
||||
: inner_(std::move(p.inner_)) {}
|
||||
|
||||
Progress& Progress::operator=(Progress&& p) noexcept
|
||||
{
|
||||
if(this != &p) inner_ = std::move(p.inner_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Progress& Progress::operator=(Progress const& p) noexcept
|
||||
{
|
||||
if(this != &p) inner_ = p.inner_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Progress::~Progress() {
|
||||
if(inner_)
|
||||
fputc('\n', inner_->output);
|
||||
}
|
||||
|
||||
|
||||
#ifdef SPINNER
|
||||
Spinner::~Spinner() {
|
||||
//TODO: Add output: if(cur_) fputc('\n', output);
|
||||
}
|
||||
|
||||
void Spinner::render(bool flush) {
|
||||
/*char arr[] = {
|
||||
'\r',
|
||||
cur_,
|
||||
0,
|
||||
};
|
||||
fputs(arr, output);
|
||||
if(flush) fflush(output);*/
|
||||
}
|
||||
#endif
|
||||
}
|
Loading…
Reference in new issue