Revision control
Copy as Markdown
// Copyright (C) 2020 The Qt Company Ltd.
// Copyright (C) 2021 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
#ifndef QOFFSETSTRINGARRAY_P_H
#define QOFFSETSTRINGARRAY_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "private/qglobal_p.h"
#include <QByteArrayView>
#include <QtCore/q20algorithm.h>
#include <array>
#include <limits>
#include <string_view>
class tst_QOffsetStringArray;
QT_BEGIN_NAMESPACE
QT_WARNING_PUSH
#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1100
// we usually don't overread, but GCC has a false positive
QT_WARNING_DISABLE_GCC("-Wstringop-overread")
#endif
template <typename StaticString, typename OffsetList, int LongestElement>
class QOffsetStringArray
{
static auto viewType_helper()
{
// returning std::type_identity here to avoid having to #include
if constexpr (sizeof(Char) == 2) {
return q20::type_identity<QStringView>();
#ifdef __cpp_char8_t
} else if constexpr (std::is_same_v<Char, char8_t>) {
return q20::type_identity<QUtf8StringView>();
#endif
} else {
return q20::type_identity<QByteArrayView>();
}
}
public:
using Char = typename StaticString::value_type;
using View = typename decltype(viewType_helper())::type;
static constexpr typename OffsetList::value_type MaxElementLength = LongestElement;
constexpr QOffsetStringArray(const StaticString &string, const OffsetList &offsets)
: m_string(string), m_offsets(offsets)
{}
constexpr const Char *operator[](const int index) const noexcept
{
return m_string.data() + m_offsets[qBound(int(0), index, count())];
}
constexpr const Char *at(const int index) const noexcept
{
return m_string.data() + m_offsets[index];
}
constexpr View viewAt(qsizetype index) const noexcept
{
return { m_string.data() + m_offsets[index],
qsizetype(m_offsets[index + 1]) - qsizetype(m_offsets[index]) - 1 };
}
constexpr int count() const { return int(m_offsets.size()) - 1; }
bool contains(View needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{
for (qsizetype i = 0; i < count(); ++i) {
if (viewAt(i).compare(needle, cs) == 0)
return true;
}
return false;
}
private:
StaticString m_string;
OffsetList m_offsets;
friend tst_QOffsetStringArray;
};
namespace QtPrivate {
template <size_t Highest> constexpr auto minifyValue()
{
constexpr size_t max8 = (std::numeric_limits<quint8>::max)();
constexpr size_t max16 = (std::numeric_limits<quint16>::max)();
if constexpr (Highest <= max8) {
return quint8(Highest);
} else if constexpr (Highest <= max16) {
return quint16(Highest);
} else {
// int is probably enough for everyone
return int(Highest);
}
}
template <typename Char, int... Nx>
constexpr auto makeOffsetStringArray(const Char (&...entries)[Nx])
{
constexpr int LongestElement = std::max({ Nx... }) - 1;
constexpr size_t StringLength = (Nx + ...);
using OffsetType = decltype(QtPrivate::minifyValue<StringLength>());
// prepend the first offset (zero) pointing to the *start* of the first element
size_t offset = 0;
std::array offsetList = {
OffsetType(0),
OffsetType(offset += Nx)...
};
// append an extra null terminator
std::array<Char, StringLength + 1> staticString = {};
const Char *strings[] = { entries... };
for (size_t i = 0; i < std::size(strings); ++i) {
size_t length = offsetList[i + 1] - offsetList[i];
q20::copy_n(strings[i], length, staticString.begin() + offsetList[i]);
}
using StaticString = decltype(staticString);
using OffsetList = decltype(offsetList);
using R = QOffsetStringArray<StaticString, OffsetList, LongestElement>;
return R(staticString, offsetList);
}
} // namespace QtPrivate
template<typename Char, int ... Nx>
#ifdef __cpp_concepts
requires std::is_same_v<Char, char> || std::is_same_v<Char, char16_t>
# ifdef __cpp_char8_t
|| std::is_same_v<Char, char8_t>
# endif
#endif
constexpr auto qOffsetStringArray(const Char (&...strings)[Nx]) noexcept
{
return QtPrivate::makeOffsetStringArray<Char>(strings...);
}
QT_WARNING_POP
QT_END_NAMESPACE
#endif // QOFFSETSTRINGARRAY_P_H