Skip to content

Commit

Permalink
feat: Arbitrary Qt formatstring support for ScopedTimer
Browse files Browse the repository at this point in the history
  • Loading branch information
Swiftb0y committed May 20, 2024
1 parent 7e2d085 commit 8691c46
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,7 @@ target_precompile_headers(mixxx-lib PUBLIC
src/track/tracknumbers.h
src/track/trackrecord.h
src/track/trackref.h
src/util/always_false.h
src/util/alphabetafilter.h
src/util/battery/battery.h
src/util/cache.h
Expand Down Expand Up @@ -1445,6 +1446,7 @@ target_precompile_headers(mixxx-lib PUBLIC
src/util/path.h
src/util/performancetimer.h
src/util/platform.h
src/util/qstringformat.h
src/util/qt.h
src/util/quuid.h
src/util/rampingvalue.h
Expand Down
5 changes: 5 additions & 0 deletions src/util/always_false.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once
// always false, used for static_assert and workaround for compilers without
// https://cplusplus.github.io/CWG/issues/2518.html
template<typename T>
static constexpr bool always_false_v = false;

Check failure on line 5 in src/util/always_false.h

View workflow job for this annotation

GitHub Actions / Windows 2019 (MSVC)

'always_false_v': variable template has already been initialized
39 changes: 39 additions & 0 deletions src/util/qstringformat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once

#include <QString>
#include <type_traits>
#include <utility>

#include "util/always_false.h"

namespace {

// taken from Qt
template<typename T>
static constexpr bool is_convertible_to_view_or_qstring_v =
std::is_convertible_v<T, QString> ||
std::is_convertible_v<T, QStringView> ||
std::is_convertible_v<T, QLatin1String>;

// check if we can call QString::number(T) with T
template<typename T>
static constexpr bool is_number_compatible_v =
std::is_invocable_v<decltype(QString::number(std::declval<T>()))(T), T>;
} // namespace

// Try to convert T to a type that would be accepted by QString::args(Args&&...)
template<typename T>
auto convertToQStringConvertible(T&& arg) {
if constexpr (is_convertible_to_view_or_qstring_v<T>) {
// no need to do anything, just return verbatim
return std::forward<T>(arg);
} else if constexpr (is_number_compatible_v<T>) {
return QString::number(std::forward<T>(arg));
} else {
static_assert(always_false_v<T>, "Unsupported type for QString::arg");
// unreachable, but returning a QString results in a better error message
// because the log won't be spammed with all the QString::arg overloads
// it couldn't match with `void`.
return QString();
}
}
49 changes: 27 additions & 22 deletions src/util/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,40 +39,45 @@ class Timer {
// TODO: replace with std::experimental::scope_exit<Timer> once stabilized
class ScopedTimer {
public:
ScopedTimer(QStringView key,
Stat::ComputeFlags compute = kDefaultComputeFlags)
: ScopedTimer(key, QStringView(), compute) {
}
ScopedTimer(QStringView key,
int i,
Stat::ComputeFlags compute = kDefaultComputeFlags)
: ScopedTimer(key,
CmdlineArgs::Instance().getDeveloper()
? QString::number(i)
: QStringView(),
compute) {
}

ScopedTimer(QStringView key, QStringView arg, Stat::ComputeFlags compute = kDefaultComputeFlags)
// Allows the timer to contain a format string which is only assembled
// when we're not in `--developer` mode.
/// @param compute Flags to use for the Stat::ComputeFlags (can be omitted)
/// @param key The format string as QStringLiteral to identify the timer
/// @param args The arguments to pass to the format string
template<typename T, typename... Ts>
ScopedTimer(Stat::ComputeFlags compute, T&& key, Ts&&... args)
: m_maybeTimer(std::nullopt) {
static_assert(std::is_same_v<T, QString>,
"only QString is supported as key type. Wrap it in u\"\""
"_s or QStringLiteral() "
"to avoid runtime UTF-16 conversion.");
if (!CmdlineArgs::Instance().getDeveloper()) {
return;
return; // leave timer in cancelled state
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QString strKey = arg.isEmpty() ? key.toString() : key.arg(arg);
#else
QString strKey = arg.isEmpty() ? key.toString() : key.toString().arg(arg);
#endif
m_maybeTimer = std::make_optional<Timer>(std::move(strKey), compute);
//
auto assembledKey = QString(std::forward<T>(key));
// ensure the string was indeed a literal an not unnecessarily heap-allocated
DEBUG_ASSERT(assembledKey.capacity() == 0);
if constexpr (sizeof...(args) > 0) {
// only try to call QString::arg when we've been given parameters
assembledKey = assembledKey.arg(convertToQStringConvertible(std::forward<Ts>(args))...);

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / Ubuntu 22.04

‘convertToQStringConvertible’ was not declared in this scope

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / Ubuntu 22.04

‘convertToQStringConvertible’ was not declared in this scope

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / clazy

use of undeclared identifier 'convertToQStringConvertible'

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / clazy

use of undeclared identifier 'convertToQStringConvertible'

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / clazy

use of undeclared identifier 'convertToQStringConvertible'

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / macOS 11 x64

use of undeclared identifier 'convertToQStringConvertible'

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / macOS 11 x64

use of undeclared identifier 'convertToQStringConvertible'

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / macOS 11 arm64

use of undeclared identifier 'convertToQStringConvertible'

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / coverage

‘convertToQStringConvertible’ was not declared in this scope

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / coverage

‘convertToQStringConvertible’ was not declared in this scope

Check failure on line 63 in src/util/timer.h

View workflow job for this annotation

GitHub Actions / coverage

‘convertToQStringConvertible’ was not declared in this scope
}
m_maybeTimer = std::make_optional<Timer>(assembledKey, compute);
m_maybeTimer->start();
}

template<typename T, typename... Ts>
ScopedTimer(T&& key, Ts&&... args)
: ScopedTimer(kDefaultComputeFlags, std::forward<T>(key), std::forward<Ts>(args)...) {
}

~ScopedTimer() noexcept {
if (m_maybeTimer) {
m_maybeTimer->elapsed(true);
}
}

// copying would technically be possible, but likely not intended
ScopedTimer(const ScopedTimer&) = delete;
ScopedTimer& operator=(const ScopedTimer&) = delete;

Expand Down

0 comments on commit 8691c46

Please sign in to comment.