summaryrefslogtreecommitdiffhomepage
path: root/compat
diff options
context:
space:
mode:
Diffstat (limited to 'compat')
-rw-r--r--compat/CMakeLists.txt2
-rw-r--r--compat/functional.hpp86
-rw-r--r--compat/meta.hpp22
-rw-r--r--compat/time.hpp25
-rw-r--r--compat/timer-resolution.cpp55
-rw-r--r--compat/timer-resolution.hpp45
-rw-r--r--compat/timer.cpp32
-rw-r--r--compat/timer.hpp18
-rw-r--r--compat/util.hpp33
9 files changed, 264 insertions, 54 deletions
diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt
index 40850862..7655a223 100644
--- a/compat/CMakeLists.txt
+++ b/compat/CMakeLists.txt
@@ -5,5 +5,5 @@ if(NOT WIN32 AND NOT APPLE)
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")
+ set_property(SOURCE nan.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -fno-lto -fno-fast-math -fno-finite-math-only -O0")
endif()
diff --git a/compat/functional.hpp b/compat/functional.hpp
new file mode 100644
index 00000000..893fe1a0
--- /dev/null
+++ b/compat/functional.hpp
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <algorithm>
+#include <iterator>
+#include <type_traits>
+
+template<typename t>
+using remove_qualifiers = std::remove_reference_t<std::remove_cv_t<t>>;
+
+namespace functools
+{
+
+template<typename seq_, typename = void>
+struct reserver_
+{
+ static inline void maybe_reserve_space(seq_&, unsigned)
+ {
+ //qDebug() << "nada";
+ }
+};
+
+template<typename seq_>
+struct reserver_<seq_, decltype(std::declval<seq_>().reserve(0u), (void)0)>
+{
+ static inline void maybe_reserve_space(seq_& seq, unsigned sz)
+ {
+ seq.reserve(sz);
+ }
+};
+
+template<typename seq_>
+inline void maybe_reserve_space(seq_& seq, unsigned sz)
+{
+ reserver_<seq_, void>::maybe_reserve_space(seq, sz);
+}
+
+} // ns
+
+template<typename t, t value_>
+struct constant final
+{
+ using type = t;
+ constexpr type operator()() const noexcept
+ {
+ return value_;
+ }
+ static constexpr type value = value_;
+
+ constant() = delete;
+};
+
+template<typename seq_, typename F>
+auto map(F&& fun, const seq_& seq)
+{
+ using seq_type = remove_qualifiers<seq_>;
+
+ seq_type ret;
+ std::back_insert_iterator<seq_type> it = std::back_inserter(ret);
+
+ for (const auto& elt : seq)
+ it = fun(elt);
+
+ return ret;
+}
+
+template<typename seq_, typename F>
+auto remove_if_not(F&& fun, const seq_& seq)
+{
+ using namespace functools;
+
+ using seq_type = remove_qualifiers<seq_>;
+ using value_type = typename std::iterator_traits<decltype(std::begin(std::declval<seq_>()))>::value_type;
+ using fun_ret_type = decltype(fun(std::declval<const value_type&>()));
+ static_assert(std::is_convertible<fun_ret_type, bool>::value, "must return bool");
+
+ seq_type ret;
+ maybe_reserve_space(ret, seq.size());
+
+ std::back_insert_iterator<seq_type> it = std::back_inserter(ret);
+
+ for (const value_type& elt : seq)
+ if (fun(elt))
+ it = elt;
+
+ return ret;
+}
diff --git a/compat/meta.hpp b/compat/meta.hpp
index b1c1dd1a..900c515f 100644
--- a/compat/meta.hpp
+++ b/compat/meta.hpp
@@ -1,6 +1,8 @@
#pragma once
+#include <type_traits>
#include <tuple>
+#include <cstddef>
namespace meta {
@@ -29,7 +31,20 @@ namespace detail {
{
using type = inst<xs...>;
};
-}
+
+ template<typename N, N max, N pos, typename... xs>
+ struct index_sequence_
+ {
+ using part = std::integral_constant<N, pos>;
+ using type = typename index_sequence_<N, max, pos+1, xs..., part>::type;
+ };
+
+ template<typename N, N max, typename... xs>
+ struct index_sequence_<N, max, max, xs...>
+ {
+ using type = std::tuple<xs...>;
+ };
+} // ns detail
template<typename... xs>
@@ -50,4 +65,7 @@ using butlast = reverse<rest<reverse<xs...>>>;
template<typename... xs>
using last = lift<first, reverse<xs...>>;
-}
+template<std::size_t max>
+using index_sequence = typename detail::index_sequence_<std::size_t, max, std::size_t(0)>::type;
+
+} // ns meta
diff --git a/compat/time.hpp b/compat/time.hpp
new file mode 100644
index 00000000..fbe7469a
--- /dev/null
+++ b/compat/time.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <chrono>
+#include <type_traits>
+
+namespace time_units {
+
+template<typename repr, typename ratio>
+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, std::ratio<1, 1>>;
+using secs_ = duration<long long, std::ratio<1, 1>>;
+using ms = duration<double, std::milli>;
+using ms_ = duration<long long, std::milli>;
+using us = duration<double, std::micro>;
+using us_ = duration<long long, std::micro>;
+using ns = duration<long long, std::nano>;
+
+} // ns time_units
diff --git a/compat/timer-resolution.cpp b/compat/timer-resolution.cpp
index 597ee91e..d59c250d 100644
--- a/compat/timer-resolution.cpp
+++ b/compat/timer-resolution.cpp
@@ -8,12 +8,11 @@
#include "timer-resolution.hpp"
#if defined _WIN32
-# include <windows.h>
-
# include <QLibrary>
# include <QDebug>
-typedef LONG (__stdcall *funptr_NtSetTimerResolution) (ULONG, BOOLEAN, PULONG);
+using namespace timer_impl;
+
static funptr_NtSetTimerResolution init_timer_resolution_funptr();
static funptr_NtSetTimerResolution get_funptr();
@@ -41,62 +40,72 @@ static funptr_NtSetTimerResolution init_timer_resolution_funptr()
static funptr_NtSetTimerResolution get_funptr()
{
+ // starting with C++11 static initializers are fully
+ // thread-safe and run the first time function is called
+
+ // cf. http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11
+
static auto ret = init_timer_resolution_funptr();
return ret;
}
-timer_resolution::timer_resolution(int msecs) : old_value(-1)
+timer_resolution::timer_resolution(int msecs) : old_value(fail_())
{
- if (msecs <= 0 || msecs > 30)
+ if (msecs <= 0 || msecs > 100)
{
qDebug() << "can't set timer resolution to" << msecs << "ms";
return;
}
- funptr_NtSetTimerResolution f = get_funptr();
- if (f == nullptr)
+ funptr_NtSetTimerResolution set_timer_res = get_funptr();
+ if (set_timer_res == nullptr)
return;
// hundredth of a nanosecond
- const ULONG value = msecs * ULONG(10000);
- NTSTATUS error = f(value, TRUE, &old_value);
- ULONG old_value_ = -1;
+ const ulong_ value = msecs * ulong_(10000);
+ ntstatus_ res;
- if (error != 0)
+ res = set_timer_res(value, true_(), &old_value);
+
+ if (res < 0)
{
- old_value = -1;
- qDebug() << "NtSetTimerResolution erred with" << error;
+ old_value = fail_();
+ qDebug() << "NtSetTimerResolution erred with" << res;
return;
}
// see if it stuck
- error = f(value, TRUE, &old_value_);
- if (error != 0)
+ ulong_ old_value_ = fail_();
+
+ res = set_timer_res(value, true_(), &old_value_);
+ if (res < 0)
{
- old_value = -1;
- qDebug() << "NtSetTimerResolution check erred with" << error;
+ old_value = fail_();
+ qDebug() << "NtSetTimerResolution check erred with" << res;
return;
}
if (old_value_ != old_value)
{
+ using t = long long;
+
qDebug() << "NtSetTimerResolution:"
<< "old value didn't stick"
- << "current resolution" << old_value_
- << "* 100 ns";
- old_value = -1;
+ << "current resolution" << (t(old_value_) * t(100))
+ << "ns";
+ old_value = fail_();
return;
}
}
timer_resolution::~timer_resolution()
{
- if (old_value != ULONG(-1))
+ if (old_value != fail_())
{
funptr_NtSetTimerResolution f = get_funptr();
- ULONG fuzz = -1;
- (void) f(old_value, TRUE, &fuzz);
+ ulong_ fuzz = fail_();
+ (void) f(old_value, true_(), &fuzz);
}
}
diff --git a/compat/timer-resolution.hpp b/compat/timer-resolution.hpp
index 5db877c0..8c18a600 100644
--- a/compat/timer-resolution.hpp
+++ b/compat/timer-resolution.hpp
@@ -3,14 +3,57 @@
#if defined _WIN32
# include "export.hpp"
+#include <type_traits>
+
+namespace timer_impl
+{
+
+// cf. https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
+// for NTSTATUS, see http://stackoverflow.com/questions/3378622/how-to-understand-the-ntstatus-nt-success-typedef-in-windows-ddk
+
+using ulong_ = unsigned long;
+using long_ = long;
+using byte_ = unsigned char;
+using boolean_ = byte_;
+
+using true_ = std::integral_constant<int, 1>;
+
+using fail_ = std::integral_constant<byte_, byte_(-1)>;
+
+// cf. http://stackoverflow.com/questions/3378622/how-to-understand-the-ntstatus-nt-success-typedef-in-windows-ddk
+
+// typedef __success(return >= 0) LONG NTSTATUS;
+
+// __success(expr) T f() : indicates whether function f succeeded or
+// not. If is true at exit, all the function's guarantees (as given
+// by other annotations) must hold. If is false at exit, the caller
+// should not expect any of the function's guarantees to hold. If not used,
+// the function must always satisfy its guarantees. Added automatically to
+// functions that indicate success in standard ways, such as by returning an
+// HRESULT.
+
+using ntstatus_ = long_;
+
+// finally what we want
+// this is equivalent to typedef syntax
+
+using funptr_NtSetTimerResolution = ntstatus_ (__stdcall *)(ulong_, boolean_, ulong_*);
+
+// RAII wrapper
+
class OTR_COMPAT_EXPORT timer_resolution final
{
- unsigned long old_value;
+ ulong_ old_value;
public:
timer_resolution(int msecs);
~timer_resolution();
};
+
+}
+
+using timer_impl::timer_resolution;
+
#else
struct timer_resolution final
{
diff --git a/compat/timer.cpp b/compat/timer.cpp
index d5052ccb..3ecdf528 100644
--- a/compat/timer.cpp
+++ b/compat/timer.cpp
@@ -7,6 +7,7 @@
*/
#include "timer.hpp"
+#include <cmath>
Timer::Timer()
{
@@ -15,17 +16,20 @@ Timer::Timer()
void Timer::start()
{
- wrap_gettime(&state);
+ gettime(&state);
}
// common
-void Timer::wrap_gettime(timespec* state)
+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
- (void) clock_gettime(CLOCK_MONOTONIC, state);
+# error "timer query method not known"
#endif
}
@@ -33,14 +37,13 @@ void Timer::wrap_gettime(timespec* state)
long long Timer::elapsed_nsecs() const
{
- struct timespec cur = {};
- wrap_gettime(&cur);
+ timespec cur{};
+ gettime(&cur);
return conv_nsecs(cur);
}
long long Timer::conv_nsecs(const timespec& cur) const
{
- // this can and will overflow
return (cur.tv_sec - state.tv_sec) * 1000000000LL + (cur.tv_nsec - state.tv_nsec);
}
@@ -48,8 +51,8 @@ long long Timer::conv_nsecs(const timespec& cur) const
double Timer::elapsed_usecs() const
{
- struct timespec cur = {};
- wrap_gettime(&cur);
+ timespec cur{};
+ gettime(&cur);
const long long nsecs = conv_nsecs(cur);
return nsecs * 1e-3;
}
@@ -73,27 +76,26 @@ double Timer::elapsed_seconds() const
#if defined _WIN32
LARGE_INTEGER Timer::otr_get_clock_frequency()
{
- LARGE_INTEGER freq = {};
+ LARGE_INTEGER freq{};
(void) QueryPerformanceFrequency(&freq);
return freq;
}
void Timer::otr_clock_gettime(timespec* ts)
{
- static LARGE_INTEGER freq = otr_get_clock_frequency();
+ static const LARGE_INTEGER freq = otr_get_clock_frequency();
LARGE_INTEGER d;
(void) QueryPerformanceCounter(&d);
using ll = long long;
- using ld = long double;
- const long long part = ll(d.QuadPart / ld(freq.QuadPart) * 1000000000.L);
+ 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 / 1000000000LL);
- ts->tv_nsec = t_ns(part % 1000000000LL);
+ ts->tv_sec = t_s(part / 1000000000);
+ ts->tv_nsec = t_ns(part % 1000000000);
}
#elif defined __MACH__
@@ -106,7 +108,7 @@ mach_timebase_info_data_t Timer::otr_get_mach_frequency()
double Timer::otr_clock_gettime(timespec* ts)
{
- static mach_timebase_info_data_t timebase_info = otr_get_mach_frequency();
+ 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;
diff --git a/compat/timer.hpp b/compat/timer.hpp
index e9efba79..58e1c7d6 100644
--- a/compat/timer.hpp
+++ b/compat/timer.hpp
@@ -20,7 +20,9 @@
#include <ctime>
#include <tuple>
-class OTR_COMPAT_EXPORT Timer
+#include "time.hpp"
+
+class OTR_COMPAT_EXPORT Timer final
{
struct timespec state;
long long conv_nsecs(const struct timespec& cur) const;
@@ -31,16 +33,22 @@ class OTR_COMPAT_EXPORT Timer
static mach_timebase_info_data_t otr_get_mach_frequency();
#endif
- static void wrap_gettime(struct timespec* state);
+ 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 static_cast<const t&>(ns(elapsed_nsecs()));
+ }
+
long long elapsed_nsecs() const;
double elapsed_usecs() const;
double elapsed_ms() const;
double elapsed_seconds() const;
};
-
-
diff --git a/compat/util.hpp b/compat/util.hpp
index b904978b..823b83d1 100644
--- a/compat/util.hpp
+++ b/compat/util.hpp
@@ -3,6 +3,7 @@
#include "ndebug-guard.hpp"
#include "run-in-thread.hpp"
#include "meta.hpp"
+#include "functional.hpp"
#include <memory>
#include <cmath>
@@ -12,10 +13,14 @@
#include <QDebug>
#define progn(...) ([&]() { __VA_ARGS__ }())
+#define prog1(x, ...) (([&]() { auto _ret1324 = (x); do { __VA_ARGS__; } while (0); return _ret1324; })())
#define once_only(...) progn(static bool once = false; if (!once) { once = true; __VA_ARGS__; })
-
-#define load_time_value(x) progn(static const auto _value132((x)); return _value132;)
+#define load_time_value(x) \
+ progn( \
+ static const auto _value132((x)); \
+ return static_cast<decltype(_value132)&>(value132); \
+ )
template<typename t> using mem = std::shared_ptr<t>;
template<typename t> using ptr = std::unique_ptr<t>;
@@ -40,20 +45,34 @@ template<typename t> using ptr = std::unique_ptr<t>;
# define unused_on_unix(t, i) t i
#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
+
template<typename t>
-int iround(const t& val)
+inline int iround(const t& val)
{
return int(std::round(val));
}
+template<typename t>
+inline unsigned uround(const t& val)
+{
+ return std::round(std::fmax(t(0), val));
+}
+
namespace util_detail {
template<typename n>
inline auto clamp_(n val, n min, n max) -> n
{
- if (val > max)
+ if (unlikely(val > max))
return max;
- if (val < min)
+ if (unlikely(val < min))
return min;
return val;
}
@@ -61,9 +80,9 @@ inline auto clamp_(n val, n min, n max) -> n
}
template<typename t, typename u, typename w>
-inline auto clamp(const t& val, const u& min, const w& max) -> decltype(val * min * max)
+inline auto clamp(const t& val, const u& min, const w& max) -> decltype(val + min + max)
{
- return ::util_detail::clamp_<decltype(val * min * max)>(val, min, max);
+ return ::util_detail::clamp_<decltype(val + min + max)>(val, min, max);
}
template<typename t, typename... xs>