diff options
3 files changed, 105 insertions, 129 deletions
diff --git a/src/corelib/tools/qoffsetstringarray_p.h b/src/corelib/tools/qoffsetstringarray_p.h index a5d54546ea..6e0cb1f30b 100644 --- a/src/corelib/tools/qoffsetstringarray_p.h +++ b/src/corelib/tools/qoffsetstringarray_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -53,152 +54,122 @@ #include "private/qglobal_p.h" -#include <tuple> #include <array> #include <limits> +#include <string> +#include <tuple> -QT_BEGIN_NAMESPACE - -namespace QtPrivate { -template<int N, int O, int I, int ... Idx> -struct OffsetSequenceHelper : OffsetSequenceHelper<N - 1, O + I, Idx..., O> { }; +class tst_QOffsetStringArray; -template<int Last, int I, int S, int ... Idx> -struct OffsetSequenceHelper<1, Last, I, S, Idx...> : IndexesList<Last + I, Idx..., Last> -{ - // the unary + before std::numeric_limits below is required. Otherwise we get on g++-10.2: - // error: comparison is always false due to limited range of data type [-Werror=type-limits] - static const constexpr auto Length = Last + I; - using Type = typename std::conditional< - Last <= +std::numeric_limits<quint8>::max(), - quint8, - typename std::conditional< - Last <= std::numeric_limits<quint16>::max(), - quint16, - int>::type - >::type; -}; +QT_BEGIN_NAMESPACE -template<int ... Idx> -struct OffsetSequence : OffsetSequenceHelper<sizeof ... (Idx), 0, Idx..., 0> { }; -template<int N> -struct StaticString +template <typename StaticString, typename OffsetList> +class QOffsetStringArray { - const char data[N]; -}; - +public: + constexpr QOffsetStringArray(const StaticString &string, const OffsetList &offsets) + : m_string(string), m_offsets(offsets) + {} -template<> -struct StaticString<0> -{ - static constexpr int size() noexcept + constexpr const char *operator[](const int index) const noexcept { - return 0; + return m_string.data() + m_offsets[qBound(int(0), index, count() - 1)]; } -}; - -template<typename, typename> -struct StaticStringBuilder; -template<int ... I1, int ... I2> -struct StaticStringBuilder<IndexesList<I1...>, IndexesList<I2...>> -{ - -QT_WARNING_PUSH -QT_WARNING_DISABLE_MSVC(4100) // The formal parameter is not referenced in the body of the function. - // The unreferenced parameter is ignored. - // It happens when 'rs' is StaticString<0> - template<int N1, int N2> - static constexpr StaticString<N1 + N2> concatenate( - const char (&ls)[N1], const StaticString<N2> &rs) noexcept + constexpr const char *at(const int index) const noexcept { - return StaticString<N1 + N2>{{ls[I1]..., rs.data[I2]...}}; + return m_string.data() + m_offsets[index]; } -QT_WARNING_POP + + constexpr int count() const { return int(m_offsets.size()); } + +private: + StaticString m_string; + OffsetList m_offsets; + friend tst_QOffsetStringArray; }; -template<int Sum> -constexpr StaticString<0> staticString() noexcept +namespace QtPrivate { +// std::copy is not constexpr in C++17 +template <typename II, typename OO> +static constexpr OO copyData(II input, qsizetype n, OO output) { - return StaticString<0>{}; + using E = decltype(+*output); + for (qsizetype i = 0; i < n; ++i) + output[i] = E(input[i]); + return output + n; } -QT_WARNING_PUSH -QT_WARNING_DISABLE_MSVC(4503) -template<int Sum, int I, int ... Ix> -constexpr StaticString<Sum> staticString(const char (&s)[I], const char (&...sx)[Ix]) noexcept +template <size_t Highest> constexpr auto minifyValue() { - return StaticStringBuilder< - makeIndexSequence<I>, - makeIndexSequence<Sum - I>>::concatenate(s, staticString<Sum - I>(sx...)); -} -QT_WARNING_POP -} // namespace QtPrivate - -QT_WARNING_PUSH -#if defined(Q_CC_GNU) && __GNUC__ == 9 -QT_WARNING_DISABLE_GCC("-Wstringop-overflow") -#endif -template<typename T, int SizeString, int SizeOffsets> -class QOffsetStringArray -{ -public: - using Type = T; - - template<int ... Ox> - constexpr QOffsetStringArray(const QtPrivate::StaticString<SizeString> &str, - QtPrivate::IndexesList<SizeString, Ox...>) noexcept - : m_string(str), - m_offsets{Ox...} - { } - - constexpr inline const char *operator[](const int index) const noexcept - { - return m_string.data + m_offsets[qBound(int(0), index, SizeOffsets - 1)]; + if constexpr (Highest <= std::numeric_limits<quint8>::max()) { + return quint8(Highest); + } else if constexpr (Highest <= std::numeric_limits<quint16>::max()) { + return quint16(Highest); + } else { + // int is probably enough for everyone + return int(Highest); } +} - constexpr inline const char *at(const int index) const noexcept - { - return m_string.data + m_offsets[index]; +template <size_t StringLength, typename Extractor, typename... T> +constexpr auto makeStaticString(Extractor extract, const T &... entries) +{ + std::array<char, StringLength> result = {}; + qptrdiff offset = 0; + + const char *strings[] = { extract(entries).operator const char *()... }; + size_t lengths[] = { sizeof(extract(T{}))... }; + for (size_t i = 0; i < std::size(strings); ++i) { + copyData(strings[i], lengths[i], result.begin() + offset); + offset += lengths[i]; } + return result; +} - constexpr inline const char *str() const { return m_string.data; } - constexpr inline const T *offsets() const { return m_offsets; } - constexpr inline int count() const { return SizeOffsets; } - - static constexpr const auto sizeString = SizeString; - static constexpr const auto sizeOffsets = SizeOffsets; - -private: - QtPrivate::StaticString<SizeString> m_string; - const T m_offsets[SizeOffsets]; +template <size_t N> struct StaticString +{ + char value[N] = {}; + constexpr StaticString() = default; + constexpr StaticString(const char (&s)[N]) { copyData(s, N, value); } + constexpr operator const char *() const { return value; } }; -QT_WARNING_POP -template<typename T, int N, int ... Ox> -constexpr QOffsetStringArray<T, N, sizeof ... (Ox)> qOffsetStringArray( - const QtPrivate::StaticString<N> &string, - QtPrivate::IndexesList<N, Ox...> offsets) noexcept +template <size_t KL, size_t VL> struct StaticMapEntry { - return QOffsetStringArray<T, N, sizeof ... (Ox)>( - string, - offsets); -} + StaticString<KL> key = {}; + StaticString<VL> value = {}; + constexpr StaticMapEntry() = default; + constexpr StaticMapEntry(const char (&k)[KL], const char (&v)[VL]) + : key(k), value(v) + {} +}; -template<int ... Nx> -struct QOffsetStringArrayRet +template <typename StringExtractor, typename... T> +constexpr auto qOffsetStringArray(StringExtractor extractString, const T &... entries) { - using Offsets = QtPrivate::OffsetSequence<Nx...>; - using Type = QOffsetStringArray<typename Offsets::Type, Offsets::Length, sizeof ... (Nx)>; -}; + constexpr size_t Count = sizeof...(T); + constexpr qsizetype StringLength = (sizeof(extractString(T{})) + ...); + using MinifiedOffsetType = decltype(QtPrivate::minifyValue<StringLength>()); + + size_t offset = 0; + std::array fullOffsetList = { offset += sizeof(extractString(T{}))... }; + + // prepend zero, drop last element + std::array<MinifiedOffsetType, Count> minifiedOffsetList = {}; + QtPrivate::copyData(fullOffsetList.begin(), Count - 1, minifiedOffsetList.begin() + 1); + + std::array staticString = QtPrivate::makeStaticString<StringLength>(extractString, entries...); + return QOffsetStringArray(staticString, minifiedOffsetList); +} +} template<int ... Nx> -constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept -> typename QOffsetStringArrayRet<Nx...>::Type +constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept { - using Offsets = QtPrivate::OffsetSequence<Nx...>; - return qOffsetStringArray<typename Offsets::Type>( - QtPrivate::staticString<Offsets::Length>(strings...), Offsets{}); + auto extractString = [](const auto &s) -> decltype(auto) { return s; }; + return QtPrivate::qOffsetStringArray(extractString, QtPrivate::StaticString(strings)...); } QT_END_NAMESPACE diff --git a/tests/auto/corelib/tools/qoffsetstringarray/CMakeLists.txt b/tests/auto/corelib/tools/qoffsetstringarray/CMakeLists.txt index 7584d580ec..67dffe0284 100644 --- a/tests/auto/corelib/tools/qoffsetstringarray/CMakeLists.txt +++ b/tests/auto/corelib/tools/qoffsetstringarray/CMakeLists.txt @@ -10,3 +10,10 @@ qt_internal_add_test(tst_qoffsetstringarray PUBLIC_LIBRARIES Qt::CorePrivate ) + +if (CLANG) + target_compile_options(tst_qoffsetstringarray + PUBLIC -fbracket-depth=512) +elseif (GCC) + # fconstexpr-depth= defaults to 512 +endif() diff --git a/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp b/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp index 9445366efc..0130939b4e 100644 --- a/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp +++ b/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp @@ -90,19 +90,17 @@ constexpr const auto messagesBigOffsets = qOffsetStringArray( void tst_QOffsetStringArray::init() { - static_assert(messages.sizeString == 51, "message.sizeString"); - static_assert(messages.sizeOffsets == 6, "message.sizeOffsets"); - static_assert(std::is_same<decltype(messages)::Type, quint8>::value, "messages::Type != quint8"); - - static_assert(messages257.sizeOffsets == 257, "messages257.sizeOffsets"); - static_assert(messages257.sizeString == 260, "messages257.sizeString"); - static_assert(std::is_same<decltype(messages257)::Type, quint16>::value, - "messages257::Type != quint16"); - - static_assert(messagesBigOffsets.sizeOffsets == 4, "messagesBigOffsets.sizeOffsets"); - static_assert(messagesBigOffsets.sizeString == 364, "messagesBigOffsets.sizeString"); - static_assert(std::is_same<decltype(messagesBigOffsets)::Type, quint16>::value, - "messagesBigOffsets::Type != quint16"); + static_assert(messages.m_string.size() == 51); + static_assert(messages.m_offsets.size() == 6); + static_assert(std::is_same_v<decltype(messages.m_offsets)::value_type, quint8>); + + static_assert(messages257.m_offsets.size() == 257); + static_assert(messages257.m_string.size() == 260); + static_assert(std::is_same_v<decltype(messages257.m_offsets)::value_type, quint16>); + + static_assert(messagesBigOffsets.m_offsets.size() == 4); + static_assert(messagesBigOffsets.m_string.size() == 364); + static_assert(std::is_same_v<decltype(messagesBigOffsets.m_offsets)::value_type, quint16>); } void tst_QOffsetStringArray::access() |