1 | // Copyright (C) 2020 The Qt Company Ltd. |
2 | // Copyright (C) 2021 Intel Corporation. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #ifndef QOFFSETSTRINGARRAY_P_H |
6 | #define QOFFSETSTRINGARRAY_P_H |
7 | |
8 | // |
9 | // W A R N I N G |
10 | // ------------- |
11 | // |
12 | // This file is not part of the Qt API. It exists purely as an |
13 | // implementation detail. This header file may change from version to |
14 | // version without notice, or even be removed. |
15 | // |
16 | // We mean it. |
17 | // |
18 | |
19 | #include "private/qglobal_p.h" |
20 | |
21 | #include <QByteArrayView> |
22 | |
23 | #include <QtCore/q20algorithm.h> |
24 | #include <array> |
25 | #include <limits> |
26 | #include <string_view> |
27 | #include <tuple> |
28 | |
29 | class tst_QOffsetStringArray; |
30 | |
31 | QT_BEGIN_NAMESPACE |
32 | |
33 | QT_WARNING_PUSH |
34 | #if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1100 |
35 | // we usually don't overread, but GCC has a false positive |
36 | QT_WARNING_DISABLE_GCC("-Wstringop-overread" ) |
37 | #endif |
38 | |
39 | |
40 | template <typename StaticString, typename OffsetList> |
41 | class QOffsetStringArray |
42 | { |
43 | public: |
44 | constexpr QOffsetStringArray(const StaticString &string, const OffsetList &offsets) |
45 | : m_string(string), m_offsets(offsets) |
46 | {} |
47 | |
48 | constexpr const char *operator[](const int index) const noexcept |
49 | { |
50 | return m_string.data() + m_offsets[qBound(int(0), index, count())]; |
51 | } |
52 | |
53 | constexpr const char *at(const int index) const noexcept |
54 | { |
55 | return m_string.data() + m_offsets[index]; |
56 | } |
57 | |
58 | constexpr QByteArrayView viewAt(qsizetype index) const noexcept |
59 | { |
60 | return { m_string.data() + m_offsets[index], |
61 | qsizetype(m_offsets[index + 1]) - qsizetype(m_offsets[index]) - 1 }; |
62 | } |
63 | |
64 | constexpr int count() const { return int(m_offsets.size()) - 1; } |
65 | |
66 | bool contains(QByteArrayView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept |
67 | { |
68 | for (qsizetype i = 0; i < count(); ++i) { |
69 | if (viewAt(index: i).compare(needle, cs) == 0) |
70 | return true; |
71 | } |
72 | return false; |
73 | } |
74 | |
75 | private: |
76 | StaticString m_string; |
77 | OffsetList m_offsets; |
78 | friend tst_QOffsetStringArray; |
79 | }; |
80 | |
81 | namespace QtPrivate { |
82 | template <size_t Highest> constexpr auto minifyValue() |
83 | { |
84 | constexpr size_t max8 = (std::numeric_limits<quint8>::max)(); |
85 | constexpr size_t max16 = (std::numeric_limits<quint16>::max)(); |
86 | if constexpr (Highest <= max8) { |
87 | return quint8(Highest); |
88 | } else if constexpr (Highest <= max16) { |
89 | return quint16(Highest); |
90 | } else { |
91 | // int is probably enough for everyone |
92 | return int(Highest); |
93 | } |
94 | } |
95 | |
96 | template <size_t StringLength, typename Extractor, typename... T> |
97 | constexpr auto makeStaticString(Extractor , const T &... entries) |
98 | { |
99 | std::array<char, StringLength> result = {}; |
100 | qptrdiff offset = 0; |
101 | |
102 | const char *strings[] = { extract(entries).operator const char *()... }; |
103 | size_t lengths[] = { sizeof(extract(T{}))... }; |
104 | for (size_t i = 0; i < std::size(strings); ++i) { |
105 | q20::copy_n(strings[i], lengths[i], result.begin() + offset); |
106 | offset += lengths[i]; |
107 | } |
108 | return result; |
109 | } |
110 | |
111 | template <size_t N> struct StaticString |
112 | { |
113 | char value[N] = {}; |
114 | constexpr StaticString() = default; |
115 | constexpr StaticString(const char (&s)[N]) { q20::copy_n(s, N, value); } |
116 | constexpr operator const char *() const { return value; } |
117 | }; |
118 | |
119 | template <size_t KL, size_t VL> struct StaticMapEntry |
120 | { |
121 | StaticString<KL> key = {}; |
122 | StaticString<VL> value = {}; |
123 | constexpr StaticMapEntry() = default; |
124 | constexpr StaticMapEntry(const char (&k)[KL], const char (&v)[VL]) |
125 | : key(k), value(v) |
126 | {} |
127 | }; |
128 | |
129 | template <typename StringExtractor, typename... T> |
130 | constexpr auto makeOffsetStringArray(StringExtractor , const T &... entries) |
131 | { |
132 | constexpr size_t Count = sizeof...(T); |
133 | constexpr size_t StringLength = (sizeof(extractString(T{})) + ...); |
134 | using MinifiedOffsetType = decltype(QtPrivate::minifyValue<StringLength>()); |
135 | |
136 | size_t offset = 0; |
137 | std::array fullOffsetList = { offset += sizeof(extractString(T{}))... }; |
138 | |
139 | // prepend zero |
140 | std::array<MinifiedOffsetType, Count + 1> minifiedOffsetList = {}; |
141 | q20::transform(fullOffsetList.begin(), fullOffsetList.end(), |
142 | minifiedOffsetList.begin() + 1, |
143 | [] (auto e) { return MinifiedOffsetType(e); }); |
144 | |
145 | std::array staticString = QtPrivate::makeStaticString<StringLength>(extractString, entries...); |
146 | return QOffsetStringArray(staticString, minifiedOffsetList); |
147 | } |
148 | } // namespace QtPrivate |
149 | |
150 | template<int ... Nx> |
151 | constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept |
152 | { |
153 | auto = [](const auto &s) -> decltype(auto) { return s; }; |
154 | return QtPrivate::makeOffsetStringArray(extractString, QtPrivate::StaticString(strings)...); |
155 | } |
156 | |
157 | QT_WARNING_POP |
158 | QT_END_NAMESPACE |
159 | |
160 | #endif // QOFFSETSTRINGARRAY_P_H |
161 | |