corelib/tools: Add QOffsetStringArray API

This function allows to generate an array of offsets of substrings in
a string at compile time. This produces less verbose and easier to maintain
source code.

Change-Id: I5774b8b91906f6191f2b1244a676c07e7eb15b47
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Mikhail Svetkin 2018-07-26 14:35:15 +02:00
parent 2cdbe29ef0
commit f0066cae8f
5 changed files with 328 additions and 0 deletions

View File

@ -0,0 +1,211 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#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 <tuple>
#include <array>
QT_BEGIN_NAMESPACE
namespace QtPrivate {
template<int N, int O, int I, int ... Idx>
struct OffsetSequenceHelper : OffsetSequenceHelper<N - 1, O + I, Idx..., O> { };
template<int O, int I, int ... Idx>
struct OffsetSequenceHelper<0, O, I, Idx...> : IndexesList<O, Idx...>
{
static const constexpr auto Length = O;
};
template<int I, int ... Idx>
struct OffsetSequence : OffsetSequenceHelper<sizeof ... (Idx) + 1, 0, I, Idx..., 0>
{
static const constexpr auto Count = sizeof ... (Idx) + 1;
using Type = typename QConditional<
Count <= std::numeric_limits<quint8>::max() + 1,
quint8,
typename QConditional<
Count <= std::numeric_limits<quint16>::max() + 1,
quint16,
int>::Type
>::Type;
};
template<int N>
struct StaticString
{
const char data[N];
constexpr StaticString(const char (&literal)[N]) noexcept
: StaticString(literal, makeIndexSequence<N> {})
{ }
template<int ... Idx>
constexpr StaticString(const char (&literal)[N],
IndexesList<Idx...>) noexcept
: data{literal[Idx]...}
{ }
template<typename ... T>
constexpr StaticString(const T ... c) noexcept : data{c...} { }
constexpr char operator[](int i) const noexcept
{
return data[i];
}
template<int N2>
constexpr StaticString<N + N2> operator+(const StaticString<N2> &rs) const noexcept
{
return concatenate(rs, makeIndexSequence<N>{}, makeIndexSequence<N2>{});
}
template<int N2, int ... I1, int ... I2>
constexpr StaticString<N + N2> concatenate(const StaticString<N2> &rs,
IndexesList<I1...>,
IndexesList<I2...>) const noexcept
{
return StaticString<N + N2>(data[I1]..., rs[I2]...);
}
constexpr int size() const noexcept
{
return N;
}
};
template<>
struct StaticString<0>
{
};
template<int Sum>
constexpr StaticString<0> staticString() noexcept
{
return StaticString<0>{};
}
template<int Sum, int I, int ... Ix>
constexpr StaticString<Sum> staticString(const char (&s)[I], const char (&...sx)[Ix]) noexcept
{
return StaticString<I>(s) + staticString<Sum - I>(sx...);
}
} // namespace QtPrivate
template<typename T, int SizeString, int SizeOffsets>
class QOffsetStringArray
{
public:
using Type = T;
template<int ... Cx, int ... Ox>
constexpr QOffsetStringArray(const QtPrivate::StaticString<SizeString> &str,
QtPrivate::IndexesList<Cx...>,
QtPrivate::IndexesList<SizeString, Ox...>) noexcept
: m_string{str[Cx]...},
m_offsets{Ox...}
{ }
constexpr inline const char *operator[](const int index) const noexcept
{
return m_string + m_offsets[qBound(int(0), index, SizeOffsets - 1)];
}
constexpr inline const char *at(const int index) const noexcept
{
return m_string + m_offsets[index];
}
constexpr inline const char *str() const { return m_string; }
constexpr inline const int *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:
const char m_string[SizeString];
const T m_offsets[SizeOffsets];
};
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
{
return QOffsetStringArray<T, N, sizeof ... (Ox)>(
string,
QtPrivate::makeIndexSequence<N> {},
offsets);
}
template<int ... Nx>
struct QOffsetStringArrayRet
{
using Offsets = QtPrivate::OffsetSequence<Nx...>;
using Type = QOffsetStringArray<typename Offsets::Type, Offsets::Length, sizeof ... (Nx)>;
};
template<int ... Nx>
constexpr auto qOffsetStringArray(const char (&...strings)[Nx]) noexcept -> typename QOffsetStringArrayRet<Nx...>::Type
{
using Offsets = QtPrivate::OffsetSequence<Nx...>;
return qOffsetStringArray<typename Offsets::Type>(
QtPrivate::staticString<Offsets::Length>(strings...), Offsets{});
}
QT_END_NAMESPACE
#endif // QOFFSETSTRINGARRAY_P_H

View File

@ -39,6 +39,7 @@ HEADERS += \
tools/qmargins.h \
tools/qmessageauthenticationcode.h \
tools/qcontiguouscache.h \
tools/qoffsetstringarray_p.h \
tools/qpair.h \
tools/qpoint.h \
tools/qqueue.h \

View File

@ -0,0 +1,6 @@
CONFIG += testcase
TARGET = tst_qoffsetstringarray
QT = core testlib core-private
CONFIG += c++11
CONFIG += strict_c++
SOURCES = $$PWD/tst_qoffsetstringarray.cpp

View File

@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <private/qoffsetstringarray_p.h>
class tst_QOffsetStringArray : public QObject
{
Q_OBJECT
private slots:
void init();
void access();
};
constexpr const auto messages = qOffsetStringArray(
"level - 0",
"level - 1",
"level - 2",
"level - 3",
"level - 4",
""
);
constexpr const auto messages257 = qOffsetStringArray(
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "end"
);
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");
}
void tst_QOffsetStringArray::access()
{
QCOMPARE(messages[0], "level - 0");
QCOMPARE(messages[1], "level - 1");
QCOMPARE(messages[2], "level - 2");
QCOMPARE(messages[3], "level - 3");
QCOMPARE(messages[4], "level - 4");
QCOMPARE(messages[5], "");
QCOMPARE(messages[6], "");
}
QTEST_APPLESS_MAIN(tst_QOffsetStringArray)
#include "tst_qoffsetstringarray.moc"

View File

@ -35,6 +35,7 @@ SUBDIRS=\
qmap_strictiterators \
qmargins \
qmessageauthenticationcode \
qoffsetstringarray \
qpair \
qpoint \
qpointf \