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
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
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
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
This commit is contained in:
87
Telegram/lib_crl/CMakeLists.txt
Normal file
87
Telegram/lib_crl/CMakeLists.txt
Normal file
@@ -0,0 +1,87 @@
|
||||
# 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
|
||||
|
||||
add_library(lib_crl OBJECT)
|
||||
add_library(desktop-app::lib_crl ALIAS lib_crl)
|
||||
init_target(lib_crl)
|
||||
|
||||
get_filename_component(src_loc . REALPATH)
|
||||
|
||||
nice_target_sources(lib_crl ${src_loc}
|
||||
PRIVATE
|
||||
crl/common/crl_common_config.h
|
||||
crl/common/crl_common_fp_exceptions.cpp
|
||||
crl/common/crl_common_guards.h
|
||||
crl/common/crl_common_list.cpp
|
||||
crl/common/crl_common_list.h
|
||||
crl/common/crl_common_object_async.h
|
||||
crl/common/crl_common_on_main.cpp
|
||||
crl/common/crl_common_on_main.h
|
||||
crl/common/crl_common_on_main_guarded.h
|
||||
crl/common/crl_common_queue.cpp
|
||||
crl/common/crl_common_queue.h
|
||||
crl/common/crl_common_semaphore.h
|
||||
crl/common/crl_common_sync.h
|
||||
crl/common/crl_common_utils.h
|
||||
crl/dispatch/crl_dispatch_async.cpp
|
||||
crl/dispatch/crl_dispatch_async.h
|
||||
crl/dispatch/crl_dispatch_on_main.h
|
||||
crl/dispatch/crl_dispatch_queue.cpp
|
||||
crl/dispatch/crl_dispatch_queue.h
|
||||
crl/dispatch/crl_dispatch_semaphore.cpp
|
||||
crl/dispatch/crl_dispatch_semaphore.h
|
||||
crl/mac/crl_mac_time.cpp
|
||||
crl/linux/crl_linux_time.cpp
|
||||
crl/qt/crl_qt_async.h
|
||||
crl/qt/crl_qt_guards.h
|
||||
crl/winapi/crl_winapi_async.cpp
|
||||
crl/winapi/crl_winapi_async.h
|
||||
crl/winapi/crl_winapi_dll.h
|
||||
crl/winapi/crl_winapi_fp_exceptions.cpp
|
||||
crl/winapi/crl_winapi_list.cpp
|
||||
crl/winapi/crl_winapi_list.h
|
||||
crl/winapi/crl_winapi_semaphore.cpp
|
||||
crl/winapi/crl_winapi_semaphore.h
|
||||
crl/winapi/crl_winapi_time.cpp
|
||||
crl/winapi/crl_winapi_windows_h.h
|
||||
crl/crl.h
|
||||
crl/crl_async.h
|
||||
crl/crl_fp_exceptions.h
|
||||
crl/crl_object_on_queue.h
|
||||
crl/crl_object_on_thread.cpp
|
||||
crl/crl_object_on_thread.h
|
||||
crl/crl_on_main.h
|
||||
crl/crl_queue.h
|
||||
crl/crl_semaphore.h
|
||||
crl/crl_time.cpp
|
||||
crl/crl_time.h
|
||||
)
|
||||
|
||||
target_include_directories(lib_crl
|
||||
PUBLIC
|
||||
${src_loc}
|
||||
)
|
||||
|
||||
if (TARGET desktop-app::external_dispatch)
|
||||
target_link_libraries(lib_crl
|
||||
PUBLIC
|
||||
desktop-app::external_dispatch
|
||||
)
|
||||
endif()
|
||||
|
||||
if (build_macstore OR TARGET desktop-app::external_dispatch)
|
||||
target_compile_definitions(lib_crl
|
||||
PUBLIC
|
||||
CRL_FORCE_COMMON_QUEUE
|
||||
)
|
||||
endif()
|
||||
|
||||
if (TARGET desktop-app::external_qt)
|
||||
target_link_libraries(lib_crl
|
||||
PUBLIC
|
||||
desktop-app::external_qt
|
||||
)
|
||||
endif()
|
||||
55
Telegram/lib_crl/crl/common/crl_common_config.h
Normal file
55
Telegram/lib_crl/crl/common/crl_common_config.h
Normal 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>)
|
||||
21
Telegram/lib_crl/crl/common/crl_common_fp_exceptions.cpp
Normal file
21
Telegram/lib_crl/crl/common/crl_common_fp_exceptions.cpp
Normal 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
|
||||
47
Telegram/lib_crl/crl/common/crl_common_guards.h
Normal file
47
Telegram/lib_crl/crl/common/crl_common_guards.h
Normal 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
|
||||
66
Telegram/lib_crl/crl/common/crl_common_list.cpp
Normal file
66
Telegram/lib_crl/crl/common/crl_common_list.cpp
Normal 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
|
||||
90
Telegram/lib_crl/crl/common/crl_common_list.h
Normal file
90
Telegram/lib_crl/crl/common/crl_common_list.h
Normal 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
|
||||
474
Telegram/lib_crl/crl/common/crl_common_object_async.h
Normal file
474
Telegram/lib_crl/crl/common/crl_common_object_async.h
Normal 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
|
||||
63
Telegram/lib_crl/crl/common/crl_common_on_main.cpp
Normal file
63
Telegram/lib_crl/crl/common/crl_common_on_main.cpp
Normal 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
|
||||
75
Telegram/lib_crl/crl/common/crl_common_on_main.h
Normal file
75
Telegram/lib_crl/crl/common/crl_common_on_main.h
Normal 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
|
||||
115
Telegram/lib_crl/crl/common/crl_common_on_main_guarded.h
Normal file
115
Telegram/lib_crl/crl/common/crl_common_on_main_guarded.h
Normal 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
|
||||
53
Telegram/lib_crl/crl/common/crl_common_queue.cpp
Normal file
53
Telegram/lib_crl/crl/common/crl_common_queue.cpp
Normal 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
|
||||
63
Telegram/lib_crl/crl/common/crl_common_queue.h
Normal file
63
Telegram/lib_crl/crl/common/crl_common_queue.h
Normal 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
|
||||
35
Telegram/lib_crl/crl/common/crl_common_semaphore.h
Normal file
35
Telegram/lib_crl/crl/common/crl_common_semaphore.h
Normal 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
|
||||
23
Telegram/lib_crl/crl/common/crl_common_sync.h
Normal file
23
Telegram/lib_crl/crl/common/crl_common_sync.h
Normal 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
|
||||
73
Telegram/lib_crl/crl/common/crl_common_utils.h
Normal file
73
Telegram/lib_crl/crl/common/crl_common_utils.h
Normal 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
|
||||
15
Telegram/lib_crl/crl/crl.h
Normal file
15
Telegram/lib_crl/crl/crl.h
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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>
|
||||
#include <crl/crl_async.h>
|
||||
#include <crl/crl_fp_exceptions.h>
|
||||
#include <crl/crl_queue.h>
|
||||
#include <crl/crl_on_main.h>
|
||||
#include <crl/crl_object_on_queue.h>
|
||||
#include <crl/crl_time.h>
|
||||
19
Telegram/lib_crl/crl/crl_async.h
Normal file
19
Telegram/lib_crl/crl/crl_async.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// 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
|
||||
#include <crl/winapi/crl_winapi_async.h>
|
||||
#elif defined CRL_USE_DISPATCH // CRL_USE_WINAPI
|
||||
#include <crl/dispatch/crl_dispatch_async.h>
|
||||
#elif defined CRL_USE_QT // CRL_USE_DISPATCH
|
||||
#include <crl/qt/crl_qt_async.h>
|
||||
#else // CRL_USE_QT
|
||||
#error "Configuration is not supported."
|
||||
#endif // !CRL_USE_WINAPI && !CRL_USE_DISPATCH && !CRL_USE_QT
|
||||
16
Telegram/lib_crl/crl/crl_fp_exceptions.h
Normal file
16
Telegram/lib_crl/crl/crl_fp_exceptions.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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>
|
||||
|
||||
namespace crl {
|
||||
|
||||
// Thread-local.
|
||||
void toggle_fp_exceptions(bool throwing);
|
||||
|
||||
} // namespace crl
|
||||
38
Telegram/lib_crl/crl/crl_object_on_queue.h
Normal file
38
Telegram/lib_crl/crl/crl_object_on_queue.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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_object_async.h>
|
||||
#include <crl/crl_queue.h>
|
||||
|
||||
namespace crl {
|
||||
namespace details {
|
||||
|
||||
class queue_policy {
|
||||
protected:
|
||||
template <typename Callable>
|
||||
void async_plain(Callable &&callable) const;
|
||||
|
||||
private:
|
||||
mutable crl::queue _queue;
|
||||
|
||||
};
|
||||
|
||||
template <typename Callable>
|
||||
void queue_policy::async_plain(Callable &&callable) const {
|
||||
_queue.async(std::forward<Callable>(callable));
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <typename Type>
|
||||
using weak_on_queue = details::weak_async<details::queue_policy, Type>;
|
||||
|
||||
template <typename Type>
|
||||
using object_on_queue = details::object_async<details::queue_policy, Type>;
|
||||
|
||||
} // namespace
|
||||
39
Telegram/lib_crl/crl/crl_object_on_thread.cpp
Normal file
39
Telegram/lib_crl/crl/crl_object_on_thread.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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_object_on_thread.h>
|
||||
|
||||
#include <crl/crl_fp_exceptions.h>
|
||||
#include <thread>
|
||||
|
||||
namespace crl::details {
|
||||
|
||||
thread_policy::thread_policy() {
|
||||
std::thread([=] { run(); }).detach();
|
||||
}
|
||||
|
||||
void thread_policy::run() {
|
||||
toggle_fp_exceptions(true);
|
||||
|
||||
while (true) {
|
||||
if (!_list.process()) {
|
||||
break;
|
||||
}
|
||||
_queued.clear();
|
||||
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_variable.wait(lock, [=] { return !_list.empty(); });
|
||||
}
|
||||
}
|
||||
|
||||
void thread_policy::wake_async() const {
|
||||
if (!_queued.test_and_set()) {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_variable.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace crl::details
|
||||
49
Telegram/lib_crl/crl/crl_object_on_thread.h
Normal file
49
Telegram/lib_crl/crl/crl_object_on_thread.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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_object_async.h>
|
||||
#include <crl/common/crl_common_list.h>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace crl {
|
||||
namespace details {
|
||||
|
||||
class thread_policy {
|
||||
protected:
|
||||
thread_policy();
|
||||
|
||||
template <typename Callable>
|
||||
void async_plain(Callable &&callable) const;
|
||||
|
||||
private:
|
||||
void run();
|
||||
void wake_async() const;
|
||||
|
||||
mutable std::mutex _mutex;
|
||||
mutable std::condition_variable _variable;
|
||||
mutable details::list _list;
|
||||
mutable std::atomic_flag _queued = ATOMIC_FLAG_INIT;
|
||||
|
||||
};
|
||||
|
||||
template <typename Callable>
|
||||
void thread_policy::async_plain(Callable &&callable) const {
|
||||
if (_list.push_is_first(std::forward<Callable>(callable))) {
|
||||
wake_async();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <typename Type>
|
||||
using weak_on_thread = details::weak_async<details::thread_policy, Type>;
|
||||
|
||||
template <typename Type>
|
||||
using object_on_thread = details::object_async<details::thread_policy, Type>;
|
||||
|
||||
} // namespace
|
||||
33
Telegram/lib_crl/crl/crl_on_main.h
Normal file
33
Telegram/lib_crl/crl/crl_on_main.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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>
|
||||
|
||||
#ifdef CRL_FORCE_COMMON_QUEUE
|
||||
#include <crl/common/crl_common_on_main.h>
|
||||
#elif defined CRL_USE_DISPATCH // CRL_FORCE_COMMON_QUEUE
|
||||
#include <crl/dispatch/crl_dispatch_on_main.h>
|
||||
#else // CRL_USE_DISPATCH
|
||||
#include <crl/common/crl_common_on_main.h>
|
||||
#endif // !CRL_FORCE_COMMON_QUEUE && !CRL_USE_DISPATCH
|
||||
|
||||
#include <crl/common/crl_common_on_main_guarded.h>
|
||||
#include <crl/common/crl_common_guards.h>
|
||||
#include <crl/qt/crl_qt_guards.h>
|
||||
|
||||
#ifdef CRL_ENABLE_RPL_INTEGRATION
|
||||
|
||||
#include <rpl/producer.h>
|
||||
|
||||
namespace crl {
|
||||
|
||||
rpl::producer<> on_main_update_requests();
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_ENABLE_RPL_INTEGRATION
|
||||
17
Telegram/lib_crl/crl/crl_queue.h
Normal file
17
Telegram/lib_crl/crl/crl_queue.h
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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>
|
||||
|
||||
#ifdef CRL_FORCE_COMMON_QUEUE
|
||||
#include <crl/common/crl_common_queue.h>
|
||||
#elif defined CRL_USE_DISPATCH // CRL_FORCE_COMMON_QUEUE
|
||||
#include <crl/dispatch/crl_dispatch_queue.h>
|
||||
#else // CRL_USE_DISPATCH
|
||||
#include <crl/common/crl_common_queue.h>
|
||||
#endif // !CRL_FORCE_COMMON_QUEUE && !CRL_USE_DISPATCH
|
||||
17
Telegram/lib_crl/crl/crl_semaphore.h
Normal file
17
Telegram/lib_crl/crl/crl_semaphore.h
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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
|
||||
#include <crl/winapi/crl_winapi_semaphore.h>
|
||||
#elif defined CRL_USE_DISPATCH // CRL_USE_WINAPI
|
||||
#include <crl/dispatch/crl_dispatch_semaphore.h>
|
||||
#else // CRL_USE_DISPATCH
|
||||
#include <crl/common/crl_common_semaphore.h>
|
||||
#endif // !CRL_USE_WINAPI && !CRL_USE_DISPATCH
|
||||
95
Telegram/lib_crl/crl/crl_time.cpp
Normal file
95
Telegram/lib_crl/crl/crl_time.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// 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>
|
||||
|
||||
#include <atomic>
|
||||
#include <ctime>
|
||||
#include <limits>
|
||||
|
||||
namespace crl {
|
||||
namespace details {
|
||||
namespace {
|
||||
|
||||
time LastAdjustmentTime/* = 0*/;
|
||||
std::time_t LastAdjustmentUnixtime/* = 0*/;
|
||||
|
||||
using seconds_type = std::uint32_t;
|
||||
std::atomic<seconds_type> AdjustSeconds/* = 0*/;
|
||||
|
||||
inner_time_type StartValue/* = 0*/;
|
||||
inner_profile_type StartProfileValue/* = 0*/;
|
||||
|
||||
struct StaticInit {
|
||||
StaticInit();
|
||||
};
|
||||
|
||||
StaticInit::StaticInit() {
|
||||
StartValue = current_value();
|
||||
StartProfileValue = current_profile_value();
|
||||
|
||||
init();
|
||||
|
||||
LastAdjustmentUnixtime = ::time(nullptr);
|
||||
}
|
||||
|
||||
StaticInit StaticInitObject;
|
||||
|
||||
bool adjust_time() {
|
||||
const auto now = crl::now();
|
||||
const auto delta = (now - LastAdjustmentTime);
|
||||
const auto unixtime = ::time(nullptr);
|
||||
const auto real = (unixtime - LastAdjustmentUnixtime);
|
||||
const auto seconds = (time(real) * 1000 - delta) / 1000;
|
||||
|
||||
LastAdjustmentUnixtime = unixtime;
|
||||
LastAdjustmentTime = now;
|
||||
|
||||
if (seconds <= 0) {
|
||||
return false;
|
||||
}
|
||||
auto current = seconds_type(0);
|
||||
static constexpr auto max = std::numeric_limits<seconds_type>::max();
|
||||
while (true) {
|
||||
if (time(current) + seconds > time(max)) {
|
||||
return false;
|
||||
}
|
||||
const auto next = current + seconds_type(seconds);
|
||||
if (AdjustSeconds.compare_exchange_weak(current, next)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
time compute_adjustment() {
|
||||
return time(AdjustSeconds.load()) * 1000;
|
||||
}
|
||||
|
||||
profile_time compute_profile_adjustment() {
|
||||
return compute_adjustment() * 1000;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace details
|
||||
|
||||
time now() {
|
||||
const auto elapsed = details::current_value() - details::StartValue;
|
||||
return details::convert(elapsed) + details::compute_adjustment();
|
||||
}
|
||||
|
||||
profile_time profile() {
|
||||
const auto elapsed = details::current_profile_value()
|
||||
- details::StartProfileValue;
|
||||
return details::convert_profile(elapsed)
|
||||
+ details::compute_profile_adjustment();
|
||||
}
|
||||
|
||||
bool adjust_time() {
|
||||
return details::adjust_time();
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
42
Telegram/lib_crl/crl/crl_time.h
Normal file
42
Telegram/lib_crl/crl/crl_time.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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 <cstdint>
|
||||
|
||||
// Use after main() started.
|
||||
|
||||
namespace crl {
|
||||
|
||||
using time = std::int64_t;
|
||||
using profile_time = std::int64_t;
|
||||
|
||||
namespace details {
|
||||
|
||||
using inner_time_type = std::int64_t;
|
||||
using inner_profile_type = std::int64_t;
|
||||
|
||||
void init();
|
||||
|
||||
inner_time_type current_value();
|
||||
time convert(inner_time_type value);
|
||||
|
||||
inner_profile_type current_profile_value();
|
||||
profile_time convert_profile(inner_profile_type);
|
||||
|
||||
} // namespace details
|
||||
|
||||
// Thread-safe.
|
||||
time now();
|
||||
profile_time profile();
|
||||
|
||||
// Returns true if some adjustment was made.
|
||||
bool adjust_time();
|
||||
|
||||
} // namespace crl
|
||||
45
Telegram/lib_crl/crl/dispatch/crl_dispatch_async.cpp
Normal file
45
Telegram/lib_crl/crl/dispatch/crl_dispatch_async.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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/dispatch/crl_dispatch_async.h>
|
||||
|
||||
#ifdef CRL_USE_DISPATCH
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
namespace crl::details {
|
||||
|
||||
void empty_main_wrapper(void (*callable)(void*), void *argument) {
|
||||
callable(argument);
|
||||
}
|
||||
|
||||
main_queue_wrapper _main_wrapper = &empty_main_wrapper;
|
||||
|
||||
void *background_queue_dispatch() {
|
||||
return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
}
|
||||
|
||||
void *main_queue_dispatch() {
|
||||
return dispatch_get_main_queue();
|
||||
}
|
||||
|
||||
void on_queue_async(void *queue, void (*callable)(void*), void *argument) {
|
||||
dispatch_async_f(
|
||||
static_cast<dispatch_queue_t>(queue),
|
||||
argument,
|
||||
callable);
|
||||
}
|
||||
|
||||
void on_queue_sync(void *queue, void (*callable)(void*), void *argument) {
|
||||
dispatch_sync_f(
|
||||
static_cast<dispatch_queue_t>(queue),
|
||||
argument,
|
||||
callable);
|
||||
}
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
#endif // CRL_USE_DISPATCH
|
||||
93
Telegram/lib_crl/crl/dispatch/crl_dispatch_async.h
Normal file
93
Telegram/lib_crl/crl/dispatch/crl_dispatch_async.h
Normal file
@@ -0,0 +1,93 @@
|
||||
// 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>
|
||||
|
||||
#ifdef CRL_USE_DISPATCH
|
||||
|
||||
#include <crl/common/crl_common_utils.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace crl::details {
|
||||
|
||||
void *background_queue_dispatch();
|
||||
void *main_queue_dispatch();
|
||||
|
||||
void on_queue_async(void *queue, void (*callable)(void*), void *argument);
|
||||
void on_queue_sync(void *queue, void (*callable)(void*), void *argument);
|
||||
|
||||
template <
|
||||
typename Wrapper,
|
||||
typename Invoker,
|
||||
typename Callable,
|
||||
typename Return = decltype(std::declval<Callable>()())>
|
||||
inline void on_queue_invoke(
|
||||
void *queue,
|
||||
Invoker invoker,
|
||||
Callable &&callable) {
|
||||
using Function = std::decay_t<Callable>;
|
||||
|
||||
if constexpr (details::is_plain_function_v<Function, Return>) {
|
||||
using Plain = Return(*)();
|
||||
static_assert(sizeof(Plain) <= sizeof(void*));
|
||||
const auto copy = static_cast<Plain>(callable);
|
||||
invoker(queue, [](void *passed) {
|
||||
Wrapper::Invoke([](void *passed) {
|
||||
const auto callable = reinterpret_cast<Plain>(passed);
|
||||
(*callable)();
|
||||
}, passed);
|
||||
}, reinterpret_cast<void*>(copy));
|
||||
} else {
|
||||
const auto copy = new Function(std::forward<Callable>(callable));
|
||||
invoker(queue, [](void *passed) {
|
||||
Wrapper::Invoke([](void *passed) {
|
||||
const auto callable = static_cast<Function*>(passed);
|
||||
const auto guard = details::finally([=] { delete callable; });
|
||||
(*callable)();
|
||||
}, passed);
|
||||
}, static_cast<void*>(copy));
|
||||
}
|
||||
}
|
||||
|
||||
struct EmptyWrapper {
|
||||
template <typename Callable>
|
||||
static inline void Invoke(Callable &&callable, void *argument) {
|
||||
callable(argument);
|
||||
}
|
||||
};
|
||||
|
||||
inline void async_plain(void (*callable)(void*), void *argument) {
|
||||
return on_queue_async(
|
||||
background_queue_dispatch(),
|
||||
callable,
|
||||
argument);
|
||||
}
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
namespace crl {
|
||||
|
||||
template <typename Callable>
|
||||
inline void async(Callable &&callable) {
|
||||
return details::on_queue_invoke<details::EmptyWrapper>(
|
||||
details::background_queue_dispatch(),
|
||||
details::on_queue_async,
|
||||
std::forward<Callable>(callable));
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
inline void sync(Callable &&callable) {
|
||||
return details::on_queue_invoke<details::EmptyWrapper>(
|
||||
details::background_queue_dispatch(),
|
||||
details::on_queue_sync,
|
||||
std::forward<Callable>(callable));
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_DISPATCH
|
||||
54
Telegram/lib_crl/crl/dispatch/crl_dispatch_on_main.h
Normal file
54
Telegram/lib_crl/crl/dispatch/crl_dispatch_on_main.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// 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_DISPATCH && !defined CRL_FORCE_COMMON_QUEUE
|
||||
|
||||
#include <crl/dispatch/crl_dispatch_async.h>
|
||||
#include <crl/common/crl_common_utils.h>
|
||||
|
||||
namespace crl {
|
||||
namespace details {
|
||||
|
||||
extern main_queue_wrapper _main_wrapper;
|
||||
|
||||
struct MainQueueWrapper {
|
||||
static inline void Invoke(void (*callable)(void*), void *argument) {
|
||||
_main_wrapper(callable, argument);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
inline void init_main_queue(main_queue_processor processor) {
|
||||
}
|
||||
|
||||
inline void wrap_main_queue(main_queue_wrapper wrapper) {
|
||||
details::_main_wrapper = wrapper;
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
inline void on_main(Callable &&callable) {
|
||||
return details::on_queue_invoke<details::MainQueueWrapper>(
|
||||
details::main_queue_dispatch(),
|
||||
details::on_queue_async,
|
||||
std::forward<Callable>(callable));
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
inline void on_main_sync(Callable &&callable) {
|
||||
return details::on_queue_invoke<details::MainQueueWrapper>(
|
||||
details::main_queue_dispatch(),
|
||||
details::on_queue_sync,
|
||||
std::forward<Callable>(callable));
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_DISPATCH && !CRL_FORCE_COMMON_QUEUE
|
||||
56
Telegram/lib_crl/crl/dispatch/crl_dispatch_queue.cpp
Normal file
56
Telegram/lib_crl/crl/dispatch/crl_dispatch_queue.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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/dispatch/crl_dispatch_queue.h>
|
||||
|
||||
#if defined CRL_USE_DISPATCH && !defined CRL_FORCE_COMMON_QUEUE
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <exception>
|
||||
|
||||
namespace crl {
|
||||
namespace {
|
||||
|
||||
dispatch_queue_t Unwrap(void *value) {
|
||||
return static_cast<dispatch_queue_t>(value);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
auto queue::implementation::create() -> pointer {
|
||||
auto result = dispatch_queue_create(nullptr, DISPATCH_QUEUE_SERIAL);
|
||||
if (!result) {
|
||||
std::terminate();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void queue::implementation::operator()(pointer value) {
|
||||
if (value) {
|
||||
dispatch_release(Unwrap(value));
|
||||
}
|
||||
};
|
||||
|
||||
queue::queue() : _handle(implementation::create()) {
|
||||
}
|
||||
|
||||
void queue::async_plain(void (*callable)(void*), void *argument) {
|
||||
dispatch_async_f(
|
||||
Unwrap(_handle.get()),
|
||||
argument,
|
||||
callable);
|
||||
}
|
||||
|
||||
void queue::sync_plain(void (*callable)(void*), void *argument) {
|
||||
dispatch_sync_f(
|
||||
Unwrap(_handle.get()),
|
||||
argument,
|
||||
callable);
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_DISPATCH && !CRL_FORCE_COMMON_QUEUE
|
||||
86
Telegram/lib_crl/crl/dispatch/crl_dispatch_queue.h
Normal file
86
Telegram/lib_crl/crl/dispatch/crl_dispatch_queue.h
Normal file
@@ -0,0 +1,86 @@
|
||||
// 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_DISPATCH && !defined CRL_FORCE_COMMON_QUEUE
|
||||
|
||||
#include <crl/common/crl_common_utils.h>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
namespace crl {
|
||||
|
||||
class queue {
|
||||
public:
|
||||
queue();
|
||||
|
||||
template <
|
||||
typename Callable,
|
||||
typename Return = decltype(std::declval<Callable>()())>
|
||||
void async(Callable &&callable) {
|
||||
using Function = std::decay_t<Callable>;
|
||||
|
||||
if constexpr (details::is_plain_function_v<Function, Return>) {
|
||||
using Plain = Return(*)();
|
||||
const auto copy = static_cast<Plain>(callable);
|
||||
async_plain([](void *passed) {
|
||||
const auto callable = reinterpret_cast<Plain>(passed);
|
||||
(*callable)();
|
||||
}, reinterpret_cast<void*>(copy));
|
||||
} else {
|
||||
const auto copy = new Function(std::forward<Callable>(callable));
|
||||
async_plain([](void *passed) {
|
||||
const auto callable = static_cast<Function*>(passed);
|
||||
const auto guard = details::finally([=] { delete callable; });
|
||||
(*callable)();
|
||||
}, static_cast<void*>(copy));
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
typename Callable,
|
||||
typename Return = decltype(std::declval<Callable>()())>
|
||||
void sync(Callable &&callable) {
|
||||
using Function = std::decay_t<Callable>;
|
||||
|
||||
if constexpr (details::is_plain_function_v<Function, Return>) {
|
||||
using Plain = Return(*)();
|
||||
const auto copy = static_cast<Plain>(callable);
|
||||
sync_plain([](void *passed) {
|
||||
const auto callable = reinterpret_cast<Plain>(passed);
|
||||
(*callable)();
|
||||
}, reinterpret_cast<void*>(copy));
|
||||
} else {
|
||||
const auto copy = new Function(std::forward<Callable>(callable));
|
||||
sync_plain([](void *passed) {
|
||||
const auto callable = static_cast<Function*>(passed);
|
||||
const auto guard = details::finally([=] { delete callable; });
|
||||
(*callable)();
|
||||
}, static_cast<void*>(copy));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Hide dispatch_queue_t
|
||||
struct implementation {
|
||||
using pointer = void*;
|
||||
static pointer create();
|
||||
void operator()(pointer value);
|
||||
};
|
||||
|
||||
void async_plain(void (*callable)(void*), void *argument);
|
||||
void sync_plain(void (*callable)(void*), void *argument);
|
||||
|
||||
std::unique_ptr<implementation::pointer, implementation> _handle;
|
||||
|
||||
};
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_DISPATCH && !CRL_FORCE_COMMON_QUEUE
|
||||
47
Telegram/lib_crl/crl/dispatch/crl_dispatch_semaphore.cpp
Normal file
47
Telegram/lib_crl/crl/dispatch/crl_dispatch_semaphore.cpp
Normal 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
|
||||
//
|
||||
#include <crl/dispatch/crl_dispatch_semaphore.h>
|
||||
|
||||
#ifdef CRL_USE_DISPATCH
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <exception>
|
||||
|
||||
namespace crl {
|
||||
namespace {
|
||||
|
||||
dispatch_semaphore_t Unwrap(void *value) {
|
||||
return static_cast<dispatch_semaphore_t>(value);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
auto semaphore::implementation::create() -> pointer {
|
||||
auto result = dispatch_semaphore_create(0);
|
||||
if (!result) {
|
||||
std::terminate();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void semaphore::implementation::operator()(pointer value) {
|
||||
if (value) {
|
||||
dispatch_release(Unwrap(value));
|
||||
}
|
||||
};
|
||||
|
||||
void semaphore::acquire() {
|
||||
dispatch_semaphore_wait(Unwrap(_handle.get()), DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
void semaphore::release() {
|
||||
dispatch_semaphore_signal(Unwrap(_handle.get()));
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_DISPATCH
|
||||
47
Telegram/lib_crl/crl/dispatch/crl_dispatch_semaphore.h
Normal file
47
Telegram/lib_crl/crl/dispatch/crl_dispatch_semaphore.h
Normal 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>
|
||||
|
||||
#ifdef CRL_USE_DISPATCH
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace crl {
|
||||
|
||||
class semaphore {
|
||||
public:
|
||||
semaphore() : _handle(implementation::create()) {
|
||||
}
|
||||
semaphore(const semaphore &other) = delete;
|
||||
semaphore &operator=(const semaphore &other) = delete;
|
||||
semaphore(semaphore &&other) noexcept
|
||||
: _handle(std::move(other._handle)) {
|
||||
}
|
||||
semaphore &operator=(semaphore &&other) noexcept {
|
||||
_handle = std::move(other._handle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void acquire();
|
||||
void release();
|
||||
|
||||
private:
|
||||
// Hide dispatch_semaphore_t
|
||||
struct implementation {
|
||||
using pointer = void*;
|
||||
static pointer create();
|
||||
void operator()(pointer value);
|
||||
};
|
||||
std::unique_ptr<implementation::pointer, implementation> _handle;
|
||||
|
||||
};
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_DISPATCH
|
||||
44
Telegram/lib_crl/crl/linux/crl_linux_time.cpp
Normal file
44
Telegram/lib_crl/crl/linux/crl_linux_time.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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>
|
||||
|
||||
#ifdef CRL_USE_LINUX_TIME
|
||||
|
||||
#include <time.h>
|
||||
|
||||
namespace crl::details {
|
||||
|
||||
void init() {
|
||||
}
|
||||
|
||||
inner_time_type current_value() {
|
||||
timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
const auto seconds = inner_time_type(ts.tv_sec);
|
||||
const auto milliseconds = inner_time_type(ts.tv_nsec) / 1000000;
|
||||
return seconds * 1000 + milliseconds;
|
||||
}
|
||||
|
||||
time convert(inner_time_type value) {
|
||||
return time(value);
|
||||
}
|
||||
|
||||
inner_profile_type current_profile_value() {
|
||||
timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
const auto seconds = inner_profile_type(ts.tv_sec);
|
||||
const auto milliseconds = inner_profile_type(ts.tv_nsec) / 1000;
|
||||
return seconds * 1000000 + milliseconds;
|
||||
}
|
||||
|
||||
profile_time convert_profile(inner_profile_type value) {
|
||||
return profile_time(value);
|
||||
}
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
#endif // CRL_USE_LINUX_TIME
|
||||
46
Telegram/lib_crl/crl/mac/crl_mac_time.cpp
Normal file
46
Telegram/lib_crl/crl/mac/crl_mac_time.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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>
|
||||
|
||||
#ifdef CRL_USE_MAC_TIME
|
||||
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
namespace crl::details {
|
||||
namespace {
|
||||
|
||||
double Frequency/* = 0.*/;
|
||||
double ProfileFrequency/* = 0.*/;
|
||||
|
||||
} // namespace
|
||||
|
||||
void init() {
|
||||
mach_timebase_info_data_t tb = { 0, 0 };
|
||||
mach_timebase_info(&tb);
|
||||
Frequency = (double(tb.numer) / tb.denom) / 1000000.;
|
||||
ProfileFrequency = (double(tb.numer) / tb.denom) / 1000.;
|
||||
}
|
||||
|
||||
inner_time_type current_value() {
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
time convert(inner_time_type value) {
|
||||
return time(value * Frequency);
|
||||
}
|
||||
|
||||
inner_profile_type current_profile_value() {
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
profile_time convert_profile(inner_profile_type value) {
|
||||
return profile_time(value * ProfileFrequency);
|
||||
}
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
#endif // CRL_USE_MAC_TIME
|
||||
72
Telegram/lib_crl/crl/qt/crl_qt_async.h
Normal file
72
Telegram/lib_crl/crl/qt/crl_qt_async.h
Normal file
@@ -0,0 +1,72 @@
|
||||
// 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>
|
||||
|
||||
#ifdef CRL_USE_QT
|
||||
|
||||
#include <crl/common/crl_common_utils.h>
|
||||
#include <crl/common/crl_common_sync.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include <QtCore/QThreadPool>
|
||||
|
||||
namespace crl::details {
|
||||
|
||||
template <typename Callable>
|
||||
class Runnable : public QRunnable {
|
||||
public:
|
||||
Runnable(Callable &&callable) : _callable(std::move(callable)) {
|
||||
}
|
||||
|
||||
void run() override {
|
||||
_callable();
|
||||
}
|
||||
|
||||
private:
|
||||
Callable _callable;
|
||||
|
||||
};
|
||||
|
||||
template <typename Callable>
|
||||
inline auto create_runnable(Callable &&callable) {
|
||||
if constexpr (std::is_reference_v<Callable>) {
|
||||
auto copy = callable;
|
||||
return create_runnable(std::move(copy));
|
||||
} else {
|
||||
return new Runnable<Callable>(std::move(callable));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
inline void async_any(Callable &&callable) {
|
||||
if (const auto pool = QThreadPool::globalInstance()) {
|
||||
pool->start(create_runnable(std::forward<Callable>(callable)));
|
||||
}
|
||||
}
|
||||
|
||||
inline void async_plain(void (*callable)(void*), void *argument) {
|
||||
async_any([=] {
|
||||
callable(argument);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
namespace crl {
|
||||
|
||||
template <
|
||||
typename Callable,
|
||||
typename Return = decltype(std::declval<Callable>()())>
|
||||
inline void async(Callable &&callable) {
|
||||
details::async_any(std::forward<Callable>(callable));
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_QT
|
||||
116
Telegram/lib_crl/crl/qt/crl_qt_guards.h
Normal file
116
Telegram/lib_crl/crl/qt/crl_qt_guards.h
Normal file
@@ -0,0 +1,116 @@
|
||||
// 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 __has_include(<QtCore/QPointer>)
|
||||
|
||||
class QObject;
|
||||
|
||||
template <typename T>
|
||||
class QPointer;
|
||||
|
||||
template <typename T>
|
||||
class QWeakPointer;
|
||||
|
||||
template <typename T>
|
||||
class QSharedPointer;
|
||||
|
||||
#if __has_include(<gsl/gsl>)
|
||||
|
||||
namespace gsl {
|
||||
|
||||
template <typename T>
|
||||
class not_null;
|
||||
|
||||
} // namespace gsl
|
||||
|
||||
#endif // gsl
|
||||
|
||||
namespace crl {
|
||||
|
||||
template <typename T, typename Enable>
|
||||
struct guard_traits;
|
||||
|
||||
template <typename T>
|
||||
struct guard_traits<QPointer<T>, void> {
|
||||
static QPointer<T> create(const QPointer<T> &value) {
|
||||
return value;
|
||||
}
|
||||
static QPointer<T> create(QPointer<T> &&value) {
|
||||
return std::move(value);
|
||||
}
|
||||
static bool check(const QPointer<T> &guard) {
|
||||
return guard.data() != nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct guard_traits<
|
||||
T*,
|
||||
std::enable_if_t<
|
||||
std::is_base_of_v<QObject, std::remove_cv_t<T>>>> {
|
||||
static QPointer<T> create(T *value) {
|
||||
return value;
|
||||
}
|
||||
static bool check(const QPointer<T> &guard) {
|
||||
return guard.data() != nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#if __has_include(<gsl/gsl>)
|
||||
|
||||
template <typename T>
|
||||
struct guard_traits<
|
||||
gsl::not_null<T*>,
|
||||
std::enable_if_t<
|
||||
std::is_base_of_v<QObject, std::remove_cv_t<T>>>> {
|
||||
static QPointer<T> create(gsl::not_null<T*> value) {
|
||||
return value.get();
|
||||
}
|
||||
static bool check(const QPointer<T> &guard) {
|
||||
return guard.data() != nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // gsl
|
||||
|
||||
template <typename T>
|
||||
struct guard_traits<QWeakPointer<T>, void> {
|
||||
static QWeakPointer<T> create(const QWeakPointer<T> &value) {
|
||||
return value;
|
||||
}
|
||||
static QWeakPointer<T> create(QWeakPointer<T> &&value) {
|
||||
return std::move(value);
|
||||
}
|
||||
static bool check(const QWeakPointer<T> &guard) {
|
||||
return guard.toStrongRef() != nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct guard_traits<QSharedPointer<T>, void> {
|
||||
static QWeakPointer<T> create(const QSharedPointer<T> &value) {
|
||||
return value;
|
||||
}
|
||||
static QWeakPointer<T> create(QSharedPointer<T> &&value) {
|
||||
return value;
|
||||
}
|
||||
static bool check(const QWeakPointer<T> &guard) {
|
||||
return guard.toStrongRef() != nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // Qt
|
||||
21
Telegram/lib_crl/crl/winapi/crl_winapi_async.cpp
Normal file
21
Telegram/lib_crl/crl/winapi/crl_winapi_async.cpp
Normal 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/winapi/crl_winapi_async.h>
|
||||
|
||||
#ifdef CRL_USE_WINAPI
|
||||
|
||||
#include <concrt.h>
|
||||
|
||||
namespace crl::details {
|
||||
|
||||
void async_plain(void (*callable)(void*), void *argument) {
|
||||
Concurrency::CurrentScheduler::ScheduleTask(callable, argument);
|
||||
}
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
#endif // CRL_USE_WINAPI
|
||||
50
Telegram/lib_crl/crl/winapi/crl_winapi_async.h
Normal file
50
Telegram/lib_crl/crl/winapi/crl_winapi_async.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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>
|
||||
|
||||
#ifdef CRL_USE_WINAPI
|
||||
|
||||
#include <crl/common/crl_common_utils.h>
|
||||
#include <crl/common/crl_common_sync.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace crl::details {
|
||||
|
||||
void async_plain(void (*callable)(void*), void *argument);
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
namespace crl {
|
||||
|
||||
template <
|
||||
typename Callable,
|
||||
typename Return = decltype(std::declval<Callable>()())>
|
||||
inline void async(Callable &&callable) {
|
||||
using Function = std::decay_t<Callable>;
|
||||
|
||||
if constexpr (details::is_plain_function_v<Function, Return>) {
|
||||
using Plain = Return(*)();
|
||||
const auto copy = static_cast<Plain>(callable);
|
||||
details::async_plain([](void *passed) {
|
||||
const auto callable = reinterpret_cast<Plain>(passed);
|
||||
(*callable)();
|
||||
}, reinterpret_cast<void*>(copy));
|
||||
} else {
|
||||
const auto copy = new Function(std::forward<Callable>(callable));
|
||||
details::async_plain([](void *passed) {
|
||||
const auto callable = static_cast<Function*>(passed);
|
||||
const auto guard = details::finally([=] { delete callable; });
|
||||
(*callable)();
|
||||
}, static_cast<void*>(copy));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_WINAPI
|
||||
66
Telegram/lib_crl/crl/winapi/crl_winapi_dll.h
Normal file
66
Telegram/lib_crl/crl/winapi/crl_winapi_dll.h
Normal 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
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <crl/common/crl_common_config.h>
|
||||
|
||||
#ifdef CRL_USE_WINAPI
|
||||
|
||||
#include <exception>
|
||||
#include <crl/winapi/crl_winapi_windows_h.h>
|
||||
|
||||
namespace crl::details {
|
||||
|
||||
class dll {
|
||||
public:
|
||||
enum class own_policy {
|
||||
owner,
|
||||
load_and_leak,
|
||||
use_existing,
|
||||
};
|
||||
dll(LPCWSTR library, own_policy policy)
|
||||
: _handle((policy == own_policy::use_existing)
|
||||
? GetModuleHandle(library)
|
||||
: LoadLibrary(library))
|
||||
, _policy(policy) {
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
bool try_load(Function &function, const char *name) const {
|
||||
if (!_handle) {
|
||||
return false;
|
||||
}
|
||||
function = reinterpret_cast<Function>(GetProcAddress(_handle, name));
|
||||
return (function != nullptr);
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
void load(Function &function, const char *name) const {
|
||||
if (!try_load(function, name)) {
|
||||
Failed();
|
||||
}
|
||||
}
|
||||
|
||||
~dll() {
|
||||
if (_handle && _policy == own_policy::owner) {
|
||||
FreeLibrary(_handle);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
[[noreturn]] static void Failed() {
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
HMODULE _handle = nullptr;
|
||||
own_policy _policy = own_policy::use_existing;
|
||||
|
||||
};
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
#endif // CRL_USE_WINAPI
|
||||
47
Telegram/lib_crl/crl/winapi/crl_winapi_fp_exceptions.cpp
Normal file
47
Telegram/lib_crl/crl/winapi/crl_winapi_fp_exceptions.cpp
Normal 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
|
||||
//
|
||||
#include <crl/crl_time.h>
|
||||
|
||||
#ifdef CRL_USE_WINAPI_TIME
|
||||
|
||||
#ifdef CRL_THROW_FP_EXCEPTIONS
|
||||
|
||||
#include <float.h>
|
||||
#pragma fenv_access (on)
|
||||
|
||||
namespace crl {
|
||||
|
||||
void toggle_fp_exceptions(bool throwing) {
|
||||
// Allow throwing (and reporting) floating point exceptions.
|
||||
//
|
||||
// Otherwise x86 build behaves unpredictably on old hardware,
|
||||
// after an fp-error it may fail some benign operations, like
|
||||
// std::round(1.) giving 'nan' or double -> int64 giving int64_min.
|
||||
//
|
||||
// This results in unexpected assertion violations.
|
||||
auto state = (unsigned int)0;
|
||||
|
||||
// Right now catch only division by zero and invalid operations.
|
||||
const auto bits = (throwing ? 0 : (_EM_ZERODIVIDE | _EM_INVALID))
|
||||
| _EM_DENORMAL | _EM_INEXACT | _EM_UNDERFLOW | _EM_OVERFLOW;
|
||||
_controlfp_s(&state, bits, _MCW_EM);
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#else // CRL_THROW_FP_EXCEPTIONS
|
||||
|
||||
namespace crl {
|
||||
|
||||
void toggle_fp_exceptions(bool throwing) {
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_THROW_FP_EXCEPTIONS
|
||||
|
||||
#endif // CRL_USE_WINAPI_TIME
|
||||
23
Telegram/lib_crl/crl/winapi/crl_winapi_fp_exceptions.h
Normal file
23
Telegram/lib_crl/crl/winapi/crl_winapi_fp_exceptions.h
Normal 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/common/crl_common_config.h>
|
||||
|
||||
#ifdef CRL_USE_WINAPI
|
||||
|
||||
#include <crl/common/crl_common_utils.h>
|
||||
#include <crl/common/crl_common_sync.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace crl {
|
||||
|
||||
void toggle_fp_exceptions(bool throwing);
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_WINAPI
|
||||
92
Telegram/lib_crl/crl/winapi/crl_winapi_list.cpp
Normal file
92
Telegram/lib_crl/crl/winapi/crl_winapi_list.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// 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/winapi/crl_winapi_list.h>
|
||||
|
||||
#ifdef CRL_USE_WINAPI_LIST
|
||||
|
||||
#include <crl/winapi/crl_winapi_dll.h>
|
||||
#include <crl/winapi/crl_winapi_windows_h.h>
|
||||
|
||||
namespace crl::details {
|
||||
namespace {
|
||||
|
||||
PSLIST_HEADER UnwrapList(void *wrapped) {
|
||||
return static_cast<PSLIST_HEADER>(wrapped);
|
||||
}
|
||||
|
||||
PSLIST_ENTRY UnwrapEntry(void *wrapped) {
|
||||
return static_cast<PSLIST_ENTRY>(wrapped);
|
||||
}
|
||||
|
||||
SLIST_ENTRY *ReverseList(SLIST_ENTRY *entry, SLIST_ENTRY *next) {
|
||||
entry->Next = nullptr;
|
||||
do {
|
||||
auto third = next->Next;
|
||||
next->Next = entry;
|
||||
entry = next;
|
||||
next = third;
|
||||
} while (next);
|
||||
return entry;
|
||||
}
|
||||
|
||||
PSLIST_ENTRY (NTAPI *RtlFirstEntrySList)(const SLIST_HEADER *ListHead) = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
list::list()
|
||||
: _impl(std::make_unique<lock_free_list>())
|
||||
, _alive(new bool(true)) {
|
||||
static auto initialize = [] {
|
||||
const auto library = details::dll(
|
||||
L"ntdll.dll",
|
||||
details::dll::own_policy::load_and_leak);
|
||||
library.load(RtlFirstEntrySList, "RtlFirstEntrySList");
|
||||
return true;
|
||||
}(); // TODO crl::once?..
|
||||
|
||||
static_assert(alignof(lock_free_list) == MEMORY_ALLOCATION_ALIGNMENT);
|
||||
static_assert(alignof(lock_free_list) >= alignof(SLIST_HEADER));
|
||||
static_assert(sizeof(lock_free_list) == sizeof(SLIST_HEADER));
|
||||
InitializeSListHead(UnwrapList(_impl.get()));
|
||||
}
|
||||
|
||||
bool list::push_entry(BasicEntry *entry) {
|
||||
return (InterlockedPushEntrySList(
|
||||
UnwrapList(_impl.get()),
|
||||
UnwrapEntry(&entry->plain)) == nullptr);
|
||||
}
|
||||
|
||||
bool list::empty() const {
|
||||
return RtlFirstEntrySList(UnwrapList(_impl.get())) == nullptr;
|
||||
}
|
||||
|
||||
bool list::process() {
|
||||
if (auto entry = InterlockedFlushSList(UnwrapList(_impl.get()))) {
|
||||
const auto alive = _alive;
|
||||
if (const auto next = entry->Next) {
|
||||
entry = ReverseList(entry, next);
|
||||
}
|
||||
do {
|
||||
const auto basic = reinterpret_cast<BasicEntry*>(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_WINAPI_LIST
|
||||
101
Telegram/lib_crl/crl/winapi/crl_winapi_list.h
Normal file
101
Telegram/lib_crl/crl/winapi/crl_winapi_list.h
Normal file
@@ -0,0 +1,101 @@
|
||||
// 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>
|
||||
|
||||
#ifdef CRL_USE_WINAPI_LIST
|
||||
|
||||
#include <crl/common/crl_common_utils.h>
|
||||
#include <crl/crl_semaphore.h>
|
||||
|
||||
#ifndef CRL_USE_WINAPI
|
||||
#error "This file should not be included by client-code directly."
|
||||
#endif // CRL_USE_WINAPI
|
||||
|
||||
namespace crl::details {
|
||||
|
||||
class list {
|
||||
public:
|
||||
list();
|
||||
list(const list &other) = delete;
|
||||
list &operator=(const list &other) = delete;
|
||||
|
||||
template <typename Callable>
|
||||
bool push_is_first(Callable &&callable) {
|
||||
return push_entry(AllocateEntry(std::forward<Callable>(callable)));
|
||||
}
|
||||
bool process();
|
||||
bool empty() const;
|
||||
|
||||
~list();
|
||||
|
||||
private:
|
||||
#if defined CRL_WINAPI_X64
|
||||
static constexpr auto kLockFreeAlignment = 16;
|
||||
#elif defined CRL_WINAPI_X86 // CRL_WINAPI_X64
|
||||
static constexpr auto kLockFreeAlignment = 8;
|
||||
#else // CRL_WINAPI_X86
|
||||
#error "Configuration is not supported."
|
||||
#endif // !CRL_WINAPI_X86 && !CRL_WINAPI_X64
|
||||
|
||||
// Hide WinAPI SLIST_HEADER
|
||||
struct alignas(kLockFreeAlignment) lock_free_list {
|
||||
void *Next__; // Hide WinAPI SLIST_ENTRY
|
||||
unsigned short Depth__; // Hide WinAPI WORD
|
||||
unsigned short CpuId__; // Hide WinAPI WORD
|
||||
};
|
||||
|
||||
struct alignas(kLockFreeAlignment) BasicEntry;
|
||||
using ProcessEntryMethod = void(*)(BasicEntry *entry);
|
||||
|
||||
struct alignas(kLockFreeAlignment) BasicEntry {
|
||||
void *plain; // Hide WinAPI SLIST_ENTRY
|
||||
ProcessEntryMethod process;
|
||||
};
|
||||
|
||||
static_assert(std::is_trivial_v<BasicEntry>);
|
||||
static_assert(std::is_standard_layout_v<BasicEntry>);
|
||||
static_assert(offsetof(BasicEntry, plain) == 0);
|
||||
|
||||
template <typename Function>
|
||||
struct Entry : BasicEntry {
|
||||
Entry(Function &&function) : function(std::move(function)) {
|
||||
}
|
||||
Entry(const Function &function) : 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>;
|
||||
|
||||
auto result = new Type(std::forward<Callable>(callable));
|
||||
result->process = &Type::Process;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool push_entry(BasicEntry *entry);
|
||||
|
||||
const std::unique_ptr<lock_free_list> _impl;
|
||||
bool *_alive = nullptr;
|
||||
|
||||
};
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
#endif // CRL_USE_WINAPI_LIST
|
||||
39
Telegram/lib_crl/crl/winapi/crl_winapi_semaphore.cpp
Normal file
39
Telegram/lib_crl/crl/winapi/crl_winapi_semaphore.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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/winapi/crl_winapi_semaphore.h>
|
||||
|
||||
#ifdef CRL_USE_WINAPI
|
||||
|
||||
#include <crl/winapi/crl_winapi_windows_h.h>
|
||||
|
||||
namespace crl {
|
||||
|
||||
auto semaphore::implementation::create() -> pointer {
|
||||
auto result = CreateSemaphore(nullptr, 0, 1, nullptr);
|
||||
if (!result) {
|
||||
std::terminate();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void semaphore::implementation::operator()(pointer value) {
|
||||
if (value) {
|
||||
CloseHandle(value);
|
||||
}
|
||||
};
|
||||
|
||||
void semaphore::acquire() {
|
||||
WaitForSingleObject(_handle.get(), INFINITE);
|
||||
}
|
||||
|
||||
void semaphore::release() {
|
||||
ReleaseSemaphore(_handle.get(), 1, nullptr);
|
||||
}
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_WINAPI
|
||||
47
Telegram/lib_crl/crl/winapi/crl_winapi_semaphore.h
Normal file
47
Telegram/lib_crl/crl/winapi/crl_winapi_semaphore.h
Normal 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>
|
||||
|
||||
#ifdef CRL_USE_WINAPI
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace crl {
|
||||
|
||||
class semaphore {
|
||||
public:
|
||||
semaphore() : _handle(implementation::create()) {
|
||||
}
|
||||
semaphore(const semaphore &other) = delete;
|
||||
semaphore &operator=(const semaphore &other) = delete;
|
||||
semaphore(semaphore &&other) noexcept
|
||||
: _handle(std::move(other._handle)) {
|
||||
}
|
||||
semaphore &operator=(semaphore &&other) noexcept {
|
||||
_handle = std::move(other._handle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void acquire();
|
||||
void release();
|
||||
|
||||
private:
|
||||
// Hide WinAPI HANDLE
|
||||
struct implementation {
|
||||
using pointer = void*;
|
||||
static pointer create();
|
||||
void operator()(pointer value);
|
||||
};
|
||||
std::unique_ptr<implementation::pointer, implementation> _handle;
|
||||
|
||||
};
|
||||
|
||||
} // namespace crl
|
||||
|
||||
#endif // CRL_USE_WINAPI
|
||||
50
Telegram/lib_crl/crl/winapi/crl_winapi_time.cpp
Normal file
50
Telegram/lib_crl/crl/winapi/crl_winapi_time.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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>
|
||||
|
||||
#ifdef CRL_USE_WINAPI_TIME
|
||||
|
||||
#include <crl/winapi/crl_winapi_windows_h.h>
|
||||
|
||||
namespace crl::details {
|
||||
namespace {
|
||||
|
||||
double Frequency/* = 0.*/;
|
||||
double ProfileFrequency/* = 0.*/;
|
||||
|
||||
} // namespace
|
||||
|
||||
void init() {
|
||||
LARGE_INTEGER value;
|
||||
QueryPerformanceFrequency(&value);
|
||||
Frequency = 1000. / double(value.QuadPart);
|
||||
ProfileFrequency = 1000000. / double(value.QuadPart);
|
||||
}
|
||||
|
||||
inner_time_type current_value() {
|
||||
LARGE_INTEGER value;
|
||||
QueryPerformanceCounter(&value);
|
||||
return value.QuadPart;
|
||||
}
|
||||
|
||||
time convert(inner_time_type value) {
|
||||
return time(value * Frequency);
|
||||
}
|
||||
|
||||
inner_profile_type current_profile_value() {
|
||||
LARGE_INTEGER value;
|
||||
QueryPerformanceCounter(&value);
|
||||
return value.QuadPart;
|
||||
}
|
||||
|
||||
profile_time convert_profile(inner_profile_type value) {
|
||||
return profile_time(value * ProfileFrequency);
|
||||
}
|
||||
|
||||
} // namespace crl::details
|
||||
|
||||
#endif // CRL_USE_WINAPI_TIME
|
||||
13
Telegram/lib_crl/crl/winapi/crl_winapi_windows_h.h
Normal file
13
Telegram/lib_crl/crl/winapi/crl_winapi_windows_h.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// 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 <windows.h>
|
||||
|
||||
#ifdef small
|
||||
#undef small
|
||||
#endif // small
|
||||
Reference in New Issue
Block a user