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
29class tst_QOffsetStringArray;
30
31QT_BEGIN_NAMESPACE
32
33QT_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
36QT_WARNING_DISABLE_GCC("-Wstringop-overread")
37#endif
38
39
40template <typename StaticString, typename OffsetList>
41class QOffsetStringArray
42{
43public:
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
75private:
76 StaticString m_string;
77 OffsetList m_offsets;
78 friend tst_QOffsetStringArray;
79};
80
81namespace QtPrivate {
82template <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
96template <size_t StringLength, typename Extractor, typename... T>
97constexpr auto makeStaticString(Extractor extract, 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
111template <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
119template <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
129template <typename StringExtractor, typename... T>
130constexpr auto makeOffsetStringArray(StringExtractor extractString, 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
150template<int ... Nx>
151constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept
152{
153 auto extractString = [](const auto &s) -> decltype(auto) { return s; };
154 return QtPrivate::makeOffsetStringArray(extractString, QtPrivate::StaticString(strings)...);
155}
156
157QT_WARNING_POP
158QT_END_NAMESPACE
159
160#endif // QOFFSETSTRINGARRAY_P_H
161

source code of qtbase/src/corelib/tools/qoffsetstringarray_p.h