init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#if defined _MSC_VER || defined __MINGW32__
#define CRL_USE_WINAPI_TIME
#elif defined __APPLE__ // _MSC_VER
#define CRL_USE_MAC_TIME
#else // __APPLE__
#define CRL_USE_LINUX_TIME
#endif // !_MSC_VER && !__APPLE__
#if defined _MSC_VER && !defined CRL_FORCE_QT
#if defined _WIN64
#define CRL_USE_WINAPI
#define CRL_WINAPI_X64
#elif defined _M_IX86 // _WIN64
#define CRL_USE_WINAPI
#define CRL_WINAPI_X86
//#define CRL_THROW_FP_EXCEPTIONS
#else // _M_IX86
#error "Configuration is not supported."
#endif // !_WIN64 && !_M_IX86
#ifndef CRL_FORCE_COMMON_LIST
#define CRL_USE_WINAPI_LIST
#endif // !CRL_FORCE_COMMON_LIST
#elif __has_include(<dispatch/dispatch.h>) && !defined CRL_FORCE_QT // _MSC_VER && !CRL_FORCE_QT
// gcc compatibility
#ifndef __has_feature
#define __has_feature(x) 0
#endif // !__has_feature
#ifndef __has_extension
#define __has_extension __has_feature
#endif // !__has_extension
#define CRL_USE_DISPATCH
#elif __has_include(<QtCore/QThreadPool>) // dispatch && !CRL_FORCE_QT
#define CRL_USE_QT
#endif // !_MSC_VER && !dispatch && Qt
#if __has_include(<rpl/producer.h>)
#define CRL_ENABLE_RPL_INTEGRATION
#endif // __has_include(<rpl/producer.h>)

View File

@@ -0,0 +1,21 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include <crl/crl_time.h>
#ifndef CRL_USE_WINAPI_TIME
#include <float.h>
namespace crl {
void toggle_fp_exceptions(bool throwing) {
// We activate them only on Windows right now.
}
} // namespace crl
#endif // !CRL_USE_WINAPI_TIME

View File

@@ -0,0 +1,47 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <crl/common/crl_common_config.h>
#include <memory>
namespace crl {
template <typename T, typename Enable>
struct guard_traits;
template <typename T>
struct guard_traits<std::weak_ptr<T>, void> {
static std::weak_ptr<T> create(const std::weak_ptr<T> &value) {
return value;
}
static std::weak_ptr<T> create(std::weak_ptr<T> &&value) {
return std::move(value);
}
static bool check(const std::weak_ptr<T> &guard) {
return guard.lock() != nullptr;
}
};
template <typename T>
struct guard_traits<std::shared_ptr<T>, void> {
static std::weak_ptr<T> create(const std::shared_ptr<T> &value) {
return value;
}
static std::weak_ptr<T> create(std::shared_ptr<T> &&value) {
return value;
}
static bool check(const std::weak_ptr<T> &guard) {
return guard.lock() != nullptr;
}
};
} // namespace crl

View File

@@ -0,0 +1,66 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include <crl/common/crl_common_list.h>
#if defined CRL_USE_COMMON_LIST
namespace crl::details {
list::list() : _alive(new bool(true)) {
}
auto list::ReverseList(BasicEntry *entry, BasicEntry *next) -> BasicEntry* {
entry->next = nullptr;
do {
auto third = next->next;
next->next = entry;
entry = next;
next = third;
} while (next);
return entry;
}
bool list::push_entry(BasicEntry *entry) {
auto head = (BasicEntry*)nullptr;
while (true) {
if (_head.compare_exchange_weak(head, entry)) {
return (head == nullptr);
}
entry->next = head;
}
}
bool list::empty() const {
return (_head == nullptr);
}
bool list::process() {
if (auto entry = _head.exchange(nullptr)) {
const auto alive = _alive;
if (const auto next = entry->next) {
entry = ReverseList(entry, next);
}
do {
const auto basic = entry;
entry = entry->next;
basic->process(basic);
if (!*alive) {
delete alive;
return false;
}
} while (entry);
}
return true;
}
list::~list() {
*_alive = false;
}
} // namespace crl::details
#endif // CRL_USE_COMMON_LIST

