summaryrefslogtreecommitdiffhomepage
path: root/compat
diff options
context:
space:
mode:
Diffstat (limited to 'compat')
-rw-r--r--compat/CMakeLists.txt9
-rw-r--r--compat/activation-context.cpp51
-rw-r--r--compat/activation-context.hpp26
-rw-r--r--compat/arch.hpp50
-rw-r--r--compat/base-path.cpp10
-rw-r--r--compat/base-path.hpp3
-rw-r--r--compat/camera-names.cpp117
-rw-r--r--compat/camera-names.hpp5
-rw-r--r--compat/check-visible.cpp105
-rw-r--r--compat/check-visible.hpp14
-rw-r--r--compat/copyable-mutex.cpp36
-rw-r--r--compat/copyable-mutex.hpp27
-rw-r--r--compat/correlation-calibrator.cpp44
-rw-r--r--compat/correlation-calibrator.hpp30
-rw-r--r--compat/enum-operators.hpp45
-rw-r--r--compat/euler.cpp61
-rw-r--r--compat/euler.hpp6
-rw-r--r--compat/hamilton-tools.cpp109
-rw-r--r--compat/hamilton-tools.h76
-rw-r--r--compat/lang/de_DE.ts4
-rw-r--r--compat/lang/zh_CN.ts2
-rw-r--r--compat/library-path.hpp2
-rw-r--r--compat/linkage-macros.hpp33
-rw-r--r--compat/macros.h57
-rw-r--r--compat/macros.hpp54
-rw-r--r--compat/math.hpp68
-rw-r--r--compat/meta.hpp124
-rw-r--r--compat/mutex.cpp33
-rw-r--r--compat/mutex.hpp24
-rw-r--r--compat/process-list.hpp65
-rw-r--r--compat/qhash.hpp26
-rw-r--r--compat/qt-dpi.hpp24
-rw-r--r--compat/qt-signal.cpp7
-rw-r--r--compat/qt-signal.hpp72
-rw-r--r--compat/run-in-thread.hpp108
-rw-r--r--compat/shm.cpp133
-rw-r--r--compat/shm.h17
-rw-r--r--compat/simple-mat.hpp250
-rw-r--r--compat/sleep.cpp23
-rw-r--r--compat/sleep.hpp23
-rw-r--r--compat/sysexits.hpp28
-rw-r--r--compat/thread-name.cpp87
-rw-r--r--compat/thread-name.hpp6
-rw-r--r--compat/time.hpp16
-rw-r--r--compat/timer.cpp88
-rw-r--r--compat/timer.hpp38
-rw-r--r--compat/tr.hpp14
-rw-r--r--compat/variance.hpp24
48 files changed, 1430 insertions, 844 deletions
diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt
index b58b54e9..dc81436d 100644
--- a/compat/CMakeLists.txt
+++ b/compat/CMakeLists.txt
@@ -1,14 +1,9 @@
otr_module(compat NO-COMPAT BIN)
if(NOT WIN32 AND NOT APPLE)
- target_link_libraries(opentrack-compat rt)
+ target_link_libraries(${self} rt)
endif()
if(WIN32)
- target_link_libraries(opentrack-compat winmm strmiids)
-endif()
-
-if(CMAKE_COMPILER_IS_GNUCXX)
- set_property(SOURCE nan.cpp APPEND_STRING PROPERTY
- COMPILE_FLAGS "-fno-lto -fno-fast-math -fno-finite-math-only -O0 ")
+ target_link_libraries(${self} strmiids)
endif()
diff --git a/compat/activation-context.cpp b/compat/activation-context.cpp
new file mode 100644
index 00000000..8d34243d
--- /dev/null
+++ b/compat/activation-context.cpp
@@ -0,0 +1,51 @@
+#ifdef _WIN32
+
+#include "activation-context.hpp"
+#include "compat/library-path.hpp"
+
+#include <QString>
+#include <QFile>
+#include <QDebug>
+
+#include <windows.h>
+
+static_assert(sizeof(std::uintptr_t) == sizeof(ULONG_PTR));
+
+activation_context::activation_context(const QString& module_name, int resid)
+{
+ static const QString prefix = OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH + OPENTRACK_LIBRARY_PREFIX;
+ QString path = prefix + module_name;
+ QByteArray name = QFile::encodeName(path);
+
+ ACTCTXA actx = {};
+ actx.cbSize = sizeof(actx);
+ actx.lpResourceName = MAKEINTRESOURCEA(resid);
+ actx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
+ actx.lpSource = name.constData();
+
+ handle = CreateActCtxA(&actx);
+
+ if (handle != INVALID_HANDLE_VALUE)
+ {
+ if (!ActivateActCtx(handle, (ULONG_PTR*)&cookie))
+ {
+ qDebug() << "win32: can't set activation context" << GetLastError();
+ ReleaseActCtx(handle);
+ handle = INVALID_HANDLE_VALUE;
+ }
+ else
+ ok = true;
+ } else {
+ qDebug() << "win32: can't create activation context" << GetLastError();
+ }
+}
+
+activation_context::~activation_context()
+{
+ if (handle != INVALID_HANDLE_VALUE)
+ {
+ DeactivateActCtx(0, cookie);
+ ReleaseActCtx(handle);
+ }
+}
+#endif
diff --git a/compat/activation-context.hpp b/compat/activation-context.hpp
new file mode 100644
index 00000000..a3b0429e
--- /dev/null
+++ b/compat/activation-context.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#ifdef _WIN32
+
+#include "export.hpp"
+
+#include <cstdint>
+#include <QString>
+
+class OTR_COMPAT_EXPORT activation_context
+{
+public:
+ explicit activation_context(const QString& module_name, int resid);
+ ~activation_context();
+
+ explicit operator bool() const { return ok; }
+
+private:
+ std::uintptr_t cookie = 0;
+ void* handle = (void*)-1;
+ bool ok = false;
+};
+
+#else
+# error "tried to use win32-only activation context"
+#endif
diff --git a/compat/arch.hpp b/compat/arch.hpp
new file mode 100644
index 00000000..3120116a
--- /dev/null
+++ b/compat/arch.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+// fix MSVC arch check macros
+
+// this file is too simple to fall under copyright, and
+// can be copied, modified, and redistributed freely with
+// no conditions. there's no warranty. -sh 20181226
+
+#if defined _MSC_VER
+# ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wreserved-id-macro"
+# pragma clang diagnostic ignored "-Wunused-macros"
+# endif
+
+# if defined _M_AMD64
+# undef __x86_64__
+# define __x86_64__ 1
+# elif defined _M_IX86
+# undef __i386__
+# define __i386__ 1
+# endif
+
+# if defined __AVX__ || defined __x86_64__ || \
+ defined _M_IX86 && _M_IX86_FP >= 2
+# undef __SSE__
+# undef __SSE2__
+# undef __SSE3__
+# define __SSE__ 1
+# define __SSE2__ 1
+# define __SSE3__ 1 // assume SSE3 in the _M_IX86_FP >= 2 case
+# endif
+
+# ifdef __clang__
+# pragma clang diagnostic pop
+# endif
+#endif
+
+#if defined __SSE3__
+# define OTR_ARCH_DENORM_DAZ
+# include <pmmintrin.h>
+#elif defined __SSE2__
+# define OTR_ARCH_DENORM_FTZ
+# include <emmintrin.h>
+#endif
+
+#if defined __SSE2__
+# define OTR_ARCH_FPU_MASK
+# include <xmmintrin.h>
+#endif
diff --git a/compat/base-path.cpp b/compat/base-path.cpp
index 3285bac8..2a26dcff 100644
--- a/compat/base-path.cpp
+++ b/compat/base-path.cpp
@@ -1,10 +1,12 @@
+#undef NDEBUG
+#include <cassert>
+
#include "base-path.hpp"
#include <QCoreApplication>
-OTR_COMPAT_EXPORT
-never_inline
const QString& application_base_path()
{
- static QString const& const_path = QCoreApplication::applicationDirPath();
- return const_path;
+ assert(qApp && "logic error");
+ static QString path = QCoreApplication::applicationDirPath();
+ return path;
}
diff --git a/compat/base-path.hpp b/compat/base-path.hpp
index 8e2884fd..7a9d4115 100644
--- a/compat/base-path.hpp
+++ b/compat/base-path.hpp
@@ -1,12 +1,11 @@
#pragma once
-#include "macros.hpp"
#include "export.hpp"
#include <QString>
OTR_COMPAT_EXPORT
-never_inline
const QString& application_base_path();
#define OPENTRACK_BASE_PATH (application_base_path())
+
diff --git a/compat/camera-names.cpp b/compat/camera-names.cpp
index 22dcdd8f..b9511037 100644
--- a/compat/camera-names.cpp
+++ b/compat/camera-names.cpp
@@ -1,95 +1,130 @@
#include "camera-names.hpp"
+#include <algorithm>
+#include <iterator>
+
#ifdef _WIN32
+# include <cwchar>
# define NO_DSHOW_STRSAFE
# include <dshow.h>
-# include <cwchar>
-#elif defined(__unix) || defined(__linux) || defined(__APPLE__)
+#elif defined(__unix) || defined(__linux__) || defined(__APPLE__)
# include <unistd.h>
#endif
-#ifdef __linux
+#ifdef __APPLE__
+# include <QCameraInfo>
+#endif
+
+#ifdef __linux__
# include <fcntl.h>
# include <sys/ioctl.h>
# include <linux/videodev2.h>
# include <cerrno>
+# include <cstring>
#endif
#include <QDebug>
-OTR_COMPAT_EXPORT int camera_name_to_index(const QString &name)
+int camera_name_to_index(const QString &name)
{
auto list = get_camera_names();
- int ret = list.indexOf(name);
- if (ret < 0)
- ret = 0;
+ auto it = std::find_if(list.cbegin(), list.cend(), [&name](const auto& tuple) {
+ const auto& [str, idx] = tuple;
+ return str == name;
+ });
+ if (it != list.cend())
+ {
+ const auto& [ str, idx ] = *it;
+ return idx;
+ }
+
+ return -1;
+}
+
+#ifdef _WIN32
+# include <QRegularExpression>
+
+static QString prop_to_qstring(IPropertyBag* pPropBag, const wchar_t* name)
+{
+ QString ret{};
+ VARIANT var;
+ VariantInit(&var);
+ HRESULT hr = pPropBag->Read(name, &var, nullptr);
+ if (SUCCEEDED(hr))
+ ret = QString{(const QChar*)var.bstrVal, int(std::wcslen(var.bstrVal))};
+ VariantClear(&var);
return ret;
}
-OTR_COMPAT_EXPORT QList<QString> get_camera_names()
+static QString device_path_from_qstring(const QString& str)
+{
+ // language=RegExp prefix=R"/( suffix=)/"
+ static const QRegularExpression regexp{R"/(#vid_([0-9a-f]{4})&pid_([0-9a-f]{4})&mi_([0-9a-f]{2})#([^#]+))/",
+ QRegularExpression::CaseInsensitiveOption};
+ auto match = regexp.match(str);
+ if (!match.hasMatch())
+ return {};
+ QString id = match.captured(4);
+ id.replace('&', '_');
+ return id;
+}
+
+#endif
+
+std::vector<std::tuple<QString, int>> get_camera_names()
{
- QList<QString> ret;
-#if defined(_WIN32)
+ std::vector<std::tuple<QString, int>> ret;
+#ifdef _WIN32
// Create the System Device Enumerator.
HRESULT hr;
CoInitialize(nullptr);
- ICreateDevEnum *pSysDevEnum = NULL;
- hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
+ ICreateDevEnum *pSysDevEnum = nullptr;
+ hr = CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
if (FAILED(hr))
{
qDebug() << "failed CLSID_SystemDeviceEnum" << hr;
return ret;
}
// Obtain a class enumerator for the video compressor category.
- IEnumMoniker *pEnumCat = NULL;
+ IEnumMoniker *pEnumCat = nullptr;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
if (hr == S_OK) {
// Enumerate the monikers.
- IMoniker *pMoniker = NULL;
+ IMoniker *pMoniker = nullptr;
ULONG cFetched;
while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag *pPropBag;
- hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
- if (SUCCEEDED(hr)) {
+ hr = pMoniker->BindToStorage(nullptr, nullptr, IID_IPropertyBag, (void **)&pPropBag);
+ if (SUCCEEDED(hr)) {
// To retrieve the filter's friendly name, do the following:
- VARIANT varName;
- VariantInit(&varName);
- hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
- // Display the name in your UI somehow.
- QString str((QChar*)varName.bstrVal, int(std::wcslen(varName.bstrVal)));
- ret.append(str);
+ QString str = prop_to_qstring(pPropBag, L"FriendlyName");
+ QString path = device_path_from_qstring(prop_to_qstring(pPropBag, L"DevicePath"));
+ if (!path.isNull())
+ str += QStringLiteral(" [%1]").arg(path);
+ ret.push_back({ str, (int)ret.size() });
}
- VariantClear(&varName);
-
- ////// To create an instance of the filter, do the following:
- ////IBaseFilter *pFilter;
- ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
- //// (void**)&pFilter);
- // Now add the filter to the graph.
- //Remember to release pFilter later.
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
+#if 0
else
qDebug() << "failed CLSID_VideoInputDeviceCategory" << hr;
+#endif
pSysDevEnum->Release();
#endif
-#ifdef __linux
+
+#ifdef __linux__
for (int i = 0; i < 16; i++) {
- char buf[128];
- sprintf(buf, "/dev/video%d", i);
- if (access(buf, F_OK) == 0)
- ret.append(buf);
- else
- continue;
+ char buf[32];
+ snprintf(buf, sizeof(buf), "/dev/video%d", i);
if (access(buf, R_OK | W_OK) == 0) {
int fd = open(buf, O_RDONLY);
@@ -102,10 +137,16 @@ OTR_COMPAT_EXPORT QList<QString> get_camera_names()
close(fd);
continue;
}
- ret[ret.size()-1] = reinterpret_cast<const char*>(video_cap.card);
+ ret.push_back({ QString((const char*)video_cap.card), i});
close(fd);
}
}
#endif
+#ifdef __APPLE__
+ QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
+ for (const QCameraInfo &cameraInfo : cameras)
+ ret.push_back({ cameraInfo.description(), ret.size() });
+#endif
+
return ret;
}
diff --git a/compat/camera-names.hpp b/compat/camera-names.hpp
index 97184c8c..3585edfe 100644
--- a/compat/camera-names.hpp
+++ b/compat/camera-names.hpp
@@ -8,11 +8,12 @@
#pragma once
-#include <QList>
+#include <vector>
#include <QString>
+# include <tuple>
#include "export.hpp"
-OTR_COMPAT_EXPORT QList<QString> get_camera_names();
+OTR_COMPAT_EXPORT std::vector<std::tuple<QString, int>> get_camera_names();
OTR_COMPAT_EXPORT int camera_name_to_index(const QString &name);
diff --git a/compat/check-visible.cpp b/compat/check-visible.cpp
index 84ddd6d9..621d941a 100644
--- a/compat/check-visible.cpp
+++ b/compat/check-visible.cpp
@@ -1,71 +1,98 @@
#include "check-visible.hpp"
+#include <QMutex>
+#include <QWidget>
+#include <QDebug>
+
+static QMutex lock;
+static bool visible = true;
+
#if defined _WIN32
#include "timer.hpp"
+#include "macros.h"
-#include <QMutexLocker>
-
-#include <windows.h>
+static Timer timer;
-constexpr int visible_timeout = 5000;
+constexpr int visible_timeout = 1000;
constexpr int invisible_timeout = 250;
-static Timer timer;
-static QMutex mtx;
-static bool visible = true;
+#include <windows.h>
-never_inline OTR_COMPAT_EXPORT
void set_is_visible(const QWidget& w, bool force)
{
- QMutexLocker l(&mtx);
+ QMutexLocker l(&lock);
- if (!force && timer.elapsed_ms() < (visible ? visible_timeout : invisible_timeout))
+ if (w.isHidden() || w.windowState() & Qt::WindowMinimized)
+ {
+ visible = false;
return;
+ }
- timer.start();
+ {
+ int ndisplays = GetSystemMetrics(SM_CMONITORS);
+ if (ndisplays > 1)
+ {
+ visible = true;
+ return;
+ }
+ }
+
+ HWND hwnd = (HWND)w.winId();
- const HWND id = (HWND) w.winId();
- const QPoint pt = w.mapToGlobal({ 0, 0 });
+ if (!force && timer.elapsed_ms() < (visible ? visible_timeout : invisible_timeout))
+ return;
- const int W = w.width(), H = w.height();
+ timer.start();
- const QPoint points[] =
+ if (RECT r; GetWindowRect(hwnd, &r))
{
- pt,
- pt + QPoint(W - 1, 0),
- pt + QPoint(0, H - 1),
- pt + QPoint(W - 1, H - 1),
- pt + QPoint(W / 2, H / 2),
- };
-
- for (const QPoint& pt : points)
+ const int x = r.left, y = r.top;
+ const int w = r.right - x, h = r.bottom - y;
+
+ const POINT xs[] {
+ { x + w - 1, y + 1 },
+ { x + 1, y + h - 1 },
+ { x + w - 1, y + h - 1 },
+ { x + 1, y + 1 },
+ { x + w/2, y + h/2 },
+ };
+
+ visible = false;
+
+ for (const POINT& pt : xs)
+ if (WindowFromPoint(pt) == hwnd)
+ {
+
+ visible = true;
+ break;
+ }
+ }
+ else
{
- visible = WindowFromPoint({ pt.x(), pt.y() }) == id;
- if (visible)
- break;
+ eval_once(qDebug() << "check-visible: GetWindowRect failed");
+ visible = true;
}
}
-never_inline OTR_COMPAT_EXPORT
-bool check_is_visible()
-{
- QMutexLocker l(&mtx);
-
- return visible;
-}
-
#else
-never_inline OTR_COMPAT_EXPORT
-void set_is_visible(const QWidget&, bool)
+void set_is_visible(const QWidget& w, bool)
{
+ QMutexLocker l(&lock);
+ visible = !(w.isHidden() || w.windowState() & Qt::WindowMinimized);
}
-never_inline OTR_COMPAT_EXPORT
+#endif
+
bool check_is_visible()
{
- return true;
+ QMutexLocker l(&lock);
+ return visible;
}
-#endif
+void force_is_visible(bool value)
+{
+ QMutexLocker l(&lock);
+ visible = value;
+}
diff --git a/compat/check-visible.hpp b/compat/check-visible.hpp
index a0211982..6669b84d 100644
--- a/compat/check-visible.hpp
+++ b/compat/check-visible.hpp
@@ -1,9 +1,15 @@
#pragma once
#include "export.hpp"
-#include "macros.hpp"
+#include "macros.h"
-#include <QWidget>
+class QWidget;
-never_inline OTR_COMPAT_EXPORT void set_is_visible(QWidget const& w, bool force = false);
-never_inline OTR_COMPAT_EXPORT bool check_is_visible();
+never_inline OTR_COMPAT_EXPORT
+void set_is_visible(QWidget const& w, bool force = false);
+
+OTR_COMPAT_EXPORT
+bool check_is_visible();
+
+OTR_COMPAT_EXPORT
+void force_is_visible(bool value);
diff --git a/compat/copyable-mutex.cpp b/compat/copyable-mutex.cpp
deleted file mode 100644
index 7c112c5e..00000000
--- a/compat/copyable-mutex.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "copyable-mutex.hpp"
-
-mutex& mutex::operator=(const mutex& datum)
-{
- inner = nullptr;
- inner = std::make_unique<QMutex>(datum->isRecursive()
- ? QMutex::Recursive
- : QMutex::NonRecursive);
- return *this;
-}
-
-mutex::mutex(const mutex& datum)
-{
- *this = datum;
-}
-
-mutex::mutex(mutex::mode m) :
- inner(std::make_unique<QMutex>(static_cast<QMutex::RecursionMode>(int(m))))
-{
-}
-
-QMutex* mutex::operator&() const
-{
- return *this;
-}
-
-QMutex* mutex::operator->() const
-{
- return *this;
-}
-
-mutex::operator QMutex*() const
-{
- return const_cast<QMutex*>(inner.get());
-}
-
diff --git a/compat/copyable-mutex.hpp b/compat/copyable-mutex.hpp
deleted file mode 100644
index af82876d..00000000
--- a/compat/copyable-mutex.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-#include <memory>
-
-#include <QMutex>
-
-#include "export.hpp"
-
-class OTR_COMPAT_EXPORT mutex
-{
- std::unique_ptr<QMutex> inner;
-
-public:
- enum mode
- {
- recursive = QMutex::Recursive,
- normal = QMutex::NonRecursive,
- };
-
- mutex& operator=(const mutex& datum);
- mutex(const mutex& datum);
- mutex(mode m = normal);
-
- QMutex* operator&() const;
- operator QMutex*() const;
- QMutex* operator->() const;
-};
diff --git a/compat/correlation-calibrator.cpp b/compat/correlation-calibrator.cpp
index 949f10ae..07ef7d3d 100644
--- a/compat/correlation-calibrator.cpp
+++ b/compat/correlation-calibrator.cpp
@@ -2,6 +2,7 @@
#include "variance.hpp"
#include "compat/math.hpp"
#include "compat/meta.hpp"
+#include "compat/macros.h"
#include <cmath>
#include <iterator>
@@ -11,16 +12,9 @@
#define DEBUG_PRINT
#ifdef DEBUG_PRINT
# include <cstdio>
-# include <cwchar>
- using std::fwprintf;
- using std::fflush;
#endif
-using namespace correlation_calibrator_impl;
-
-correlation_calibrator::correlation_calibrator()
-{
-}
+namespace correlation_calibrator_impl {
static constexpr unsigned nbuckets[6] =
{
@@ -44,26 +38,26 @@ static constexpr double spacing[6] =
roll_spacing_in_degrees,
};
-static constexpr wchar_t const* const names[6] {
- L"x", L"y", L"z",
- L"yaw", L"pitch", L"roll",
+static constexpr char const* const names[6] {
+ "x", "y", "z",
+ "yaw", "pitch", "roll",
};
-bool correlation_calibrator::check_buckets(const vec6 &data)
+bool correlation_calibrator::check_buckets(const vec6& data)
{
bool ret = false;
unsigned pos[6];
for (unsigned k = 0; k < 6; k++)
{
- const double val = clamp(data[k], min[k], max[k]);
- pos[k] = (val-min[k])/spacing[k];
+ const double val = std::clamp(data[k], min[k], max[k]);
+ pos[k] = unsigned((val-min[k])/spacing[k]);
if (pos[k] >= nbuckets[k])
{
- once_only(qDebug() << "idx" << k
+ eval_once(qDebug() << "idx" << k
<< "bucket" << (int)pos[k]
- << "outside bounds" << nbuckets[k]);;
+ << "outside bounds" << nbuckets[k]);
return false;
}
@@ -133,18 +127,18 @@ mat66 correlation_calibrator::get_coefficients() const
cs = cs * (1./(data.size() - 1));
#if defined DEBUG_PRINT
- fwprintf(stderr, L"v:change-of h:due-to\n");
- fwprintf(stderr, L"%10s ", L"");
- for (unsigned k = 0; k < 6; k++)
- fwprintf(stderr, L"%10s", names[k]);
- fwprintf(stderr, L"\n");
+ fprintf(stderr, "v:change-of h:due-to\n");
+ fprintf(stderr, "%10s ", "");
+ for (char const* k : names)
+ fprintf(stderr, "%10s", k);
+ fprintf(stderr, "\n");
for (unsigned i = 0; i < 6; i++)
{
- fwprintf(stderr, L"%10s ", names[i]);
+ fprintf(stderr, "%10s ", names[i]);
for (unsigned k = 0; k < 6; k++)
- fwprintf(stderr, L"%10.3f", cs(i, k));
- fwprintf(stderr, L"\n");
+ fprintf(stderr, "%10.3f", cs(i, k));
+ fprintf(stderr, "\n");
}
fflush(stderr);
#endif
@@ -162,3 +156,5 @@ unsigned correlation_calibrator::sample_count() const
{
return data.size();
}
+
+} // ns correlation_calibrator_impl
diff --git a/compat/correlation-calibrator.hpp b/compat/correlation-calibrator.hpp
index b44a2312..44aee537 100644
--- a/compat/correlation-calibrator.hpp
+++ b/compat/correlation-calibrator.hpp
@@ -9,7 +9,7 @@
namespace correlation_calibrator_impl {
-static constexpr inline double min[6] = {
+static constexpr double min[6] = {
-50,
-50,
250,
@@ -19,7 +19,7 @@ static constexpr inline double min[6] = {
-180,
};
-static constexpr inline double max[6] = {
+static constexpr double max[6] = {
50,
50,
250,
@@ -29,18 +29,18 @@ static constexpr inline double max[6] = {
180,
};
-static constexpr inline double yaw_spacing_in_degrees = 1.5;
-static constexpr inline double pitch_spacing_in_degrees = 1;
-static constexpr inline double roll_spacing_in_degrees = 1;
+static constexpr double yaw_spacing_in_degrees = 1.5;
+static constexpr double pitch_spacing_in_degrees = 1;
+static constexpr double roll_spacing_in_degrees = 1;
-static constexpr inline unsigned yaw_nbuckets = 1+ 360./yaw_spacing_in_degrees;
-static constexpr inline unsigned pitch_nbuckets = 1+ 360./pitch_spacing_in_degrees;
-static constexpr inline unsigned roll_nbuckets = 1+ 360./roll_spacing_in_degrees;
+static constexpr unsigned yaw_nbuckets = unsigned(1+ 360./yaw_spacing_in_degrees);
+static constexpr unsigned pitch_nbuckets = unsigned(1+ 360./pitch_spacing_in_degrees);
+static constexpr unsigned roll_nbuckets = unsigned(1+ 360./roll_spacing_in_degrees);
-static constexpr inline double translation_spacing = .25;
-static constexpr inline unsigned x_nbuckets = 1+ (max[0]-min[0])/translation_spacing;
-static constexpr inline unsigned y_nbuckets = 1+ (max[1]-min[1])/translation_spacing;
-static constexpr inline unsigned z_nbuckets = 1+ (max[2]-min[2])/translation_spacing;
+static constexpr double translation_spacing = .25;
+static constexpr unsigned x_nbuckets = unsigned(1+ (max[0]-min[0])/translation_spacing);
+static constexpr unsigned y_nbuckets = unsigned(1+ (max[1]-min[1])/translation_spacing);
+static constexpr unsigned z_nbuckets = unsigned(1+ (max[2]-min[2])/translation_spacing);
using vec6 = Mat<double, 6, 1>;
using mat66 = Mat<double, 6, 6>;
@@ -63,14 +63,14 @@ class OTR_COMPAT_EXPORT correlation_calibrator final
bool check_buckets(const vec6& data);
public:
- correlation_calibrator();
+ correlation_calibrator() = default;
void input(const vec6& data);
mat66 get_coefficients() const;
unsigned sample_count() const;
- static constexpr inline unsigned min_samples = 25;
+ static constexpr unsigned min_samples = 25;
};
} // ns correlation_calibrator_impl
-using correlation_calibrator_impl::correlation_calibrator;
+using correlation_calibrator = correlation_calibrator_impl::correlation_calibrator;
diff --git a/compat/enum-operators.hpp b/compat/enum-operators.hpp
new file mode 100644
index 00000000..e4f81a39
--- /dev/null
+++ b/compat/enum-operators.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <type_traits>
+
+#define OTR_FLAGS_OP2(type, op) \
+ constexpr inline type operator op (type a, type b) \
+ { \
+ using t_ = std::underlying_type_t<type>; \
+ return type(t_((a)) op t_((b))); \
+ } // end
+
+#define OTR_FLAGS_DELETE_SHIFT(type, op) \
+ template<typename u> \
+ type operator op (type, u) = delete // end
+
+#define OTR_FLAGS_OP1(type, op) \
+ constexpr inline type operator op (type x) \
+ { \
+ using t_ = std::underlying_type_t<type>; \
+ return type(op t_((x))); \
+ } // end
+
+#define OTR_FLAGS_ASSIGN_OP(type, op) \
+ constexpr inline type& operator op ## = (type& lhs, type rhs) \
+ { \
+ using t_ = std::underlying_type_t<decltype(rhs)>; \
+ lhs = type(t_((lhs)) op t_((rhs))); \
+ return lhs; \
+ } //end
+
+#define OTR_FLAGS_DELETE_SHIFT_ASSIGN(type, op) \
+ type operator op ## = (type& lhs, type rhs) = delete //end
+
+#define DEFINE_ENUM_OPERATORS(type) \
+ OTR_FLAGS_OP2(type, |) \
+ OTR_FLAGS_OP2(type, &) \
+ OTR_FLAGS_OP2(type, ^) \
+ OTR_FLAGS_OP1(type, ~) \
+ OTR_FLAGS_DELETE_SHIFT(type, <<); \
+ OTR_FLAGS_DELETE_SHIFT(type, >>); \
+ OTR_FLAGS_ASSIGN_OP(type, |) \
+ OTR_FLAGS_ASSIGN_OP(type, &) \
+ OTR_FLAGS_ASSIGN_OP(type, ^) \
+ OTR_FLAGS_DELETE_SHIFT_ASSIGN(type, <<); \
+ OTR_FLAGS_DELETE_SHIFT_ASSIGN(type, >>) // end
diff --git a/compat/euler.cpp b/compat/euler.cpp
index 39d2b116..5d6fb25b 100644
--- a/compat/euler.cpp
+++ b/compat/euler.cpp
@@ -2,38 +2,53 @@
#include "math-imports.hpp"
#include <cmath>
-// rotation order is XYZ
-
namespace euler {
-euler_t OTR_COMPAT_EXPORT rmat_to_euler(const rmat& R)
+Pose_ rmat_to_euler(const rmat& R)
{
- double alpha, beta, gamma;
-
- beta = atan2( -R(2,0), sqrt(R(2,1)*R(2,1) + R(2,2)*R(2,2)) );
- alpha = atan2( R(1,0), R(0,0));
- gamma = atan2( R(2,1), R(2,2));
-
- return { alpha, -beta, gamma };
+ const double cy = sqrt(R(2,2)*R(2, 2) + R(2, 1)*R(2, 1));
+ const bool large_enough = cy > 1e-10;
+ if (large_enough)
+ return {
+ atan2(-R(1, 0), R(0, 0)),
+ atan2(R(2, 0), cy),
+ atan2(-R(2, 1), R(2, 2))
+ };
+ else
+ return {
+ atan2(R(0, 1), R(1, 1)),
+ atan2(R(2, 0), cy),
+ 0
+ };
}
-rmat OTR_COMPAT_EXPORT euler_to_rmat(const euler_t& e)
+// tait-bryan angles, not euler
+rmat euler_to_rmat(const Pose_& input)
{
- const double X = e(2);
- const double Y = -e(1);
- const double Z = e(0);
+ const double H = -input(0);
+ const double P = -input(1);
+ const double B = -input(2);
- const double cx = cos(X);
- const double sx = sin(X);
- const double cy = cos(Y);
- const double sy = sin(Y);
- const double cz = cos(Z);
- const double sz = sin(Z);
+ const auto c1 = cos(H);
+ const auto s1 = sin(H);
+ const auto c2 = cos(P);
+ const auto s2 = sin(P);
+ const auto c3 = cos(B);
+ const auto s3 = sin(B);
return {
- cy*cz, -cy*sz, sy,
- cz*sx*sy + cx*sz, cx*cz - sx*sy*sz, -cy*sx,
- -cx*cz*sy + sx*sz, cz*sx + cx*sy*sz, cx*cy,
+ // z
+ c1*c2,
+ c1*s2*s3 - c3*s1,
+ s1*s3 + c1*c3*s2,
+ // y
+ c2*s1,
+ c1*c3 + s1*s2*s3,
+ c3*s1*s2 - c1*s3,
+ // x
+ -s2,
+ c2*s3,
+ c2*c3
};
}
diff --git a/compat/euler.hpp b/compat/euler.hpp
index d4217a70..b2f10ac0 100644
--- a/compat/euler.hpp
+++ b/compat/euler.hpp
@@ -17,9 +17,9 @@ template<int h_, int w_> using dmat = Mat<double, h_, w_>;
using dvec3 = Mat<double, 3, 1>;
using rmat = dmat<3, 3>;
-using euler_t = dmat<3, 1>;
+using Pose_ = dmat<3, 1>;
-rmat OTR_COMPAT_EXPORT euler_to_rmat(const euler_t& input);
-euler_t OTR_COMPAT_EXPORT rmat_to_euler(const rmat& R);
+rmat OTR_COMPAT_EXPORT euler_to_rmat(const Pose_& input);
+Pose_ OTR_COMPAT_EXPORT rmat_to_euler(const rmat& R);
} // end ns euler
diff --git a/compat/hamilton-tools.cpp b/compat/hamilton-tools.cpp
new file mode 100644
index 00000000..eb0ef984
--- /dev/null
+++ b/compat/hamilton-tools.cpp
@@ -0,0 +1,109 @@
+#include "hamilton-tools.h"
+#include <cmath>
+
+tQuat QuatFromAngleAxe(const double angle, const tVector& axe)
+{
+ double a = TO_RAD * 0.5 * angle;
+ double d = sin(a) / VectorLength(axe);
+ return ( tQuat (
+ axe.v[0] * d,
+ axe.v[1] * d,
+ axe.v[2] * d,
+ cos(a)
+ )
+ );
+}
+
+tQuat QuatMultiply(const tQuat& qL, const tQuat& qR)
+{
+ tQuat Q;
+ Q.x = qL.w*qR.x + qL.x*qR.w + qL.y*qR.z - qL.z*qR.y;
+ Q.y = qL.w*qR.y + qL.y*qR.w + qL.z*qR.x - qL.x*qR.z;
+ Q.z = qL.w*qR.z + qL.z*qR.w + qL.x*qR.y - qL.y*qR.x;
+ Q.w = qL.w*qR.w - qL.x*qR.x - qL.y*qR.y - qL.z*qR.z;
+ return(Q);
+}
+
+tQuat QuatFromYPR(const double YPR[])
+{
+ tQuat Q, Qp, Qy;
+ Q = QuatFromAngleAxe( -YPR[2], {0, 0, 1} ); //Roll, Z axe
+ Qp = QuatFromAngleAxe( -YPR[1], {1, 0, 0} ); //Pitch, X axe
+ Qy = QuatFromAngleAxe( -YPR[0], {0, 1, 0} ); //Yaw, Y axe
+
+ Q = QuatMultiply(Qp, Q);
+ return(QuatMultiply(Qy, Q));
+}
+
+void Normalize(tQuat& Q)
+{
+ double m = sqrt(Q.x*Q.x + Q.y*Q.y + Q.z*Q.z + Q.w*Q.w);
+ if (m > EPSILON)
+ {
+ m = 1 / m;
+ Q.x = Q.x * m;
+ Q.y = Q.y * m;
+ Q.z = Q.z * m;
+ Q.w = Q.w * m;
+ }
+ else Q = tQuat(0, 0, 0, 1);
+}
+
+tQuat Slerp(const tQuat& S, const tQuat& D, const double alpha)
+{
+ // calc cosine of half angle
+ double cosin = S.x*D.x + S.y*D.y + S.z*D.z + S.w*D.w;
+
+ // select nearest rotation direction
+ tQuat Q;
+ if (cosin < 0)
+ {
+ cosin = - cosin;
+ Q.x = - D.x;
+ Q.y = - D.y;
+ Q.z = - D.z;
+ Q.w = - D.w;
+ }
+ else Q = D;
+
+ // calculate coefficients
+ double scale0, scale1;
+ if ((1.0 - cosin) > EPSILON)
+ {
+ double omega = acos(cosin);
+ double sinus = 1 / sin(omega);
+ scale0 = sin((1.0 - alpha) * omega) * sinus;
+ scale1 = sin(alpha * omega)* sinus;
+ }
+ else
+ {
+ scale0 = 1.0 - alpha;
+ scale1 = alpha;
+ }
+
+ Q.x = scale0 * S.x + scale1 * Q.x;
+ Q.y = scale0 * S.y + scale1 * Q.y;
+ Q.z = scale0 * S.z + scale1 * Q.z;
+ Q.w = scale0 * S.w + scale1 * Q.w;
+
+ Normalize(Q);
+
+ return( Q );
+}
+
+void QuatToYPR(const tQuat& Q, double YPR[])
+{
+ const double xx = Q.x * Q.x;
+ const double xy = Q.x * Q.y;
+ const double xz = Q.x * Q.z;
+ const double xw = Q.x * Q.w;
+ const double yy = Q.y * Q.y;
+ const double yz = Q.y * Q.z;
+ const double yw = Q.y * Q.w;
+ const double zz = Q.z * Q.z;
+ const double zw = Q.z * Q.w;
+
+ YPR[0] = TO_DEG * ( -atan2( 2 * ( xz + yw ), 1 - 2 * ( xx + yy ) ));
+ YPR[1] = TO_DEG * ( asin ( 2 * ( yz - xw ) ));
+ YPR[2] = TO_DEG * ( -atan2( 2 * ( xy + zw ), 1 - 2 * ( xx + zz ) ));
+}
diff --git a/compat/hamilton-tools.h b/compat/hamilton-tools.h
new file mode 100644
index 00000000..885e9f79
--- /dev/null
+++ b/compat/hamilton-tools.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <algorithm>
+#include "export.hpp"
+#include "compat/math.hpp"
+
+constexpr double TO_RAD = (M_PI / 180);
+constexpr double TO_DEG = (180 / M_PI);
+constexpr double EPSILON = 1e-30;
+
+struct tVector
+{
+ double v[3];
+ tVector(double X = 0, double Y = 0, double Z = 0) {v[0]=X; v[1]=Y; v[2]=Z;}
+ tVector(const double V[]) {v[0]=V[0]; v[1]=V[1]; v[2]=V[2];}
+
+ void operator=(const tVector& other)
+ {
+ std::copy(other.v, other.v + 3, v);
+ }
+ inline const tVector operator+(const tVector& other) const
+ {
+ return tVector(v[0] + other.v[0], v[1] + other.v[1], v[2] + other.v[2]);
+ }
+ void operator+=(const tVector& other)
+ {
+ v[0] += other.v[0];
+ v[1] += other.v[1];
+ v[2] += other.v[2];
+ }
+ const tVector operator-(const tVector& other) const
+ {
+ return tVector(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
+ }
+ void operator-=(const tVector& other)
+ {
+ v[0] -= other.v[0];
+ v[1] -= other.v[1];
+ v[2] -= other.v[2];
+ }
+ const tVector operator*(double scalar) const
+ {
+ return tVector(v[0] * scalar, v[1] * scalar, v[2] * scalar);
+ }
+ void operator*=(double scalar)
+ {
+ v[0] *= scalar;
+ v[1] *= scalar;
+ v[2] *= scalar;
+ }
+ const tVector operator/(double scalar) const
+ {
+ return *this * (1.0 / scalar);
+ }
+ void operator/= (double scalar)
+ {
+ *this *= 1.0 / scalar;
+ }
+};
+
+struct tQuat
+{
+ double x, y, z, w;
+ tQuat(double X = 0, double Y = 0, double Z = 0, double W = 1)
+ {x = X; y = Y; z = Z; w = W;}
+};
+
+inline double VectorLength(const tVector& v) { return sqrt(v.v[0] * v.v[0] + v.v[1] * v.v[1] + v.v[2] * v.v[2]); }
+inline double VectorDistance(const tVector& v1, const tVector& v2) { return VectorLength(v2 - v1); }
+inline tVector Lerp(const tVector& s, const tVector& d, const double alpha) { return s + (d - s) * alpha; }
+tQuat OTR_COMPAT_EXPORT QuatFromYPR(const double YPR[]);
+tQuat OTR_COMPAT_EXPORT QuatMultiply(const tQuat& qL, const tQuat& qR);
+inline tQuat QuatDivide(const tQuat& qL, const tQuat& qR) { return QuatMultiply(qL, tQuat(-qR.x, -qR.y, -qR.z, qR.w)); }
+inline double AngleBetween(const tQuat& S, const tQuat& D) { return TO_DEG * 2 * acos(fabs(S.x * D.x + S.y * D.y + S.z * D.z + S.w * D.w)); }
+tQuat OTR_COMPAT_EXPORT Slerp(const tQuat& S, const tQuat& D, const double alpha);
+void OTR_COMPAT_EXPORT QuatToYPR(const tQuat& Q, double YPR[]);
diff --git a/compat/lang/de_DE.ts b/compat/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/compat/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/compat/lang/zh_CN.ts b/compat/lang/zh_CN.ts
index 6401616d..e5ca8aa9 100644
--- a/compat/lang/zh_CN.ts
+++ b/compat/lang/zh_CN.ts
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
-<TS version="2.1">
+<TS version="2.1" language="zh_CN">
</TS>
diff --git a/compat/library-path.hpp b/compat/library-path.hpp
index e14cf5e0..49e2c414 100644
--- a/compat/library-path.hpp
+++ b/compat/library-path.hpp
@@ -1,4 +1,4 @@
#pragma once
// from build directory
-#include "__opentrack-library-path.h"
+#include "opentrack-library-path.hxx"
diff --git a/compat/linkage-macros.hpp b/compat/linkage-macros.hpp
index 9e71ac8c..f4d0104b 100644
--- a/compat/linkage-macros.hpp
+++ b/compat/linkage-macros.hpp
@@ -1,15 +1,26 @@
#pragma once
-#if defined _MSC_VER
-# define OTR_GENERIC_EXPORT __declspec(dllexport)
-# define OTR_GENERIC_IMPORT __declspec(dllimport)
-#elif defined _WIN32 && !defined(__WINE__)
-# define OTR_GENERIC_EXPORT __attribute__((dllexport, visibility ("default")))
-# define OTR_GENERIC_IMPORT __attribute__((dllimport))
-#else
-# define OTR_GENERIC_EXPORT __attribute__ ((visibility ("default")))
-# define OTR_GENERIC_IMPORT
+#ifndef OTR_GENERIC_EXPORT
+# if defined _MSC_VER
+# define OTR_GENERIC_EXPORT __declspec(dllexport)
+# define OTR_GENERIC_IMPORT __declspec(dllimport)
+# elif defined _WIN32 && !defined __WINE__
+# define OTR_GENERIC_EXPORT __attribute__((dllexport, visibility ("default")))
+# define OTR_GENERIC_IMPORT __attribute__((dllimport))
+# else
+# define OTR_GENERIC_EXPORT __attribute__((visibility ("default")))
+# define OTR_GENERIC_IMPORT
+# endif
+#endif
+
+#if defined __APPLE__ || defined __MINGW32__
+# define OTR_NO_TMPL_INST // link failure on both targets
#endif
-#define OTR_TEMPLATE_EXPORT template class OTR_GENERIC_EXPORT
-#define OTR_TEMPLATE_IMPORT extern template class OTR_GENERIC_IMPORT
+#if defined OTR_NO_TMPL_INST
+# define OTR_TEMPLATE_IMPORT(x)
+# define OTR_TEMPLATE_EXPORT(x)
+#else
+# define OTR_TEMPLATE_IMPORT(x) extern template class OTR_GENERIC_IMPORT x;
+# define OTR_TEMPLATE_EXPORT(x) template class OTR_GENERIC_EXPORT x;
+#endif
diff --git a/compat/macros.h b/compat/macros.h
new file mode 100644
index 00000000..7de7fb86
--- /dev/null
+++ b/compat/macros.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#if defined _MSC_VER
+# define never_inline __declspec(noinline)
+#else
+# define never_inline __attribute__((noinline))
+#endif
+
+#if defined _MSC_VER
+# define force_inline __forceinline
+#else
+# define force_inline __attribute__((always_inline)) inline
+#endif
+
+#if !defined likely
+# if defined __GNUC__
+# define likely(x) __builtin_expect(!!(x),1)
+# define unlikely(x) __builtin_expect(!!(x),0)
+# else
+# define likely(x) (x)
+# define unlikely(x) (x)
+# endif
+#endif
+
+#if defined _MSC_VER
+# define function_name __FUNCSIG__
+#else
+# define function_name __PRETTY_FUNCTION__
+#endif
+
+#ifdef _MSC_VER
+# define unreachable() do { __assume(0); *(volatile int*)nullptr = 0; } while (0) /* NOLINT(clang-analyzer-core.NullDereference) */
+#else
+# define unreachable() do { __builtin_unreachable(); *(volatile int*)nullptr = 0; } while (0) /* NOLINT(clang-analyzer-core.NullDereference) */
+#endif
+
+#ifdef __cplusplus
+# define progn(...) ([&]() -> decltype(auto) { __VA_ARGS__ }())
+# define eval_once2(expr, ctr) eval_once3(expr, ctr)
+# define eval_once3(expr, ctr) ([&] { [[maybe_unused]] static const char init_ ## ctr = ((void)(expr), 0); }())
+# ifdef QT_NO_DEBUG_OUTPUT
+# define eval_once(expr) void()
+# else
+# define eval_once(expr) eval_once2(expr, __COUNTER__)
+# endif
+
+#define OTR_DISABLE_MOVE_COPY(type) \
+ type(const type&) = delete; \
+ type(type&&) = delete; \
+ type& operator=(const type&) = delete; \
+ type& operator=(type&&) = delete
+#endif
+
+#ifdef _MSC_VER
+# define strncasecmp _strnicmp
+# define strcasecmp _stricmp
+#endif
diff --git a/compat/macros.hpp b/compat/macros.hpp
deleted file mode 100644
index c8fbca20..00000000
--- a/compat/macros.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-
-#if !defined __WINE__
-# include <QCoreApplication>
-# define otr_tr(...) (QCoreApplication::translate(OTR_MODULE_NAME, __VA_ARGS__))
-# define _(...) (otr_tr(__VA_ARGS__))
-#endif
-
-#if defined _MSC_VER
-#
-# define MEMORY_BARRIER _ReadWriteBarrier()
-#else
-# define MEMORY_BARRIER asm volatile("" ::: "memory")
-#endif
-
-#if defined _MSC_VER
-# define never_inline __declspec(noinline)
-#elif defined __GNUG__
-# define never_inline __attribute__((noinline))
-#else
-# define never_inline
-#endif
-
-#if defined __cplusplus
-# define restrict_ptr __restrict
-#endif
-
-#if defined _MSC_VER
-# define force_inline __forceinline
-#else
-# define force_inline __attribute__((always_inline, gnu_inline)) inline
-#endif
-
-#ifdef Q_CREATOR_RUN
-# define warn_result_unused
-#elif defined _MSC_VER
-# define warn_result_unused _Check_return_
-#else
-# define warn_result_unused __attribute__((warn_unused_result))
-#endif
-
-#if defined __GNUC__
-# define likely(x) __builtin_expect(!!(x),1)
-# define unlikely(x) __builtin_expect(!!(x),0)
-#else
-# define likely(x) (x)
-# define unlikely(x) (x)
-#endif
-
-#if defined _MSC_VER
-# define OTR_FUNNAME (__FUNCSIG__)
-#else
-# define OTR_FUNNAME (__PRETTY_FUNCTION__)
-#endif
diff --git a/compat/math.hpp b/compat/math.hpp
index 5d80dace..c5981cc2 100644
--- a/compat/math.hpp
+++ b/compat/math.hpp
@@ -1,74 +1,16 @@
#pragma once
-#include "macros.hpp"
-
#include <cmath>
#include <type_traits>
-namespace util_detail {
-
-template<typename n>
-inline auto clamp_float(n val, n min_, n max_)
-{
- return std::fmin(std::fmax(val, min_), max_);
-}
-
-template<typename t, typename n>
-struct clamp final
-{
- static inline auto clamp_(const n& val, const n& min_, const n& max_)
- {
- if (unlikely(val > max_))
- return max_;
- if (unlikely(val < min_))
- return min_;
- return val;
- }
-};
-
-template<typename t>
-struct clamp<float, t>
-{
- static inline auto clamp_(float val, float min_, float max_)
- {
- return clamp_float(val, min_, max_);
- }
-};
-
-template<typename t>
-struct clamp<double, t>
-{
- static inline auto clamp_(double val, double min_, double max_)
- {
- return clamp_float(val, min_, max_);
- }
-};
-
-} // ns util_detail
-
-template<typename t, typename u, typename w>
-inline auto clamp(const t& val, const u& min, const w& max)
-{
- using tp = decltype(val + min + max);
- return ::util_detail::clamp<std::decay_t<tp>, tp>::clamp_(val, min, max);
-}
-
template<typename t>
-inline int iround(const t& val)
+inline auto iround(t val) -> std::enable_if_t<std::is_floating_point_v<std::decay_t<t>>, int>
{
- return int(std::round(val));
+ return (int)std::round(val);
}
-template<typename t>
-inline unsigned uround(const t& val)
-{
- return std::round(std::fmax(t(0), val));
-}
-
-#include "macros.hpp"
-
-template <typename T>
-static force_inline constexpr auto signum(T x)
+template <typename t>
+constexpr int signum(const t& x)
{
- return x < T(0) ? -1 : 1;
+ return x < t{0} ? -1 : 1;
}
diff --git a/compat/meta.hpp b/compat/meta.hpp
index 80eca89a..49686996 100644
--- a/compat/meta.hpp
+++ b/compat/meta.hpp
@@ -7,26 +7,12 @@
* copyright notice and this permission notice appear in all copies.
*/
-#include <type_traits>
+namespace meta::detail {
-template<typename t>
-using cv_qualified = std::conditional_t<std::is_fundamental_v<std::decay_t<t>>, std::decay_t<t>, const t&>;
+ template<typename... xs>
+ struct tuple;
-#define progn(...) (([&]() { __VA_ARGS__ })())
-#define prog1(x, ...) (([&]() { auto _ret1324 = (x); do { __VA_ARGS__; } while (0); return _ret1324; })())
-
-#define once_only(...) do { static bool once__ = false; if (!once__) { once__ = true; __VA_ARGS__; } } while(false)
-
-#if 0
-
-#include <tuple>
-#include <cstddef>
-
-namespace meta {
-
-namespace detail {
-
- template<typename x, typename y>
+ template<typename... xs>
struct reverse_;
template<typename x0, typename... xs, template<typename...> class x, typename... ys>
@@ -41,51 +27,97 @@ namespace detail {
using type = x<ys...>;
};
- template<template<typename...> class inst, typename x>
- struct lift_;
+ template<template<typename...> class, typename, typename...> struct lift_;
- template<template<typename...> class inst, template<typename...> class x, typename... xs>
- struct lift_<inst, x<xs...>>
+ template<template<typename...> class to, template<typename...> class from, typename... xs>
+ struct lift_<to, from<xs...>>
{
- using type = inst<xs...>;
+ using type = to<xs...>;
};
- template<typename N, N max, N pos, typename... xs>
- struct index_sequence_
+ template<typename> struct append_helper;
+
+ template<typename, typename> struct cons_;
+
+ template<typename x, template<typename...> class t, typename... xs>
+ struct cons_<x, t<xs...>>
{
- using part = std::integral_constant<N, pos>;
- using type = typename index_sequence_<N, max, pos+1, xs..., part>::type;
+ using type = t<x, xs...>;
};
- template<typename N, N max, typename... xs>
- struct index_sequence_<N, max, max, xs...>
+ template<typename> struct append2;
+
+ template<template<typename...> class t, typename... xs>
+ struct append2<t<xs...>>
{
- using type = std::tuple<xs...>;
+ template<typename> struct append1;
+
+ template<template<typename...> class u, typename... ys>
+ struct append1<u<ys...>>
+ {
+ using type = t<xs..., ys...>;
+ };
};
-} // ns detail
+ template<typename, typename...> struct list__;
+
+ template<typename rest, typename... first>
+ struct list__
+ {
+ template<typename> struct list1;
+
+ template<template<typename...> class t, typename... xs>
+ struct list1<t<xs...>>
+ {
+ using type = t<first..., xs...>;
+ };
+
+ using type = typename list1<rest>::type;
+ };
+
+ template<typename xs, typename ys>
+ struct append_
+ {
+ using t1 = append2<xs>;
+ using type = typename t1::template append1<ys>::type;
+ };
+
+} // ns meta::detail
+
+namespace meta {
+ template<typename... xs>
+ using tuple_ = detail::tuple<xs...>;
+
+ template<typename... xs>
+ using reverse = typename detail::reverse_<detail::tuple<xs...>, detail::tuple<>>::type;
+
+ // the to/from order is awkward but mimics function composition
+ template<template<typename...> class to, typename from>
+ using lift = typename detail::lift_<to, from>::type;
+
+ template<template<typename...> class to, typename from>
+ constexpr inline auto lift_v = detail::lift_<to, from>::type::value;
-template<typename... xs>
-using reverse = typename detail::reverse_<std::tuple<xs...>, std::tuple<>>::type;
+ template<typename x, typename... xs>
+ using first = x;
-template<template<typename...> class inst, class x>
-using lift = typename detail::lift_<inst, x>::type;
+ template<typename x, typename... xs>
+ using rest = detail::tuple<xs...>;
-template<typename x, typename... xs>
-using first = x;
+ template<typename... xs>
+ using butlast = reverse<rest<reverse<xs...>>>;
-template<typename x, typename... xs>
-using rest = std::tuple<xs...>;
+ template<typename... xs>
+ using last = lift<first, reverse<xs...>>;
-template<typename... xs>
-using butlast = reverse<rest<reverse<xs...>>>;
+ template<typename x, typename rest>
+ using cons = typename detail::cons_<x, rest>::type;
-template<typename... xs>
-using last = lift<first, reverse<xs...>>;
+ template<typename xs, typename ys>
+ using append = typename detail::append_<xs, ys>;
-template<std::size_t max>
-using index_sequence = typename detail::index_sequence_<std::size_t, max, std::size_t(0)>::type;
+ template<typename rest, typename... xs>
+ using list_ = typename detail::list__<rest, xs...>;
} // ns meta
-#endif
diff --git a/compat/mutex.cpp b/compat/mutex.cpp
new file mode 100644
index 00000000..664677ea
--- /dev/null
+++ b/compat/mutex.cpp
@@ -0,0 +1,33 @@
+#include "mutex.hpp"
+#include <cstdlib>
+
+mutex& mutex::operator=(const mutex& rhs)
+{
+ if (rhs->isRecursive() != inner.isRecursive())
+ std::abort();
+
+ return *this;
+}
+
+mutex::mutex(const mutex& datum) : mutex{datum.inner.isRecursive() ? Recursive : NonRecursive}
+{
+}
+
+mutex::mutex(RecursionMode m) : inner{m}
+{
+}
+
+QMutex* mutex::operator&() const noexcept
+{
+ return &inner;
+}
+
+mutex::operator QMutex*() const noexcept
+{
+ return &inner;
+}
+
+QMutex* mutex::operator->() const noexcept
+{
+ return &inner;
+}
diff --git a/compat/mutex.hpp b/compat/mutex.hpp
new file mode 100644
index 00000000..54758a08
--- /dev/null
+++ b/compat/mutex.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <QMutex>
+
+#include "export.hpp"
+
+class OTR_COMPAT_EXPORT mutex
+{
+ mutable QMutex inner;
+
+public:
+ using RecursionMode = QMutex::RecursionMode;
+ static constexpr RecursionMode Recursive = RecursionMode::Recursive;
+ static constexpr RecursionMode NonRecursive = RecursionMode::NonRecursive;
+
+ mutex& operator=(const mutex& datum);
+ mutex(const mutex& datum);
+ explicit mutex(RecursionMode m);
+ mutex() : mutex{NonRecursive} {}
+
+ QMutex* operator&() const noexcept;
+ explicit operator QMutex*() const noexcept;
+ QMutex* operator->() const noexcept;
+};
diff --git a/compat/process-list.hpp b/compat/process-list.hpp
index 10613791..39e12603 100644
--- a/compat/process-list.hpp
+++ b/compat/process-list.hpp
@@ -52,7 +52,7 @@ static QStringList get_all_executable_names()
template<typename = void>
static QStringList get_all_executable_names()
{
- QStringList ret;
+ QStringList ret; ret.reserve(2048);
std::vector<int> vec;
while (true)
@@ -103,7 +103,7 @@ static QStringList get_all_executable_names()
if (idx != -1)
{
QString tmp = cmdline[0].mid(idx+1);
- if (cmdline.size() > 1 && (tmp == "wine.bin" || tmp == "wine"))
+ if (cmdline.size() > 1 && (tmp == QStringLiteral("wine.bin") || tmp == QStringLiteral("wine")))
{
idx = cmdline[1].lastIndexOf('/');
if (idx == -1)
@@ -129,14 +129,68 @@ static QStringList get_all_executable_names()
}
}
-#elif defined __linux
+#elif defined __linux__
+
+#include <cerrno>
+
+#ifdef OTR_HAS_LIBPROC2
+#include <libproc2/pids.h>
+template<typename = void>
+QStringList get_all_executable_names()
+{
+ QStringList ret; ret.reserve(2048);
+ enum pids_item items[] = { PIDS_ID_PID, PIDS_CMD, PIDS_CMDLINE_V };
+
+ enum rel_items { rel_pid, rel_cmd, rel_cmdline };
+ struct pids_info *info = NULL;
+ struct pids_stack *stack;
+ QString tmp; tmp.reserve(255);
+
+ procps_pids_new(&info, items, 3);
+ // procps-ng version 4.0.5 removed an unused argument in PIDS_VAL() macro.
+ // cf. https://gitlab.com/procps-ng/procps/-/commit/967fdcfb06e20aad0f3
+
+ // Although the emitted machine code is identical, backward API
+ // compatibility was silently broken in the patch with no upgrade path
+ // (e.g. deprecating PIDS_VAL() while introducing PIDS_VAL2()).
+
+ // Unfortunately, procps-ng doesn't include a #define for identifying its
+ // version. For these reasons the code below depends on undocumented ABI
+ // compatibility between procps-ng versions.. -sh 20241226
+
+#define OPENTRACK_PIDS_VAL(i, type, stack) stack->head[i].result.type
+
+ while ((stack = procps_pids_get(info, PIDS_FETCH_TASKS_ONLY)))
+ {
+ char **p_cmdline = OPENTRACK_PIDS_VAL(rel_cmdline, strv, stack);
+
+ // note, wine sets argv[0] so no parsing like in OSX case
+ if (p_cmdline && p_cmdline[0] && p_cmdline[0][0] &&
+ !(p_cmdline[0][0] == '-' && !p_cmdline[0][1]))
+ {
+ tmp = QString{p_cmdline[0]};
+ const int idx = std::max(tmp.lastIndexOf('\\'), tmp.lastIndexOf('/'));
+ if (idx != -1)
+ tmp = tmp.mid(idx+1);
+ //qDebug() << "procps" << tmp;
+ ret.append(tmp);
+ }
+ }
+ //qDebug() << "-- procps end";
+
+ procps_pids_unref(&info);
+
+ return ret;
+}
+#else
#include <proc/readproc.h>
#include <cerrno>
+
template<typename = void>
-static QStringList get_all_executable_names()
+QStringList get_all_executable_names()
{
- QStringList ret;
+ QStringList ret; ret.reserve(2048);
proc_t** procs = readproctab(PROC_FILLCOM);
if (procs == nullptr)
{
@@ -159,6 +213,7 @@ static QStringList get_all_executable_names()
free(procs);
return ret;
}
+#endif
#else
template<typename = void>
diff --git a/compat/qhash.hpp b/compat/qhash.hpp
new file mode 100644
index 00000000..5286e97e
--- /dev/null
+++ b/compat/qhash.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <functional>
+
+#include <QtGlobal>
+#include <QString>
+#include <QHashFunctions>
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+
+#include <cstdlib>
+
+namespace std {
+template<> struct hash<QString>
+{
+ using argument_type = QString;
+ using result_type = std::size_t;
+
+ std::size_t operator()(const QString& value) const noexcept
+ {
+ return (std::size_t) qHash(value);
+ }
+};
+}
+
+#endif
diff --git a/compat/qt-dpi.hpp b/compat/qt-dpi.hpp
new file mode 100644
index 00000000..fc17a062
--- /dev/null
+++ b/compat/qt-dpi.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <algorithm>
+#include <QWidget>
+
+static inline double screen_dpi(const QPaintDevice* widget)
+{
+ const auto& x = *widget;
+#ifdef _WIN32
+ return std::max(x.devicePixelRatioF(), 1.);
+#else
+ return std::max(std::max(x.logicalDpiX()/(double)x.physicalDpiX(), x.devicePixelRatioF()), 1.);
+#endif
+}
+
+template<typename self>
+struct screen_dpi_mixin
+{
+protected:
+ double screen_dpi() const
+ {
+ return ::screen_dpi(static_cast<const self*>(this));
+ }
+};
diff --git a/compat/qt-signal.cpp b/compat/qt-signal.cpp
new file mode 100644
index 00000000..8c23866b
--- /dev/null
+++ b/compat/qt-signal.cpp
@@ -0,0 +1,7 @@
+#define OTR_GENERATE_SIGNAL3(type) void sig_##type::operator()(const type& x) const { notify(x); }
+#include "qt-signal.hpp"
+namespace _qt_sig_impl {
+
+sig_void::sig_void(QObject* parent) : QObject(parent) {}
+
+}
diff --git a/compat/qt-signal.hpp b/compat/qt-signal.hpp
new file mode 100644
index 00000000..f74de642
--- /dev/null
+++ b/compat/qt-signal.hpp
@@ -0,0 +1,72 @@
+#pragma once
+
+// this is to avoid dealing with QMetaObject for the time being -sh 20190203
+
+#include "export.hpp"
+namespace options { class slider_value; }
+#include <QObject>
+#include <QList>
+
+namespace _qt_sig_impl {
+
+template<typename t> struct sig;
+
+class OTR_COMPAT_EXPORT sig_void final : public QObject
+{
+ Q_OBJECT
+
+public:
+ template<typename t, typename F>
+ sig_void(t* datum, F&& f, Qt::ConnectionType conntype = Qt::AutoConnection) : QObject(datum)
+ {
+ connect(this, &sig_void::notify, datum, f, conntype);
+ }
+ explicit sig_void(QObject* parent = nullptr);
+ void operator()() const { notify(); }
+
+signals:
+ void notify() const;
+};
+
+template<> struct sig<void> { using t = sig_void; };
+
+#ifndef OTR_GENERATE_SIGNAL3
+# define OTR_GENERATE_SIGNAL3(x)
+#endif
+#define OTR_GENERATE_SIGNAL2(type) \
+ class OTR_COMPAT_EXPORT sig_##type final : public QObject \
+ { \
+ Q_OBJECT \
+ public: \
+ explicit sig_##type(QObject* parent = nullptr) : QObject(parent) {} \
+ void operator()(const type& x) const; \
+ Q_SIGNALS: \
+ void notify(const type& x) const; \
+ }; \
+ OTR_GENERATE_SIGNAL3(type)
+
+# define OTR_GENERATE_SIGNAL(type) \
+ OTR_GENERATE_SIGNAL2(type); \
+ using qlist##type = QList<type>; \
+ OTR_GENERATE_SIGNAL2(qlist##type); \
+ template<> struct sig<type> { using t = sig_##type; }; \
+ template<> struct sig<qlist##type> { using t = qlist##type; }
+
+using slider_value = options::slider_value;
+
+OTR_GENERATE_SIGNAL(int);
+OTR_GENERATE_SIGNAL(double);
+OTR_GENERATE_SIGNAL(float);
+OTR_GENERATE_SIGNAL(bool);
+OTR_GENERATE_SIGNAL(QString);
+OTR_GENERATE_SIGNAL(slider_value);
+OTR_GENERATE_SIGNAL(QPointF);
+OTR_GENERATE_SIGNAL(QVariant);
+
+} // namespace _qt_sig_impl
+
+#undef OTR_GENERATE_SIGNAL2
+#undef OTR_GENERATE_SIGNAL
+
+template<typename t> using qt_signal = typename _qt_sig_impl::sig<t>::t;
+
diff --git a/compat/run-in-thread.hpp b/compat/run-in-thread.hpp
index b425532e..c552c600 100644
--- a/compat/run-in-thread.hpp
+++ b/compat/run-in-thread.hpp
@@ -7,9 +7,6 @@
* copyright notice and this permission notice appear in all copies.
*/
-#include "macros.hpp"
-
-#include <cassert>
#include <thread>
#include <condition_variable>
#include <utility>
@@ -17,99 +14,56 @@
#include <QObject>
#include <QThread>
-namespace qt_impl_detail {
-
-template<typename t>
-struct run_in_thread_traits
+namespace impl_run_in_thread {
+struct semaphore final
{
- using type = t;
- using ret_type = t;
- static inline void assign(t& lvalue, const t& rvalue) { lvalue = rvalue; }
- static inline t pass(const t& val) { return val; }
- template<typename F> static inline t call(F&& fun) { return std::move(fun()); }
-};
+ using lock_guard = std::unique_lock<std::mutex>;
+ std::mutex mtx;
+ std::condition_variable cvar;
+ bool flag = false;
-template<typename u>
-struct run_in_thread_traits<u&&>
-{
- using t = typename std::remove_reference<u>::type;
- using type = t;
- using ret_type = u;
- static inline void assign(t& lvalue, t&& rvalue) { lvalue = rvalue; }
- static inline t&& pass(t&& val) { return val; }
- template<typename F> static inline t&& call(F&& fun) { return std::move(fun()); }
-};
+ semaphore() = default;
-template<>
-struct run_in_thread_traits<void>
-{
- using type = unsigned char;
- using ret_type = void;
- static inline void assign(unsigned char&, unsigned char&&) {}
- static inline void pass(type&&) {}
- template<typename F> static type call(F&& fun) { fun(); return type(0); }
-};
+ void wait()
+ {
+ lock_guard guard(mtx);
+ while (!flag)
+ cvar.wait(guard);
+ }
+ void notify()
+ {
+ lock_guard guard(mtx);
+ flag = true;
+ cvar.notify_one();
+ }
+};
}
template<typename F>
-auto never_inline
-run_in_thread_sync(QObject* obj, F&& fun)
- -> typename qt_impl_detail::run_in_thread_traits<decltype(fun())>::ret_type
+void run_in_thread_sync(QObject* obj, F&& fun)
{
- using lock_guard = std::unique_lock<std::mutex>;
+ if (obj->thread() == QThread::currentThread())
+ return (void)fun();
- using traits = qt_impl_detail::run_in_thread_traits<decltype(fun())>;
-
- typename traits::type ret;
-
- struct semaphore final
- {
- std::mutex mtx;
- std::condition_variable cvar;
- bool flag;
-
- semaphore() : flag(false) {}
-
- void wait()
- {
- lock_guard guard(mtx);
- while (!flag)
- cvar.wait(guard);
- }
-
- void notify()
- {
- lock_guard guard(mtx);
- flag = true;
- cvar.notify_one();
- }
- };
-
- semaphore sem;
+ impl_run_in_thread::semaphore sem;
{
QObject src;
- QObject::connect(&src,
- &QObject::destroyed,
- obj,
- [&]() {
- traits::assign(ret, traits::call(fun));
- sem.notify();
- },
- Qt::AutoConnection);
+ QObject::connect(&src, &QObject::destroyed,
+ obj, [&] { fun(); sem.notify(); },
+ Qt::QueuedConnection);
}
sem.wait();
- return traits::pass(std::move(ret));
}
template<typename F>
void run_in_thread_async(QObject* obj, F&& fun)
{
+ if (obj->thread() == QThread::currentThread())
+ return (void)fun();
+
QObject src;
- QThread* t(obj->thread());
- assert(t);
- src.moveToThread(t);
- QObject::connect(&src, &QObject::destroyed, obj, std::move(fun), Qt::AutoConnection);
+ QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun), Qt::QueuedConnection);
}
diff --git a/compat/shm.cpp b/compat/shm.cpp
index 4bd89d35..f59469dc 100644
--- a/compat/shm.cpp
+++ b/compat/shm.cpp
@@ -10,130 +10,36 @@
#if defined _WIN32
#include <cstring>
-#include <stdio.h>
+#include <cstdio>
#include <accctrl.h>
#include <aclapi.h>
-#if !defined __WINE__
+#ifdef QT_CORE_LIB
# include <QDebug>
+# define warn(str, ...) (qDebug() << "shm:" str ": " << __VA_ARGS__)
+#else
+# define warn(str, ...) (void)0
#endif
-struct secattr final
-{
- bool success;
- SECURITY_DESCRIPTOR* pSD;
- SECURITY_ATTRIBUTES attrs;
- PSID pEveryoneSID;
- PACL pACL;
-
- void cleanup();
- secattr(DWORD perms);
- ~secattr();
-};
-
-void secattr::cleanup()
-{
- if (pEveryoneSID)
- FreeSid(pEveryoneSID);
- if (pACL)
- LocalFree(pACL);
- if (pSD)
- LocalFree(pSD);
- success = false;
- pSD = nullptr;
- pEveryoneSID = nullptr;
- pACL = nullptr;
-}
-
-secattr::secattr(DWORD perms) : success(true), pSD(nullptr), pEveryoneSID(nullptr), pACL(nullptr)
-{
- SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
- EXPLICIT_ACCESS ea;
-
- if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
- SECURITY_WORLD_RID,
- 0, 0, 0, 0, 0, 0, 0,
- &pEveryoneSID))
- {
- fprintf(stderr, "AllocateAndInitializeSid: %d\n", (int) GetLastError());
- goto cleanup;
- }
-
- memset(&ea, 0, sizeof(ea));
-
- ea.grfAccessPermissions = perms;
- ea.grfAccessMode = SET_ACCESS;
- ea.grfInheritance = NO_INHERITANCE;
- ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
- ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
- ea.Trustee.ptstrName = (LPTSTR) pEveryoneSID;
-
- if (SetEntriesInAcl(1, &ea, NULL, &pACL) != ERROR_SUCCESS)
- {
- fprintf(stderr, "SetEntriesInAcl: %d\n", (int) GetLastError());
- goto cleanup;
- }
-
- pSD = (SECURITY_DESCRIPTOR*) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
- if (pSD == nullptr)
- {
- fprintf(stderr, "LocalAlloc: %d\n", (int) GetLastError());
- goto cleanup;
- }
-
- if (!InitializeSecurityDescriptor(pSD,
- SECURITY_DESCRIPTOR_REVISION))
- {
- fprintf(stderr, "InitializeSecurityDescriptor: %d\n", (int) GetLastError());
- goto cleanup;
- }
-
- if (!SetSecurityDescriptorDacl(pSD,
- TRUE,
- pACL,
- FALSE))
- {
- fprintf(stderr, "SetSecurityDescriptorDacl: %d\n", (int) GetLastError());
- goto cleanup;
- }
-
- attrs.bInheritHandle = false;
- attrs.lpSecurityDescriptor = pSD;
- attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
-
- return;
-cleanup:
- cleanup();
-}
-
-secattr::~secattr()
-{
- cleanup();
-}
-
shm_wrapper::shm_wrapper(const char* shm_name, const char* mutex_name, int map_size)
{
- secattr sa(GENERIC_ALL|SYNCHRONIZE);
-
if (mutex_name == nullptr)
mutex = nullptr;
else
{
- mutex = CreateMutexA(sa.success ? &sa.attrs : nullptr, false, mutex_name);
+ mutex = CreateMutexA(nullptr, false, mutex_name);
if (!mutex)
{
- #if !defined __WINE__
- qDebug() << "CreateMutexA:" << (int) GetLastError();
- #endif
+ warn("CreateMutexA", (int) GetLastError());
return;
}
}
mapped_file = CreateFileMappingA(
INVALID_HANDLE_VALUE,
- sa.success ? &sa.attrs : nullptr,
+ nullptr,
PAGE_READWRITE,
0,
map_size,
@@ -141,9 +47,7 @@ shm_wrapper::shm_wrapper(const char* shm_name, const char* mutex_name, int map_s
if (!mapped_file)
{
-#if !defined __WINE__
- qDebug() << "CreateFileMappingA:", (int) GetLastError();
-#endif
+ warn("CreateFileMappingA", (int) GetLastError());
return;
}
@@ -155,19 +59,15 @@ shm_wrapper::shm_wrapper(const char* shm_name, const char* mutex_name, int map_s
map_size);
if (!mem)
- {
-#if !defined __WINE__
- qDebug() << "MapViewOfFile:" << (int) GetLastError();
-#endif
- }
+ warn("MapViewOfFile:", (int) GetLastError());
}
shm_wrapper::~shm_wrapper()
{
- if(!UnmapViewOfFile(mem))
+ if (mem && !UnmapViewOfFile(mem))
goto fail;
- if (!CloseHandle(mapped_file))
+ if (mapped_file && !CloseHandle(mapped_file))
goto fail;
if (mutex && !CloseHandle(mutex))
@@ -176,10 +76,7 @@ shm_wrapper::~shm_wrapper()
return;
fail:
- (void)0;
-#if !defined __WINE__
- qDebug() << "failed to close mapping";
-#endif
+ warn("failed to close mapping", (int) GetLastError());
}
bool shm_wrapper::lock()
@@ -209,7 +106,7 @@ shm_wrapper::shm_wrapper(const char *shm_name, const char* /*mutex_name*/, int m
strcat(filename, shm_name);
fd = shm_open(filename, O_RDWR | O_CREAT, 0600);
(void) ftruncate(fd, map_size);
- mem = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t)0);
+ mem = mmap(nullptr, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t)0);
}
shm_wrapper::~shm_wrapper()
@@ -234,7 +131,7 @@ bool shm_wrapper::success()
#ifndef _WIN32
return mem != (void*) -1;
#else
- return mem != NULL;
+ return mem != nullptr;
#endif
}
diff --git a/compat/shm.h b/compat/shm.h
index 5ea6c80a..5036b335 100644
--- a/compat/shm.h
+++ b/compat/shm.h
@@ -19,8 +19,8 @@
#include <sys/types.h>
#endif
-#include "macros.hpp"
#include "export.hpp"
+#include "macros.h"
class OTR_COMPAT_EXPORT shm_wrapper final
{
@@ -28,14 +28,17 @@ class OTR_COMPAT_EXPORT shm_wrapper final
#if defined(_WIN32)
HANDLE mutex, mapped_file;
#else
- int fd, size;
+ int fd;
+ unsigned size;
#endif
public:
- never_inline shm_wrapper(const char *shm_name, const char *mutex_name, int map_size);
- never_inline ~shm_wrapper();
- never_inline bool lock();
- never_inline bool unlock();
- never_inline bool success();
+ shm_wrapper(const char *shm_name, const char *mutex_name, int map_size);
+ ~shm_wrapper();
+ bool lock();
+ bool unlock();
+ bool success();
inline void* ptr() { return mem; }
+
+ OTR_DISABLE_MOVE_COPY(shm_wrapper);
};
diff --git a/compat/simple-mat.hpp b/compat/simple-mat.hpp
index c8c9f48b..e697f76a 100644
--- a/compat/simple-mat.hpp
+++ b/compat/simple-mat.hpp
@@ -8,13 +8,12 @@
#pragma once
-#include "export.hpp"
-
+#include <cstddef>
#include <type_traits>
#include <utility>
#include <cmath>
-namespace simple_mat_detail {
+namespace simple_mat {
// last param to fool SFINAE into overloading
template<int i, int j, int>
struct equals
@@ -51,81 +50,83 @@ namespace simple_mat_detail {
enum { Q = a == 1 ? 3 : 1 };
};
- template<typename num, int h, int w, typename...ts>
+ template<typename, int h, int w, typename...ts>
struct is_arglist_correct
{
enum { value = h * w == sizeof...(ts) };
};
-template<typename num, int h_, int w_>
+template<typename num, int H, int W>
class Mat
{
- static_assert(h_ > 0 && w_ > 0, "must have positive mat dimensions");
- num data[h_][w_];
+ static_assert(H > 0 && W > 0, "must have positive mat dimensions");
+ num data[H][W];
public:
- template<int Q = w_> std::enable_if_t<equals<Q, 1, 0>::value, num>
- constexpr inline operator()(unsigned i) const& { return data[i][0]; }
+ // parameters W and H are rebound so that SFINAE occurs
+ // removing them causes a compile-time error -sh 20150811
+
+ template<typename t, int Q = W> std::enable_if_t<equals<Q, 1, 0>::value, num>
+ constexpr inline operator()(t i) const& { return data[(unsigned)i][0]; }
- template<int P = h_> std::enable_if_t<equals<P, 1, 1>::value, num>
- constexpr inline operator()(unsigned i) const& { return data[0][i]; }
+ template<typename t, int P = H> std::enable_if_t<equals<P, 1, 1>::value, num>
+ constexpr inline operator()(t i) const& { return data[0][(unsigned)i]; }
- template<int Q = w_> std::enable_if_t<equals<Q, 1, 2>::value, num&>
- constexpr inline operator()(unsigned i) & { return data[i][0]; }
+ template<typename t, int Q = W> std::enable_if_t<equals<Q, 1, 2>::value, num&>
+ constexpr inline operator()(t i) & { return data[(unsigned)i][0]; }
- template<int P = h_> std::enable_if_t<equals<P, 1, 3>::value, num&>
- constexpr inline operator()(unsigned i) & { return data[0][i]; }
+ template<typename t, int P = H> std::enable_if_t<equals<P, 1, 3>::value, num&>
+ constexpr inline operator()(t i) & { return data[0][(unsigned)i]; }
-#define OPENTRACK_ASSERT_SWIZZLE static_assert(P == h_ && Q == w_, "")
+#define OTR_MAT_ASSERT_SWIZZLE static_assert(P == H && Q == W)
// const variants
- template<int P = h_, int Q = w_> std::enable_if_t<maybe_add_swizzle<P, Q, 1, 4>::value, num>
- constexpr inline x() const& { OPENTRACK_ASSERT_SWIZZLE; return operator()(0); }
+ template<int P = H, int Q = W> std::enable_if_t<maybe_add_swizzle<P, Q, 1, 4>::value, num>
+ constexpr inline x() const& { OTR_MAT_ASSERT_SWIZZLE; return operator()(0); }
- template<int P = h_, int Q = w_> std::enable_if_t<maybe_add_swizzle<P, Q, 2, 4>::value, num>
- constexpr inline y() const& { OPENTRACK_ASSERT_SWIZZLE; return operator()(1); }
+ template<int P = H, int Q = W> std::enable_if_t<maybe_add_swizzle<P, Q, 2, 4>::value, num>
+ constexpr inline y() const& { OTR_MAT_ASSERT_SWIZZLE; return operator()(1); }
- template<int P = h_, int Q = w_> std::enable_if_t<maybe_add_swizzle<P, Q, 3, 4>::value, num>
- constexpr inline z() const& { OPENTRACK_ASSERT_SWIZZLE; return operator()(2); }
+ template<int P = H, int Q = W> std::enable_if_t<maybe_add_swizzle<P, Q, 3, 4>::value, num>
+ constexpr inline z() const& { OTR_MAT_ASSERT_SWIZZLE; return operator()(2); }
- template<int P = h_, int Q = w_> std::enable_if_t<maybe_add_swizzle<P, Q, 4, 4>::value, num>
- constexpr inline w() const& { OPENTRACK_ASSERT_SWIZZLE; return operator()(3); }
+ template<int P = H, int Q = W> std::enable_if_t<maybe_add_swizzle<P, Q, 4, 4>::value, num>
+ constexpr inline w() const& { OTR_MAT_ASSERT_SWIZZLE; return operator()(3); }
// mutable variants
- template<int P = h_, int Q = w_> std::enable_if_t<maybe_add_swizzle<P, Q, 1, 4>::value, num&>
- constexpr inline x() & { OPENTRACK_ASSERT_SWIZZLE; return operator()(0); }
+ template<int P = H, int Q = W> std::enable_if_t<maybe_add_swizzle<P, Q, 1, 4>::value, num&>
+ constexpr inline x() & { OTR_MAT_ASSERT_SWIZZLE; return operator()(0); }
- template<int P = h_, int Q = w_> std::enable_if_t<maybe_add_swizzle<P, Q, 2, 4>::value, num&>
- constexpr inline y() & { OPENTRACK_ASSERT_SWIZZLE; return operator()(1); }
+ template<int P = H, int Q = W> std::enable_if_t<maybe_add_swizzle<P, Q, 2, 4>::value, num&>
+ constexpr inline y() & { OTR_MAT_ASSERT_SWIZZLE; return operator()(1); }
- template<int P = h_, int Q = w_> std::enable_if_t<maybe_add_swizzle<P, Q, 3, 4>::value, num&>
- constexpr inline z() & { OPENTRACK_ASSERT_SWIZZLE; return operator()(2); }
+ template<int P = H, int Q = W> std::enable_if_t<maybe_add_swizzle<P, Q, 3, 4>::value, num&>
+ constexpr inline z() & { OTR_MAT_ASSERT_SWIZZLE; return operator()(2); }
- template<int P = h_, int Q = w_> std::enable_if_t<maybe_add_swizzle<P, Q, 4, 4>::value, num&>
- constexpr inline w() & { OPENTRACK_ASSERT_SWIZZLE; return operator()(3); }
+ template<int P = H, int Q = W> std::enable_if_t<maybe_add_swizzle<P, Q, 4, 4>::value, num&>
+ constexpr inline w() & { OTR_MAT_ASSERT_SWIZZLE; return operator()(3); }
- // parameters w_ and h_ are rebound so that SFINAE occurs
- // removing them causes a compile-time error -sh 20150811
-
- template<int P = h_, int Q = w_>
- std::enable_if_t<is_vector<P, Q>::value, num>
- norm() const
+ template<int P = H, int Q = W>
+ constexpr auto norm_squared() const -> std::enable_if_t<is_vector<P, Q>::value, num>
{
- static_assert(P == h_ && Q == w_, "");
+ static_assert(P == H && Q == W);
const num val = dot(*this);
+ constexpr num eps = num(1e-4);
- if (val < num(1e-4))
+ if (val < eps)
return num(0);
else
- return std::sqrt(val);
+ return val;
}
- template<int R, int S, int P = h_, int Q = w_>
+ inline auto norm() const { return num(std::sqrt(norm_squared())); }
+
+ template<int R, int S, int P = H, int Q = W>
std::enable_if_t<is_vector_pair<R, S, P, Q>::value, num>
constexpr dot(const Mat<num, R, S>& p2) const
{
- static_assert(P == h_ && Q == w_, "");
+ static_assert(P == H && Q == W);
num ret = 0;
constexpr int len = vector_len<R, S>::value;
@@ -134,166 +135,201 @@ public:
return ret;
}
- template<int R, int S, int P = h_, int Q = w_>
+ template<int R, int S, int P = H, int Q = W>
std::enable_if_t<is_dim3<P, Q, R, S>::value, Mat<num, is_dim3<P, Q, R, S>::P, is_dim3<P, Q, R, S>::Q>>
constexpr cross(const Mat<num, R, S>& b) const
{
- static_assert(P == h_ && Q == w_, "");
- auto& a = *this;
+ static_assert(P == H && Q == W);
+ const auto& a = *this;
return Mat<num, R, S>(a.y()*b.z() - a.z()*b.y(),
a.z()*b.x() - a.x()*b.z(),
a.x()*b.y() - a.y()*b.x());
}
- constexpr Mat<num, h_, w_> operator+(const Mat<num, h_, w_>& other) const
+ constexpr Mat<num, H, W> operator+(const Mat<num, H, W>& other) const
{
- Mat<num, h_, w_> ret;
- for (int j = 0; j < h_; j++)
- for (int i = 0; i < w_; i++)
+ Mat<num, H, W> ret;
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
ret(j, i) = data[j][i] + other.data[j][i];
return ret;
}
- constexpr Mat<num, h_, w_> operator-(const Mat<num, h_, w_>& other) const
+ constexpr Mat<num, H, W> operator-(const Mat<num, H, W>& other) const
{
- Mat<num, h_, w_> ret;
- for (int j = 0; j < h_; j++)
- for (int i = 0; i < w_; i++)
+ Mat<num, H, W> ret;
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
ret(j, i) = data[j][i] - other.data[j][i];
return ret;
}
- constexpr Mat<num, h_, w_> operator+(const num other) const
+ constexpr Mat<num, H, W> operator+(const num other) const
{
- Mat<num, h_, w_> ret;
- for (int j = 0; j < h_; j++)
- for (int i = 0; i < w_; i++)
+ Mat<num, H, W> ret;
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
ret(j, i) = data[j][i] + other;
return ret;
}
- constexpr Mat<num, h_, w_> operator-(const num other) const
+ constexpr Mat<num, H, W> operator-(const num other) const
{
- Mat<num, h_, w_> ret;
- for (int j = 0; j < h_; j++)
- for (int i = 0; i < w_; i++)
+ Mat<num, H, W> ret;
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
ret(j, i) = data[j][i] - other;
return ret;
}
template<int p>
- constexpr Mat<num, h_, p> operator*(const Mat<num, w_, p>& other) const
+ constexpr Mat<num, H, p> operator*(const Mat<num, W, p>& other) const
{
- Mat<num, h_, p> ret;
- for (int k = 0; k < h_; k++)
+ Mat<num, H, p> ret;
+ for (int k = 0; k < H; k++)
for (int i = 0; i < p; i++)
{
ret(k, i) = 0;
- for (int j = 0; j < w_; j++)
+ for (int j = 0; j < W; j++)
ret(k, i) += data[k][j] * other(j, i);
}
return ret;
}
- constexpr Mat<num, h_, w_> mult_elementwise(const Mat<num, h_, w_>& other) const&
+ constexpr Mat<num, H, W> mult_elementwise(const Mat<num, H, W>& other) const&
{
- Mat<num, h_, w_> ret;
+ Mat<num, H, W> ret;
- for (unsigned j = 0; j < h_; j++)
- for (unsigned i = 0; i < w_; i++)
+ for (unsigned j = 0; j < H; j++)
+ for (unsigned i = 0; i < W; i++)
ret(j, i) = data[j][i] * other.data[j][i];
return ret;
}
template<typename t, typename u>
- constexpr inline num operator()(t j, u i) const& { return data[(int) j][(int) i]; }
+ constexpr inline num operator()(t j, u i) const& { return data[(unsigned)j][(unsigned)i]; }
template<typename t, typename u>
- constexpr inline num& operator()(t j, u i) & { return data[(int) j][(int) i]; }
+ constexpr inline num& operator()(t j, u i) & { return data[(unsigned)j][(unsigned)i]; }
-#ifdef __GNUG__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wmissing-braces"
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wmissing-braces"
#endif
- template<typename... ts, int h__ = h_, int w__ = w_,
- typename = std::enable_if_t<is_arglist_correct<num, h__, w__, ts...>::value>>
+ template<typename... ts, int h2 = H, int w2 = W,
+ typename = std::enable_if_t<is_arglist_correct<num, h2, w2, ts...>::value>>
constexpr Mat(const ts... xs) : data{static_cast<num>(xs)...}
{
- static_assert(h__ == h_ && w__ == w_, "");
+ static_assert(h2 == H && w2 == W);
}
-#ifdef __GNUG__
-# pragma GCC diagnostic pop
+#ifdef __clang__
+# pragma clang diagnostic pop
#endif
constexpr Mat()
{
- for (int j = 0; j < h_; j++)
- for (int i = 0; i < w_; i++)
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
data[j][i] = num(0);
}
- Mat(const num* mem)
+ constexpr Mat(const num* mem)
{
- for (int j = 0; j < h_; j++)
- for (int i = 0; i < w_; i++)
- data[j][i] = mem[i*h_+j];
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
+ data[j][i] = mem[i*H+j];
}
- operator num*() { return reinterpret_cast<num*>(data); }
- operator const num*() const { return reinterpret_cast<const num*>(data); }
+ constexpr Mat(const Mat<num, H, W>& x)
+ {
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
+ data[j][i] = x(j, i);
+ }
+
+ constexpr operator num*() & { return (num*)data; }
+ constexpr operator const num*() const& { return (const num*)data; }
// XXX add more operators as needed, third-party dependencies mostly
// not needed merely for matrix algebra -sh 20141030
- template<int h__ = h_>
- static std::enable_if_t<h_ == w_, Mat<num, h__, h__>> eye()
+ template<int H_ = H>
+ static constexpr std::enable_if_t<H == W, Mat<num, H_, H_>> eye()
{
- static_assert(h_ == h__, "");
+ static_assert(H == H_);
- Mat<num, h_, h_> ret;
- for (int j = 0; j < h_; j++)
- for (int i = 0; i < w_; i++)
+ Mat<num, H, H> ret;
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
ret.data[j][i] = 0;
- for (int i = 0; i < h_; i++)
+ for (int i = 0; i < H; i++)
ret.data[i][i] = 1;
return ret;
}
- constexpr Mat<num, w_, h_> t() const
+ constexpr Mat<num, W, H> t() const
{
- Mat<num, w_, h_> ret;
+ Mat<num, W, H> ret;
- for (int j = 0; j < h_; j++)
- for (int i = 0; i < w_; i++)
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
ret(i, j) = data[j][i];
return ret;
}
+
+ constexpr Mat<num, H, W>& operator=(const Mat<num, H, W>& rhs)
+ {
+ for (unsigned j = 0; j < H; j++)
+ for (unsigned i = 0; i < W; i++)
+ data[j][i] = rhs(j, i);
+
+ return *this;
+ }
};
+template<unsigned k, typename num, int h, int w>
+constexpr num get(const Mat<num, h, w>& m) { return m(k); }
+
+template<unsigned k, typename num, int h, int w>
+constexpr num& get(Mat<num, h, w>& m) { return m(k); }
+
+} // ns simple_mat
+
+template<typename num, int h, int w>
+using Mat = simple_mat::Mat<num, h, w>;
+
template<typename num, int h, int w>
constexpr Mat<num, h, w> operator*(num scalar, const Mat<num, h, w>& mat)
{
return mat * scalar;
}
-template<typename num, int h_, int w_>
-constexpr Mat<num, h_, w_> operator*(const Mat<num, h_, w_>& self, num other)
+template<typename num, int H, int W>
+constexpr Mat<num, H, W> operator*(const Mat<num, H, W>& self, num other)
{
- Mat<num, h_, w_> ret;
- for (int j = 0; j < h_; j++)
- for (int i = 0; i < w_; i++)
+ Mat<num, H, W> ret;
+ for (int j = 0; j < H; j++)
+ for (int i = 0; i < W; i++)
ret(j, i) = self(j, i) * other;
return ret;
}
-} // ns simple_mat_detail
+namespace std {
+ template<typename num, int H, int W>
+ struct tuple_size<Mat<num, H, W>> :
+ std::integral_constant<std::size_t, H == 1 || W == 1 ? W * H : 0>
+ {};
-template<typename num, int h, int w>
-using Mat = simple_mat_detail::Mat<num, h, w>;
+ template<std::size_t k, typename num, int h, int w>
+ struct tuple_element<k, Mat<num, h, w>>
+ {
+ using type = std::remove_const_t<std::remove_reference_t<num>>;
+ };
+} // ns std
diff --git a/compat/sleep.cpp b/compat/sleep.cpp
new file mode 100644
index 00000000..e64e6254
--- /dev/null
+++ b/compat/sleep.cpp
@@ -0,0 +1,23 @@
+#include "sleep.hpp"
+
+#ifdef _WIN32
+# include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+namespace portable
+{
+ void sleep(int milliseconds)
+ {
+ if (milliseconds > 0)
+ {
+#ifdef _WIN32
+
+ Sleep((unsigned)milliseconds);
+#else
+ usleep(unsigned(milliseconds) * 1000U); // takes microseconds
+#endif
+ }
+ }
+}
diff --git a/compat/sleep.hpp b/compat/sleep.hpp
index 4cd7a397..9419b36b 100644
--- a/compat/sleep.hpp
+++ b/compat/sleep.hpp
@@ -1,24 +1,7 @@
#pragma once
-#ifdef _WIN32
-# include <windows.h>
-#else
-# include <unistd.h>
-#endif
+#include "export.hpp"
-namespace portable
-{
-#ifdef _WIN32
- inline void sleep(int milliseconds)
- {
- if (milliseconds > 0)
- Sleep(milliseconds);
- }
-#else
- inline void sleep(int milliseconds)
- {
- if (milliseconds > 0)
- usleep(unsigned(milliseconds) * 1000U); // takes microseconds
- }
-#endif
+namespace portable {
+ OTR_COMPAT_EXPORT void sleep(int milliseconds);
}
diff --git a/compat/sysexits.hpp b/compat/sysexits.hpp
new file mode 100644
index 00000000..6747fc88
--- /dev/null
+++ b/compat/sysexits.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <cstdlib> // for EXIT_SUCCESS, EXIT_FAILRUE
+
+#ifndef _WIN32
+# include <sysexits.h>
+#else
+// this conforms to BSD sysexits(3)
+// reference the manual page on FreeBSD or Linux for semantics
+# define EX_OK 0
+# define EX_USAGE 64
+# define EX_DATAERR 65
+# define EX_NOINPUT 66
+# define EX_NOUSER 67
+# define EX_NOHOST 68
+# define EX_UNAVAILABLE 69
+# define EX_SOFTWARE 70
+# define EX_OSERR 71
+# define EX_OSFILE 72
+# define EX_CANTCREAT 73
+# define EX_IOERR 74
+# define EX_TEMPFAIL 75
+# define EX_PROTOCOL 76
+# define EX_NOPERM 77
+# define EX_CONFIG 78
+#endif
+
+
diff --git a/compat/thread-name.cpp b/compat/thread-name.cpp
new file mode 100644
index 00000000..08a7d628
--- /dev/null
+++ b/compat/thread-name.cpp
@@ -0,0 +1,87 @@
+#include "thread-name.hpp"
+#ifdef _WIN32
+# include <QDebug>
+# include <windows.h>
+#else
+# include <QThread>
+#endif
+
+namespace portable {
+
+#ifdef _WIN32
+
+#ifdef _MSC_VER
+struct THREADNAME_INFO
+{
+ DWORD dwType; // must be 0x1000
+ LPCSTR szName; // pointer to name (in user addr space)
+ HANDLE dwThreadID; // thread ID (-1=caller thread)
+ DWORD dwFlags; // reserved for future use, must be zero
+};
+
+static inline
+void set_curthread_name_old_(const char* name)
+{
+ HANDLE curthread = GetCurrentThread();
+ THREADNAME_INFO info; // NOLINT(cppcoreguidelines-pro-type-member-init)
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = curthread;
+ info.dwFlags = 0;
+ __try
+ {
+ static_assert(sizeof(info) % sizeof(unsigned) == 0);
+ unsigned sz = sizeof(info)/sizeof(unsigned);
+ RaiseException(0x406D1388, 0, sz, (const ULONG_PTR*)&info);
+ }
+ __except (EXCEPTION_CONTINUE_EXECUTION)
+ {
+ }
+}
+
+static inline
+void set_curthread_name_old(const QString& name_)
+{
+ QByteArray str = name_.toLocal8Bit();
+ const char* name = str.constData();
+
+ set_curthread_name_old_(name);
+}
+#else
+
+static inline void set_curthread_name_old(const QString&) {}
+
+#endif
+
+using SetThreadDescr_type = HRESULT (__stdcall *)(HANDLE, const wchar_t*);
+
+static SetThreadDescr_type get_funptr()
+{
+ HMODULE module;
+ if (GetModuleHandleExA(0, "kernel32.dll", &module))
+ return (SetThreadDescr_type)GetProcAddress(module, "SetThreadDescription");
+ else
+ return nullptr;
+}
+
+void set_curthread_name(const QString& name)
+{
+ static_assert(sizeof(wchar_t) == sizeof(decltype(*QString().utf16())));
+ static const SetThreadDescr_type fn = get_funptr();
+
+ if (fn)
+ fn(GetCurrentThread(), (const wchar_t*)name.utf16());
+ else
+ set_curthread_name_old(name);
+}
+
+#else
+
+void set_curthread_name(const QString& name)
+{
+ QThread::currentThread()->setObjectName(name);
+}
+
+#endif
+
+} // ns portable
diff --git a/compat/thread-name.hpp b/compat/thread-name.hpp
new file mode 100644
index 00000000..21256003
--- /dev/null
+++ b/compat/thread-name.hpp
@@ -0,0 +1,6 @@
+#pragma once
+#include "export.hpp"
+#include <QString>
+namespace portable {
+ OTR_COMPAT_EXPORT void set_curthread_name(const QString& name);
+}
diff --git a/compat/time.hpp b/compat/time.hpp
index d34e4e8c..0d171038 100644
--- a/compat/time.hpp
+++ b/compat/time.hpp
@@ -7,17 +7,9 @@ namespace time_units {
template<typename repr, typename ratio = std::ratio<1>>
using duration = std::chrono::duration<repr, ratio>;
-template<typename t, typename u>
-static inline constexpr auto time_cast(const u& in)
-{
- return std::chrono::duration_cast<t>(in);
-}
-
-using secs = duration<double>;
-using secs_ = duration<long>;
-using ms = duration<double, std::milli>;
-using us = duration<double, std::micro>;
-using us_ = duration<long long, std::micro>;
-using ns = duration<long long, std::nano>;
+using secs = duration<float>;
+using ms = duration<float, std::milli>;
+using us = duration<float, std::micro>;
+using ns = duration<float, std::nano>;
} // ns time_units
diff --git a/compat/timer.cpp b/compat/timer.cpp
index 162ba16f..fdea185a 100644
--- a/compat/timer.cpp
+++ b/compat/timer.cpp
@@ -6,10 +6,12 @@
* notice appear in all copies.
*/
-#include <cassert>
+#undef NDEBUG
#include "timer.hpp"
+#include <cassert>
#include <cmath>
+#include <QDebug>
Timer::Timer()
{
@@ -21,40 +23,25 @@ void Timer::start()
gettime(&state);
}
-// nanoseconds
-
-long long Timer::elapsed_nsecs() const
-{
- timespec cur{};
- gettime(&cur);
- return conv_nsecs(cur);
-}
-
-long long Timer::conv_nsecs(const struct timespec& cur) const
+struct timespec Timer::get_delta() const
{
- return (cur.tv_sec - state.tv_sec) * 1000000000LL + (cur.tv_nsec - state.tv_nsec);
-}
-
-// microseconds
-
-double Timer::elapsed_usecs() const
-{
- timespec cur{};
- gettime(&cur);
- const long long nsecs = conv_nsecs(cur);
- return nsecs * 1e-3;
+ struct timespec ts; // NOLINT
+ gettime(&ts);
+ return { ts.tv_sec - state.tv_sec, ts.tv_nsec - state.tv_nsec };
}
// milliseconds
double Timer::elapsed_ms() const
{
- return elapsed_usecs() / 1000.;
+ struct timespec delta = get_delta();
+ return delta.tv_sec * 1000 + delta.tv_nsec * 1e-6;
}
double Timer::elapsed_seconds() const
{
- return double(elapsed_nsecs() * 1e-9L);
+ struct timespec delta = get_delta();
+ return delta.tv_sec + delta.tv_nsec * 1e-9;
}
// --
@@ -64,29 +51,24 @@ double Timer::elapsed_seconds() const
#if defined (_WIN32)
# include <windows.h>
-static LARGE_INTEGER otr_get_clock_frequency()
+static auto otr_get_clock_frequency()
{
LARGE_INTEGER freq{};
- const BOOL ret = QueryPerformanceFrequency(&freq);
+ BOOL ret = QueryPerformanceFrequency(&freq);
assert(ret && "QueryPerformanceFrequency failed");
- return freq;
+ return freq.QuadPart;
}
-static void otr_clock_gettime(timespec* ts)
+void Timer::gettime(timespec* state)
{
- static const LARGE_INTEGER freq = otr_get_clock_frequency();
-
+ static const auto freq = otr_get_clock_frequency();
LARGE_INTEGER d;
+ BOOL ret = QueryPerformanceCounter(&d);
+ assert(ret && "QueryPerformanceCounter failed");
- (void) QueryPerformanceCounter(&d);
-
- using ll = long long;
- const ll part = ll(std::roundl((d.QuadPart * 1000000000.L) / ll(freq.QuadPart)));
- using t_s = decltype(ts->tv_sec);
- using t_ns = decltype(ts->tv_nsec);
-
- ts->tv_sec = t_s(part / 1000000000);
- ts->tv_nsec = t_ns(part % 1000000000);
+ constexpr int nsec = 1'000'000 * 1000;
+ state->tv_sec = (time_t)(d.QuadPart/freq);
+ state->tv_nsec = (decltype(state->tv_nsec))(d.QuadPart % freq * nsec / freq);
}
#elif defined __MACH__
@@ -96,32 +78,30 @@ static void otr_clock_gettime(timespec* ts)
static mach_timebase_info_data_t otr_get_mach_frequency()
{
mach_timebase_info_data_t timebase_info;
- (void) mach_timebase_info(&timebase_info);
+ kern_return_t status = mach_timebase_info(&timebase_info);
+ assert(status == KERN_SUCCESS && "mach_timebase_info failed");
return timebase_info;
}
-static void otr_clock_gettime(timespec* ts)
+void Timer::gettime(timespec* ts)
{
static const mach_timebase_info_data_t timebase_info = otr_get_mach_frequency();
uint64_t state, nsec;
state = mach_absolute_time();
nsec = state * timebase_info.numer / timebase_info.denom;
- ts->tv_sec = nsec / 1000000000L;
- ts->tv_nsec = nsec % 1000000000L;
+ ts->tv_sec = nsec / 1000000000UL;
+ ts->tv_nsec = nsec % 1000000000UL;
+}
+
+#else
+
+void Timer::gettime(timespec* ts)
+{
+ int error = clock_gettime(CLOCK_MONOTONIC, ts);
+ assert(error == 0 && "clock_gettime failed");
}
#endif
// common
-void Timer::gettime(timespec* state)
-{
-#if defined(_WIN32) || defined(__MACH__)
- otr_clock_gettime(state);
-#elif defined CLOCK_MONOTONIC
- const int res = clock_gettime(CLOCK_MONOTONIC, state);
- assert(res == 0 && "must support CLOCK_MONOTONIC");
-#else
-# error "timer query method not known"
-#endif
-}
diff --git a/compat/timer.hpp b/compat/timer.hpp
index 03b537ac..47072226 100644
--- a/compat/timer.hpp
+++ b/compat/timer.hpp
@@ -10,43 +10,19 @@
#include "export.hpp"
#include "time.hpp"
-
#include <ctime>
-class OTR_COMPAT_EXPORT Timer final
+struct OTR_COMPAT_EXPORT Timer final
{
- struct timespec state;
- long long conv_nsecs(const struct timespec& cur) const;
-
- static void gettime(struct timespec* state);
-
- using ns = time_units::ns;
-public:
Timer();
void start();
- template<typename t>
- t elapsed() const
- {
- using namespace time_units;
- return time_cast<t>(ns(elapsed_nsecs()));
- }
-
- template<typename t>
- bool is_elapsed(const t& time_value)
- {
- using namespace time_units;
-
- if (unlikely(elapsed<ns>() >= time_value))
- {
- start();
- return true;
- }
- return false;
- }
-
- long long elapsed_nsecs() const;
- double elapsed_usecs() const;
double elapsed_ms() const;
double elapsed_seconds() const;
+
+private:
+ struct timespec state {};
+ static void gettime(struct timespec* state);
+ struct timespec get_delta() const;
+ using ns = time_units::ns;
};
diff --git a/compat/tr.hpp b/compat/tr.hpp
new file mode 100644
index 00000000..c5a561e7
--- /dev/null
+++ b/compat/tr.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <QObject>
+
+// The class does nothing except provide a fake assignment operator for QObject
+// It's meant to be used inside classes that need i18n support but are returned by value.
+
+struct TR : QObject
+{
+ TR() = default;
+ TR(const TR&) : QObject(nullptr) {}
+
+ TR& operator=(const TR&) { return *this; }
+};
diff --git a/compat/variance.hpp b/compat/variance.hpp
index 7a83154c..8abefd33 100644
--- a/compat/variance.hpp
+++ b/compat/variance.hpp
@@ -1,7 +1,6 @@
#pragma once
#include <cmath>
-#include <cinttypes>
// no copyright information other than the attribution below.
@@ -18,19 +17,18 @@
// Comparison of Several Algorithms for Computing Sample Means and Variances.
// Journal of the American Statistical Association, Vol. 69, No. 348, 859-866.
-class variance
+struct variance final
{
- double m_old, m_new, s_old, s_new;
- std::uintptr_t cnt;
-
-public:
- using size_type = std::uintptr_t;
+ using size_type = unsigned;
- variance() : cnt(0) {}
+ variance& operator=(variance const&) = default;
+ void clear() { *this = {}; }
- void clear() { *this = variance(); }
+ constexpr size_type count() const { return cnt; }
- size_type count() { return cnt; }
+ constexpr double avg() const { return cnt > 0 ? m_new : 0; }
+ constexpr double Var() const { return cnt > 1 ? s_new/(cnt - 1) : 0; }
+ double stddev() const { return std::sqrt(Var()); }
void input(double x)
{
@@ -51,7 +49,7 @@ public:
}
}
- double avg() const { return cnt > 0 ? m_new : 0; }
- double Var() const { return cnt > 1 ? s_new/(cnt - 1) : 0; }
- double stddev() const { return std::sqrt(Var()); }
+private:
+ double m_old, m_new, s_old, s_new;
+ size_type cnt = 0;
};