Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump libfmt; enable Qt 6 build; add std::format support #29

Merged
merged 2 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions qt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ add_subdirectory(singleshot_connect)
add_subdirectory(tabWindow)
add_subdirectory(ui_watchdog)
add_subdirectory(qt6_natvis)
add_subdirectory(qt_fmt)

if(LINUX)
add_subdirectory(asan_assert_fail_qt)
Expand All @@ -26,7 +27,4 @@ endif()
if(QT_VERSION_MAJOR EQUAL 5)
# Qt6 has it's own QStringTokenizer
add_subdirectory(stringtokenizer)

# fails to build with with Qt6
add_subdirectory(qt_fmt)
endif()
8 changes: 6 additions & 2 deletions qt/qt_fmt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# This file is part of KDToolBox.
#
# SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
#
# SPDX-License-Identifier: MIT
#
include(CheckSubmoduleExists)

check_submodule_exists(fmt fmt)

add_subdirectory(test)
add_subdirectory(testfmt)

if(KDTOOLBOX_CXX20)
add_subdirectory(teststd)
endif()
2 changes: 1 addition & 1 deletion qt/qt_fmt/fmt
Submodule fmt updated 60 files
+8 −0 .github/dependabot.yml
+3 −3 .github/workflows/cifuzz.yml
+1 −1 .github/workflows/doc.yml
+26 −0 .github/workflows/lint.yml
+1 −1 .github/workflows/linux.yml
+13 −3 .github/workflows/macos.yml
+65 −0 .github/workflows/scorecard.yml
+3 −3 .github/workflows/windows.yml
+13 −26 .gitignore
+24 −12 CMakeLists.txt
+5,533 −0 ChangeLog.md
+0 −5,687 ChangeLog.rst
+0 −0 LICENSE
+490 −0 README.md
+0 −540 README.rst
+6 −6 doc/_static/bootstrap.min.js
+116 −86 doc/api.rst
+10 −5 doc/build.py
+11 −4 doc/syntax.rst
+38 −0 doc/usage.rst
+7 −6 include/fmt/args.h
+226 −253 include/fmt/chrono.h
+48 −38 include/fmt/color.h
+27 −99 include/fmt/compile.h
+328 −310 include/fmt/core.h
+93 −96 include/fmt/format-inl.h
+426 −626 include/fmt/format.h
+28 −24 include/fmt/os.h
+69 −33 include/fmt/ostream.h
+131 −135 include/fmt/printf.h
+23 −17 include/fmt/ranges.h
+250 −62 include/fmt/std.h
+32 −32 include/fmt/xchar.h
+2 −10 src/fmt.cc
+24 −12 src/os.cc
+1 −1 support/AndroidManifest.xml
+45 −19 support/manage.py
+0 −159 support/rst2md.py
+6 −1 test/CMakeLists.txt
+245 −225 test/chrono-test.cc
+1 −0 test/compile-fp-test.cc
+28 −44 test/compile-test.cc
+35 −9 test/core-test.cc
+3 −95 test/format-impl-test.cc
+498 −470 test/format-test.cc
+1 −1 test/gtest-extra-test.cc
+2 −2 test/gtest-extra.cc
+1 −1 test/gtest-extra.h
+1 −1 test/gtest/gmock-gtest-all.cc
+4 −4 test/os-test.cc
+18 −1 test/ostream-test.cc
+4 −4 test/posix-mock.h
+11 −30 test/printf-test.cc
+92 −29 test/ranges-test.cc
+103 −31 test/scan-test.cc
+559 −139 test/scan.h
+98 −13 test/std-test.cc
+6 −2 test/util.cc
+14 −12 test/util.h
+86 −38 test/xchar-test.cc
66 changes: 4 additions & 62 deletions qt/qt_fmt/qt_fmt.h
Original file line number Diff line number Diff line change
@@ -1,75 +1,17 @@
/*
This file is part of KDToolBox.

SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>

SPDX-License-Identifier: MIT
*/