View File

@@ -0,0 +1,90 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <crl/common/crl_common_config.h>
#if defined CRL_USE_WINAPI_LIST
#include <crl/winapi/crl_winapi_list.h>
#else // CRL_USE_WINAPI_LIST
#include <crl/common/crl_common_utils.h>
#include <crl/crl_semaphore.h>
#include <atomic>
#define CRL_USE_COMMON_LIST
namespace crl::details {
class list {
public:
list();
template <typename Callable>
bool push_is_first(Callable &&callable) {
return push_entry(AllocateEntry(std::forward<Callable>(callable)));
}
bool process();
bool empty() const;
~list();
private:
struct BasicEntry;
using ProcessEntryMethod = void(*)(BasicEntry *entry);
struct BasicEntry {
BasicEntry(ProcessEntryMethod method) : process(method) {
}
BasicEntry *next = nullptr;
ProcessEntryMethod process = nullptr;
};
template <typename Function>
struct Entry : BasicEntry {
Entry(Function &&function)
: BasicEntry(Entry::Process)
, function(std::move(function)) {
}
Entry(const Function &function)
: BasicEntry(Entry::Process)
, function(function) {
}
Function function;
static void Process(BasicEntry *entry) {
auto full = static_cast<Entry*>(entry);
auto guard = details::finally([=] { delete full; });
full->function();
}
};
template <typename Callable>
static Entry<std::decay_t<Callable>> *AllocateEntry(
Callable &&callable) {
using Function = std::decay_t<Callable>;
using Type = Entry<Function>;
return new Type(std::forward<Callable>(callable));
}
static BasicEntry *ReverseList(BasicEntry *entry, BasicEntry *next);
bool push_entry(BasicEntry *entry);
std::atomic<BasicEntry*> _head = nullptr;
bool *_alive = nullptr;
};
} // namespace crl::details
#endif // !CRL_USE_WINAPI_LIST

View File

@@ -0,0 +1,474 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <crl/common/crl_common_config.h>
#include <crl/crl_on_main.h>
#include <crl/crl_semaphore.h>
#include <memory>
#include <tuple>
#ifdef CRL_ENABLE_RPL_INTEGRATION
#include <rpl/producer.h>
#endif // CRL_ENABLE_RPL_INTEGRATION
namespace crl::details {
template <typename Policy>
class object_async_base
: public std::enable_shared_from_this<object_async_base<Policy>>
, private Policy {
public:
template <
typename Value,
typename = std::enable_if_t<!std::is_reference_v<Value>>>
void destroy(Value &&value) const;
protected:
template <typename Callable>
void async(Callable &&callable) const;
template <typename Callable>
void sync(Callable &&callable) const;
~object_async_base() = default;
};
template <typename Type>
class object_async_storage {
protected:
Type &value();
const Type &value() const;
~object_async_storage();
private:
std::aligned_storage_t<sizeof(Type), alignof(Type)> _storage;
};
template <typename Policy, typename Type>
class object_async_data final
: private object_async_storage<Type>
, public object_async_base<Policy> {
public:
using Object = Type;
template <typename ...Args>
void construct(Args &&...args);
template <typename Method>
void with(Method &&method);
template <typename Method>
void with(Method &&method) const;
template <typename Method>
void with_sync(Method &&method);
template <typename Method>
void with_sync(Method &&method) const;
};
template <typename Policy, typename Type>
class weak_async final {
using data = details::object_async_data<
Policy,
std::remove_const_t<Type>>;
using my_data = std::conditional_t<
std::is_const_v<Type>,
const data,
data>;
public:
weak_async() = default;
weak_async(const std::shared_ptr<data> &strong);
weak_async(const weak_async &other) = default;
weak_async(weak_async &&other) = default;
weak_async &operator=(const weak_async &other) = default;
weak_async &operator=(weak_async &&other) = default;
template <typename Method>
void with(Method &&method) const;
template <typename Method>
void with_sync(Method &&method) const;
template <
typename Value,
typename = std::enable_if_t<!std::is_reference_v<Value>>>
void destroy(Value &&value) const;
// Returns a lambda that runs arbitrary callable on the objects queue.
// const auto r = runner(); r([] { make_some_work_on_queue(); });
auto runner() const {
return [weak = *this](auto &&method) {
weak.with([
method = std::forward<decltype(method)>(method)
](Type&) mutable {
std::move(method)();
});
};
}
#ifdef CRL_ENABLE_RPL_INTEGRATION
template <
typename Method,
typename Invoke,
typename Result = decltype(
std::declval<Method>()(std::declval<Type&>()))>
Result producer(Method &&method, Invoke &&invoke) const;
template <
typename Method,
typename Result = decltype(
std::declval<Method>()(std::declval<Type&>()))>
Result producer_on_main(Method &&method) const;
#endif // CRL_ENABLE_RPL_INTEGRATION
private:
std::weak_ptr<my_data> _weak;
};
template <typename Policy, typename Type>
class object_async final {
public:
template <typename ...Args>
object_async(Args &&...args);
object_async(const object_async &other) = delete;
object_async &operator=(const object_async &other) = delete;
template <typename Method>
void with(Method &&method);
template <typename Method>
void with(Method &&method) const;
template <typename Method>
void with_sync(Method &&method);
template <typename Method>
void with_sync(Method &&method) const;
template <
typename Value,
typename = std::enable_if_t<!std::is_reference_v<Value>>>
void destroy(Value &&value) const;
#ifdef CRL_ENABLE_RPL_INTEGRATION
template <
typename Method,
typename Invoke,
typename Result = decltype(
std::declval<Method>()(std::declval<Type&>()))>
Result producer(Method &&method, Invoke &&invoke) const;
template <
typename Method,
typename Result = decltype(
std::declval<Method>()(std::declval<Type&>()))>
Result producer_on_main(Method &&method) const;
#endif // CRL_ENABLE_RPL_INTEGRATION
weak_async<Policy, Type> weak();
weak_async<Policy, const Type> weak() const;
~object_async();
private:
using Data = details::object_async_data<Policy, Type>;
std::shared_ptr<Data> _data;
};
template <typename Policy>
template <typename Callable>
void object_async_base<Policy>::async(Callable &&callable) const {
Policy::async_plain([
that = this->shared_from_this(),
what = std::forward<Callable>(callable)
]() mutable {
std::move(what)();
});
}
template <typename Policy>
template <typename Callable>
void object_async_base<Policy>::sync(Callable &&callable) const {
semaphore waiter;
Policy::async_plain([&] {
const auto guard = details::finally([&] { waiter.release(); });
callable();
});
waiter.acquire();
}
template <typename Policy>
template <typename Value, typename>
void object_async_base<Policy>::destroy(Value &&value) const {
Policy::async_plain([moved = std::move(value)]{});
}
template <typename Type>
Type &object_async_storage<Type>::value() {
return *reinterpret_cast<Type*>(&_storage);
}
template <typename Type>
const Type &object_async_storage<Type>::value() const {
return *reinterpret_cast<const Type*>(&_storage);
}
template <typename Type>
object_async_storage<Type>::~object_async_storage() {
value().~Type();
}
template <typename Policy, typename Type>
template <typename ...Args>
void object_async_data<Policy, Type>::construct(Args &&...args) {
object_async_base<Policy>::async([arguments = std::make_tuple(
&object_async_storage<Type>::value(),
std::forward<Args>(args)...
)]() mutable {
const auto create = [](void *storage, Args &&...args) {
new (storage) Type(std::forward<Args>(args)...);
};
std::apply(create, std::move(arguments));
});
}
template <typename Policy, typename Type>
template <typename Method>
void object_async_data<Policy, Type>::with(Method &&method) {
object_async_base<Policy>::async([
=,
method = std::forward<Method>(method)
]() mutable {
std::move(method)(object_async_storage<Type>::value());
});
}
template <typename Policy, typename Type>
template <typename Method>
void object_async_data<Policy, Type>::with(Method &&method) const {
object_async_base<Policy>::async([
=,
method = std::forward<Method>(method)
]() mutable {
std::move(method)(object_async_storage<Type>::value());
});
}
template <typename Policy, typename Type>
template <typename Method>
void object_async_data<Policy, Type>::with_sync(Method &&method) {
object_async_base<Policy>::sync([
=,
method = std::forward<Method>(method)
]() mutable {
std::move(method)(object_async_storage<Type>::value());
});
}
template <typename Policy, typename Type>
template <typename Method>
void object_async_data<Policy, Type>::with_sync(Method &&method) const {
object_async_base<Policy>::sync([
=,
method = std::forward<Method>(method)
]() mutable {
std::move(method)(object_async_storage<Type>::value());
});
}
template <typename Policy, typename Type>
weak_async<Policy, Type>::weak_async(const std::shared_ptr<data> &strong)
: _weak(strong) {
}
template <typename Policy, typename Type>
template <typename Method>
void weak_async<Policy, Type>::with(Method &&method) const {
if (auto strong = _weak.lock()) {
const auto raw = strong.get();
raw->with(std::move(method));
raw->destroy(std::move(strong));
}
}
template <typename Policy, typename Type>
template <typename Method>
void weak_async<Policy, Type>::with_sync(Method &&method) const {
if (auto strong = _weak.lock()) {
const auto raw = strong.get();
raw->with_sync(std::move(method));
raw->destroy(std::move(strong));
}
}
template <typename Policy, typename Type>
template <typename Value, typename>
void weak_async<Policy, Type>::destroy(Value &&value) const {
if (auto strong = _weak.lock()) {
const auto raw = strong.get();
raw->destroy(std::move(value));
raw->destroy(std::move(strong));
} else {
[[maybe_unused]] const auto moved = std::move(value);
}
}
#ifdef CRL_ENABLE_RPL_INTEGRATION
template <typename Policy, typename Type>
template <typename Method, typename Invoke, typename Result>
Result weak_async<Policy, Type>::producer(
Method &&method,
Invoke &&invoke) const {
return [
weak = *this,
method = std::forward<Method>(method),
invoke = std::forward<Invoke>(invoke)
](auto consumer) mutable {
auto lifetime_on_queue = std::make_shared<rpl::lifetime>();
weak.with([
method = std::move(method),
invoke = std::move(invoke),
consumer = std::move(consumer),
lifetime_on_queue
](const Type &that) mutable {
method(
that
) | rpl::on_next_error_done([=](auto &&value) {
invoke([
consumer,
value = std::forward<decltype(value)>(value)
]() mutable {
consumer.put_next(std::move(value));
});
}, [=](auto &&error) {
invoke([
consumer,
error = std::forward<decltype(error)>(error)
]() mutable {
consumer.put_error(std::move(error));
});
}, [=] {
invoke([=] {
consumer.put_done();
});
}, *lifetime_on_queue);
});
return rpl::lifetime([
lifetime_on_queue = std::move(lifetime_on_queue),
weak = std::move(weak)
]() mutable {
weak.destroy(std::move(lifetime_on_queue));
});
};
}
template <typename Policy, typename Type>
template <typename Method, typename Result>
Result weak_async<Policy, Type>::producer_on_main(Method &&method) const {
return producer(std::forward<Method>(method), [](auto &&callback) {
crl::on_main(std::forward<decltype(callback)>(callback));
});
}
#endif // CRL_ENABLE_RPL_INTEGRATION
template <typename Policy, typename Type>
template <typename ...Args>
object_async<Policy, Type>::object_async(Args &&...args)
: _data(std::make_shared<Data>()) {
constexpr auto plain_construct = std::is_constructible_v<
Type,
Args...>;
[[maybe_unused]] constexpr auto with_weak_construct = std::is_constructible_v<
Type,
weak_async<Policy, Type>,
Args...>;
if constexpr (plain_construct) {
_data->construct(std::forward<Args>(args)...);
} else if constexpr (with_weak_construct) {
_data->construct(weak(), std::forward<Args>(args)...);
} else {
static_assert(false_t(args...), "Could not find a constructor.");
}
}
template <typename Policy, typename Type>
template <typename Method>
void object_async<Policy, Type>::with(Method &&method) {
_data->with(std::forward<Method>(method));
}
template <typename Policy, typename Type>
template <typename Method>
void object_async<Policy, Type>::with(Method &&method) const {
const auto data = static_cast<const Data*>(_data.get());
data->with(std::forward<Method>(method));
}
template <typename Policy, typename Type>
template <typename Method>
void object_async<Policy, Type>::with_sync(Method &&method) {
_data->with_sync(std::forward<Method>(method));
}
template <typename Policy, typename Type>
template <typename Method>
void object_async<Policy, Type>::with_sync(Method &&method) const {
const auto data = static_cast<const Data*>(_data.get());
data->with_sync(std::forward<Method>(method));
}
template <typename Policy, typename Type>
template <typename Value, typename>
void object_async<Policy, Type>::destroy(Value &&value) const {
_data->destroy(std::move(value));
}
#ifdef CRL_ENABLE_RPL_INTEGRATION
template <typename Policy, typename Type>
template <typename Method, typename Callback, typename Result>
Result object_async<Policy, Type>::producer(
Method &&method,
Callback &&callback) const {
return weak().producer(
std::forward<Method>(method),
std::forward<Callback>(callback));
}
template <typename Policy, typename Type>
template <typename Method, typename Result>
Result object_async<Policy, Type>::producer_on_main(Method &&method) const {
return weak().producer_on_main(std::forward<Method>(method));
}
#endif // CRL_ENABLE_RPL_INTEGRATION
template <typename Policy, typename Type>
auto object_async<Policy, Type>::weak() -> weak_async<Policy, Type> {
return { _data };
}
template <typename Policy, typename Type>
auto object_async<Policy, Type>::weak() const
-> weak_async<Policy, const Type> {
return { _data };
}
template <typename Policy, typename Type>
object_async<Policy, Type>::~object_async() {
_data->destroy(std::move(_data));
}
} // namespace crl::details