#pragma once

#include <fmt/format.h>

#include <type_traits>
#include "qt_fmt_helpers.h"

#include <fmt/format.h>
#include <QDebug>
#include <QString>

namespace Qt_fmt
{
namespace detail
{

template<typename T, template<typename...> typename Primary>
struct is_specialization_of : std::false_type
{
};

template<template<typename...> typename Primary, typename... Args>
struct is_specialization_of<Primary<Args...>, Primary> : std::true_type
{
};

} // namespace detail

// Offering this as a customization point for users who might want to
// define both QDebug streaming and fmt formatters, so they need a way
// to shut down this path.
//
// Note: keeping this in sync between fmt and QDebug sounds like a
// nightmare.
// clang-format off
template<typename T, typename Enable = void>
struct exclude_from_qdebug_fmt
: std::disjunction<std::is_fundamental<T>,
// QByteArray is a thorn in the side.
// fmt handles automatically types that convert to const char *,
// but not types that convert to const void *. QByteArray by default
// converts to both; so be careful about it here.
std::conjunction<
std::is_convertible<T, const void *>,
std::negation<std::is_same<std::remove_cv_t<T>, QByteArray>>
>,
std::conjunction<
std::is_convertible<T, const char *>,
std::negation<std::is_same<std::remove_cv_t<T>, QByteArray>>
>,
// Re-include char-arrays, since the above would exclude them
std::conjunction<
std::is_array<T>,
std::is_same<std::remove_cv_t<T>, char>
>,
// fmt doesn't necessarily offer these as builtins, but let's be conservative
detail::is_specialization_of<T, std::pair>,
detail::is_specialization_of<T, std::vector>,
detail::is_specialization_of<T, std::list>,
detail::is_specialization_of<T, std::map>,
detail::is_specialization_of<T, std::multimap>>
{
};
// clang-format on

} // namespace Qt_fmt

template<typename T>
struct fmt::formatter<T, char,
Expand All @@ -86,7 +28,7 @@ struct fmt::formatter<T, char,
}