View File

@@ -0,0 +1,63 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include <crl/crl_on_main.h>
#ifdef CRL_USE_COMMON_QUEUE
#include <exception>
namespace {
crl::queue *Queue/* = nullptr*/;
std::atomic<int> Counter/* = 0*/;
crl::details::main_queue_pointer Lifetime;
} // namespace
namespace crl::details {
void main_queue_pointer::grab() {
auto counter = Counter.load(std::memory_order_acquire);
while (true) {
if (!counter) {
return;
} else if (Counter.compare_exchange_weak(counter, counter + 1)) {
_pointer = Queue;
return;
}
}
}
void main_queue_pointer::ungrab() {
if (_pointer) {
if (--Counter == 0) {
delete _pointer;
}
_pointer = nullptr;
}
}
void main_queue_pointer::create(main_queue_processor processor) {
if (Counter.load(std::memory_order_acquire) != 0) {
std::terminate();
}
Queue = new queue(processor);
Counter.store(1, std::memory_order_release);
_pointer = Queue;
}
} // namespace crl::details
namespace crl {
void init_main_queue(main_queue_processor processor) {
Lifetime.create(processor);
}
} // namespace crl
#endif // CRL_USE_COMMON_QUEUE

View File

@@ -0,0 +1,75 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <crl/common/crl_common_config.h>
#include <crl/common/crl_common_queue.h>
#include <atomic>
#ifndef CRL_USE_COMMON_QUEUE
#define CRL_USE_COMMON_QUEUE
#endif // !CRL_USE_COMMON_QUEUE
namespace crl::details {
extern queue *MainQueue;
extern std::atomic<int> MainQueueCounter;
class main_queue_pointer {
public:
main_queue_pointer() {
grab();
}
void create(main_queue_processor processor);
explicit operator bool() const {
return _pointer != nullptr;
}
queue *operator->() const {
return _pointer;
}
~main_queue_pointer() {
ungrab();
}
private:
void grab();
void ungrab();
queue *_pointer = nullptr;
};
} // namespace crl::details
namespace crl {
void init_main_queue(main_queue_processor processor);
inline void wrap_main_queue(main_queue_wrapper wrapper) {
// If wrapping is needed here, it can be done inside processor.
}
template <typename Callable>
inline void on_main(Callable &&callable) {
if (const auto main = details::main_queue_pointer()) {
main->async(std::forward<Callable>(callable));
}
}
template <typename Callable>
inline void on_main_sync(Callable &&callable) {
if (const auto main = details::main_queue_pointer()) {
main->sync(std::forward<Callable>(callable));
}
}
} // namespace crl

View File

@@ -0,0 +1,115 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <crl/common/crl_common_config.h>
#include <memory>
#include <type_traits>
namespace crl {
namespace details {
template <typename T>
constexpr std::size_t dependent_zero = 0;
} // namespace details
template <typename T, typename Enable = void>
struct guard_traits;
template <typename Callable>
struct deduce_call_type_traits {
using type = decltype(&Callable::operator());
};
template <typename Callable>
using deduced_call_type = typename deduce_call_type_traits<
std::decay_t<Callable>>::type;
template <typename Guard, typename Callable>
class guarded_wrap {
public:
using ClearCallable = std::decay_t<Callable>;
using GuardTraits = guard_traits<std::decay_t<Guard>>;
using GuardType = decltype(GuardTraits::create(std::declval<Guard>()));
guarded_wrap(Guard &&object, Callable &&callable)
: _guard(GuardTraits::create(std::forward<Guard>(object)))
, _callable(std::forward<Callable>(callable)) {
}
template <
typename ...OtherArgs,
typename Return = decltype(
std::declval<ClearCallable>()(std::declval<OtherArgs>()...))>
Return operator()(OtherArgs &&...args) {
return GuardTraits::check(_guard)
? _callable(std::forward<OtherArgs>(args)...)
: Return();
}
template <
typename ...OtherArgs,
typename Return = decltype(
std::declval<ClearCallable>()(std::declval<OtherArgs>()...))>
Return operator()(OtherArgs &&...args) const {
return GuardTraits::check(_guard)
? _callable(std::forward<OtherArgs>(args)...)
: Return();
}
private:
GuardType _guard;
ClearCallable _callable;
};
template <typename Guard, typename Callable>
struct deduce_call_type_traits<guarded_wrap<Guard, Callable>> {
using type = deduced_call_type<Callable>;
};
template <
typename Guard,
typename Callable,
typename GuardTraits = guard_traits<std::decay_t<Guard>>,
typename = std::enable_if_t<
sizeof(GuardTraits) != details::dependent_zero<GuardTraits>>>
inline auto guard(Guard &&object, Callable &&callable)
-> guarded_wrap<Guard, Callable> {
return {
std::forward<Guard>(object),
std::forward<Callable>(callable)
};
}
template <
typename Guard,
typename Callable,
typename GuardTraits = guard_traits<std::decay_t<Guard>>,
typename = std::enable_if_t<
sizeof(GuardTraits) != details::dependent_zero<GuardTraits>>>
inline void on_main(Guard &&object, Callable &&callable) {
return on_main(guard(
std::forward<Guard>(object),
std::forward<Callable>(callable)));
}
template <
typename Guard,
typename Callable,
typename GuardTraits = guard_traits<std::decay_t<Guard>>,
typename = std::enable_if_t<
sizeof(GuardTraits) != details::dependent_zero<GuardTraits>>>
inline void on_main_sync(Guard &&object, Callable &&callable) {
return on_main_sync(guard(
std::forward<Guard>(object),
std::forward<Callable>(callable)));
}
} // namespace crl