template<typename FormatContext>
auto format(const T &t, FormatContext &ctx)
auto format(const T &t, FormatContext &ctx) const
{
// This is really expensive (lots of allocations). Unfortunately
// there isn't something as easy to do that also performs better.
Expand Down
87 changes: 87 additions & 0 deletions qt/qt_fmt/qt_fmt_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
This file is part of KDToolBox.

SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>

SPDX-License-Identifier: MIT
*/

#pragma once

#include <type_traits>

#include <QDebug>
#include <QString>
#include <QByteArray>
#include <utility>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <unordered_map>
#include <unordered_set>

namespace Qt_fmt
{
namespace detail
{

template<typename T, template<typename...> typename Primary>
struct is_specialization_of : std::false_type
{
};

template<template<typename...> typename Primary, typename... Args>
struct is_specialization_of<Primary<Args...>, Primary> : std::true_type
{
};

} // namespace detail

// Offering this as a customization point for users who might want to
// define both QDebug streaming and fmt formatters, so they need a way
// to shut down this path.
//
// Note: keeping this in sync between fmt and QDebug sounds like a
// nightmare.
// clang-format off
template<typename T, typename Enable = void>
struct exclude_from_qdebug_fmt
: std::disjunction<std::is_fundamental<T>,
// QByteArray is a thorn in the side.
// fmt handles automatically types that convert to const char *,
// but not types that convert to const void *. QByteArray by default
// converts to both; so be careful about it here.
std::conjunction<
std::is_convertible<T, const void *>,
std::negation<std::is_same<std::remove_cv_t<T>, QByteArray>>
>,
std::conjunction<
std::is_convertible<T, const char *>,
std::negation<std::is_same<std::remove_cv_t<T>, QByteArray>>
>,
// Re-include char-arrays, since the above would exclude them
std::conjunction<
std::is_array<T>,
std::is_same<std::remove_cv_t<T>, char>
>,
// fmt doesn't necessarily offer these as builtins, but let's be conservative
detail::is_specialization_of<T, std::pair>,
detail::is_specialization_of<T, std::tuple>,
detail::is_specialization_of<T, std::vector>,
detail::is_specialization_of<T, std::list>,
detail::is_specialization_of<T, std::map>,
detail::is_specialization_of<T, std::multimap>,
detail::is_specialization_of<T, std::set>,
detail::is_specialization_of<T, std::multiset>,
detail::is_specialization_of<T, std::unordered_map>,
detail::is_specialization_of<T, std::unordered_set>,
detail::is_specialization_of<T, std::unordered_multimap>,
detail::is_specialization_of<T, std::unordered_multiset>
>
{
};
// clang-format on

} // namespace Qt_fmt

52 changes: 52 additions & 0 deletions qt/qt_fmt/qt_std_format.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
This file is part of KDToolBox.

SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>

SPDX-License-Identifier: MIT
*/

#pragma once

#if __cplusplus < 202002L
#error "This header requires C++20"
#endif

#include <format>
#include <QDebug>
#include "qt_fmt_helpers.h"

namespace Qt_fmt::detail
{
template<typename T>
concept IsFormattableViaQDebug = requires(QDebug &d, const T &t)
{
d << t;
requires !Qt_fmt::exclude_from_qdebug_fmt<T>::value;
};
}

template<typename T>
requires Qt_fmt::detail::IsFormattableViaQDebug<T>
struct std::formatter<T, char>
{
template<typename ParseContext>
constexpr auto parse(ParseContext &ctx)
{
auto it = ctx.begin();
auto end = ctx.end();
if (it != end && *it != '}')
throw std::format_error("Only {} is supported");
return it;
}

template<typename FormatContext>
auto format(const T &t, FormatContext &ctx) const
{
// See the comment in the libfmt formatter
QString buffer;
QDebug debug(&buffer);
debug.noquote().nospace() << t;
return std::format_to(ctx.out(), "{}", buffer.toStdString());
}
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This file is part of KDToolBox.
#
# SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
#
# SPDX-License-Identifier: MIT
#
Expand All @@ -19,7 +19,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)

include_directories(../fmt/include/)

set(test_tmp_2_SOURCES ../fmt/src/format.cc tst_qt_fmt.cpp)
set(test_qt_fmt_SOURCES ../fmt/src/format.cc tst_qt_fmt.cpp)

add_executable(test_tmp_2 ${test_tmp_2_SOURCES})
target_link_libraries(test_tmp_2 PUBLIC Qt::Core Qt::Gui Qt::Test)
add_executable(test_qt_fmt ${test_qt_fmt_SOURCES})
target_link_libraries(test_qt_fmt PUBLIC Qt::Core Qt::Gui Qt::Test)
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ struct fmt::formatter<BothFmtAndQDebugClass, char>
return it;
}
template<typename FormatContext>
auto format(const BothFmtAndQDebugClass &, FormatContext &ctx)
auto format(const BothFmtAndQDebugClass &, FormatContext &ctx) const
{
return fmt::format_to(ctx.out(), "BothFmtAndQDebugClass via fmt");
}
Expand Down
23 changes: 23 additions & 0 deletions qt/qt_fmt/teststd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This file is part of KDToolBox.
#
# SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
#
# SPDX-License-Identifier: MIT
#
find_package(
Qt${QT_VERSION_MAJOR}
${QT_REQUIRED_VERSION}
CONFIG
REQUIRED
Core
Gui
Test
)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(test_qt_std_format_SOURCES tst_qt_std_format.cpp)

add_executable(test_qt_std_format ${test_qt_std_format_SOURCES})
target_link_libraries(test_qt_std_format PUBLIC Qt::Core Qt::Gui Qt::Test)
Loading