View File

@@ -0,0 +1,53 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include <crl/crl_queue.h>
#ifdef CRL_USE_COMMON_QUEUE
#include <crl/crl_async.h>
#include <crl/crl_fp_exceptions.h>
namespace crl {
queue::queue() = default;
queue::queue(main_queue_processor processor) : _main_processor(processor) {
}
void queue::wake_async() {
if (!_queued.test_and_set()) {
(_main_processor ? _main_processor : details::async_plain)(
ProcessCallback,
static_cast<void*>(this));
}
}
void queue::process() {
if (!_list.process()) {
return;
}
_queued.clear();
if (!_list.empty()) {
wake_async();
}
}
void queue::ProcessCallback(void *that) {
#ifdef CRL_THROW_FP_EXCEPTIONS
static thread_local const bool kInited = [] {
toggle_fp_exceptions(true);
return true;
}();
#endif // CRL_THROW_FP_EXCEPTIONS
static_cast<queue*>(that)->process();
}
} // namespace crl
#endif // CRL_USE_COMMON_QUEUE

View File

@@ -0,0 +1,63 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <crl/common/crl_common_config.h>
#include <crl/common/crl_common_list.h>
#include <crl/common/crl_common_utils.h>
#include <atomic>
#ifndef CRL_USE_COMMON_QUEUE
#define CRL_USE_COMMON_QUEUE
#endif // !CRL_USE_COMMON_QUEUE
namespace crl {
namespace details {
class main_queue_pointer;
} // namespace details
class queue {
public:
queue();
queue(const queue &other) = delete;
queue &operator=(const queue &other) = delete;
template <typename Callable>
void async(Callable &&callable) {
if (_list.push_is_first(std::forward<Callable>(callable))) {
wake_async();
}
}
template <typename Callable>
void sync(Callable &&callable) {
semaphore waiter;
async([&] {
const auto guard = details::finally([&] { waiter.release(); });
callable();
});
waiter.acquire();
}
private:
friend class details::main_queue_pointer;
static void ProcessCallback(void *that);
queue(main_queue_processor processor);
void wake_async();
void process();
main_queue_processor _main_processor = nullptr;
details::list _list;
std::atomic_flag _queued = ATOMIC_FLAG_INIT;
};
} // namespace crl

View File

@@ -0,0 +1,35 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <crl/common/crl_common_config.h>
#include <semaphore>
namespace crl {
class semaphore {
public:
semaphore() = default;
semaphore(const semaphore &other) = delete;
semaphore &operator=(const semaphore &other) = delete;
semaphore(semaphore &&other) = delete;
semaphore &operator=(semaphore &&other) = delete;
void acquire() {
_impl.acquire();
}
void release() {
_impl.release();
}
private:
std::binary_semaphore _impl{0};
};
} // namespace crl

View File

@@ -0,0 +1,23 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <crl/crl_semaphore.h>
namespace crl {
template <typename Callable>
inline void sync(Callable &&callable) {
semaphore waiter;
async([&] {
const auto guard = details::finally([&] { waiter.release(); });
callable();
});
waiter.acquire();
}
} // namespace crl

View File

@@ -0,0 +1,73 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <crl/common/crl_common_config.h>
#include <utility>
namespace crl {
using main_queue_processor = void(*)(void (*callable)(void*), void *argument);
using main_queue_wrapper = void(*)(void (*callable)(void*), void *argument);
} // namespace crl
namespace crl::details {
using true_t = char;
struct false_t {
char data[2];
};
template <typename Return, typename ...Args>
struct check_plain_function {
static false_t check(...);
static true_t check(Return(*)(Args...));
};
template <typename Callable, typename Return, typename ...Args>
constexpr bool is_plain_function_v = sizeof(
check_plain_function<Return, Args...>::check(
std::declval<Callable>())) == sizeof(true_t);
template <typename Callable>
class finalizer {
public:
explicit finalizer(Callable &&callable)
: _callable(std::move(callable)) {
}
finalizer(const finalizer &other) = delete;
finalizer &operator=(const finalizer &other) = delete;
finalizer(finalizer &&other)
: _callable(std::move(other._callable))
, _disabled(std::exchange(other._disabled, true)) {
}
finalizer &operator=(finalizer &&other) {
_callable = std::move(other._callable);
_disabled = std::exchange(other._disabled, true);
return *this;
}
~finalizer() {
if (!_disabled) {
_callable();
}
}
private:
Callable _callable;
bool _disabled = false;
};
template <
typename Callable,
typename = std::enable_if_t<!std::is_reference_v<Callable>>>
finalizer<Callable> finally(Callable &&callable) {
return finalizer<Callable>{ std::move(callable) };
}
} // namespace crl::details