Qx v0.7.2
Qt Extensions Library
Loading...
Searching...
No Matches
qx-fixedstringlist.h
1#ifndef QX_FIXEDSTRINGLIST_H
2#define QX_FIXEDSTRINGLIST_H
3
4// Qt Includes
5#include <QChar>
6#include <QLatin1StringView>
7#include <QString>
8#include <QStringList>
9#include <QStringView>
10
11// Intra-component Includes
12#include "qx/core/qx-fixedlist.h"
13
14// Extra-component Includes
16
18namespace _QxPrivate
19{
20
21/* Used by the deduction guide: anything a QLatin1StringView can be made from (i.e. a 'char' literal)
22 * results in a QLatin1StringView, everything else (char16_t literals, QString, QStringView) a QStringView.
23 */
24template<typename T>
25using string_view_for_t = std::conditional_t<std::constructible_from<QLatin1StringView, T>, QLatin1StringView, QStringView>;
26
27}
29
30namespace Qx
31{
32
33template<typename ViewT, size_t N>
35class FixedStringList : public FixedList<ViewT, N>
36{
37//-Aliases----------------------------------------------------------------------------------------------------------
38private:
39 using Base = FixedList<ViewT, N>;
40
41//-Constructor----------------------------------------------------------------------------------------------------------
42public:
43 constexpr FixedStringList() = default;
44
45 template<size_t M>
46 requires (M == N)
47 constexpr FixedStringList(const ViewT (&arr)[M]) : Base(arr) {}
48
49 /* These are templated so that a braced list, which can't deduce A or B, is never a candidate for them. Otherwise
50 * they are ambiguous with the C array constructor, as the items need a user-defined conversion to the view type.
51 */
52 template<typename A>
53 requires std::same_as<std::remove_cvref_t<A>, std::array<ViewT, N>>
54 constexpr FixedStringList(A&& arr) : Base(std::forward<A>(arr)) {}
55
56 template<typename B>
57 requires std::same_as<std::remove_cvref_t<B>, Base>
58 constexpr explicit FixedStringList(B&& base) : Base(std::forward<B>(base)) {}
59
60 // Takes literals (or views) directly, e.g. {u"string1", u"string2"} or {"string1", "string2"}
61 template<typename... Args>
62 requires (N > 0 && sizeof...(Args) == N && (std::constructible_from<ViewT, Args> && ...))
63 constexpr FixedStringList(Args&&... args) noexcept :
64 Base(std::array<ViewT, N>{ ViewT(std::forward<Args>(args))... })
65 {}
66
67//-Class Functions--------------------------------------------------------------------------------------------------
68private:
69 template<size_t M>
70 static constexpr FixedStringList<ViewT, M> wrap(const FixedList<ViewT, M>& list) { return FixedStringList<ViewT, M>(list); }
71
72//-Instance Functions----------------------------------------------------------------------------------------------------
73private:
74 template<typename S>
75 qsizetype indexOfImpl(const S& str, qsizetype from, Qt::CaseSensitivity cs) const noexcept
76 {
77 if(from < 0)
78 from = std::max(from + Base::size_v, qsizetype(0));
79
80 for(qsizetype i = from; i < Base::size_v; ++i)
81 if((*this)[i].compare(str, cs) == 0)
82 return i;
83
84 return -1;
85 }
86
87 template<typename S>
88 qsizetype lastIndexOfImpl(const S& str, qsizetype from, Qt::CaseSensitivity cs) const noexcept
89 {
90 if(from < 0)
91 from += Base::size_v;
92 else if(from >= Base::size_v)
93 from = Base::size_v - 1;
94
95 for(qsizetype i = from; i >= 0; --i)
96 if((*this)[i].compare(str, cs) == 0)
97 return i;
98
99 return -1;
100 }
101
102 template<typename S>
103 QString joinImpl(const S& separator, qsizetype separatorSize) const
104 {
105 qsizetype total = 0;
106 for(const ViewT& item : *this)
107 total += item.size();
108 if constexpr(N > 1)
109 total += separatorSize * static_cast<qsizetype>(N - 1);
110
111 QString result;
112 result.reserve(total);
113
114 bool first = true;
115 for(const ViewT& item : *this)
116 {
117 if(!first)
118 result.append(separator);
119 first = false;
120 result.append(item);
121 }
122
123 return result;
124 }
125
126public:
127 /* Inherited accessors that would otherwise be hidden by the sub-list versions below. These brings in all of them, and we then
128 * shadow only the ones we need to below.
129 */
130 using Base::first; // For the `ViewT& first()` form
131 using Base::last; // For the `ViewT& last()` form
132
133 bool contains(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return indexOfImpl(str, 0, cs) != -1; }
134 bool contains(QLatin1StringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return indexOfImpl(str, 0, cs) != -1; }
135
136 qsizetype indexOf(QStringView str, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return indexOfImpl(str, from, cs); }
137 qsizetype indexOf(QLatin1StringView str, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return indexOfImpl(str, from, cs); }
138
139 qsizetype lastIndexOf(QStringView str, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return lastIndexOfImpl(str, from, cs); }
140 qsizetype lastIndexOf(QLatin1StringView str, qsizetype from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept { return lastIndexOfImpl(str, from, cs); }
141
142 /* TODO:
143 * If the C++ standard and Qt ever add enough functionality to compile time plumbing to allow this,
144 * it would be great if join() could be constexpr itself (since this class and all join param types
145 * are constexpr) and produce a QStringView or QLatin1String. This way, still at compile time one
146 * could do:
147 *
148 * static constexpr Qx::FixedStringList LIST = {u"Hello", u"World"};
149 * static constexpr QStringView STR = LIST.join(u" "); // STR = u"Hello World";
150 *
151 * C++26's std::define_static_string might make this possible.
152 */
153 QString join(QStringView separator) const { return joinImpl(separator, separator.size()); }
154 QString join(QLatin1StringView separator) const { return joinImpl(separator, separator.size()); }
155 QString join(QChar separator) const { return joinImpl(separator, 1); }
156
157 QStringList toStringList() const
158 {
159 QStringList list;
160 list.reserve(N);
161 for(const ViewT& item : *this)
162 list.append(item.toString());
163 return list;
164 }
165
166 // Sub-lists (re-declared so that they produce a FixedStringList instead of a FixedList)
167 template<qsizetype K>
168 constexpr auto first() const { return wrap(Base::template first<K>()); }
169
170 template<qsizetype K>
171 constexpr auto last() const { return wrap(Base::template last<K>()); }
172
181 template<qsizetype Pos, qsizetype K>
182 constexpr auto sliced() const { return wrap(Base::template sliced<Pos, K>()); }
183
192 template<qsizetype Pos>
193 constexpr auto sliced() const { return wrap(Base::template sliced<Pos>()); }
194
195 template<qsizetype K>
196 constexpr auto chopped() const { return wrap(Base::template chopped<K>()); }
197
198 template<qsizetype Pos, qsizetype Len = -1>
199 constexpr auto mid() const { return wrap(Base::template mid<Pos, Len>()); }
200
201 // Concatenation
202 template<size_t M>
203 constexpr FixedStringList<ViewT, N + M> operator+(const FixedStringList<ViewT, M>& other) const { return wrap(Base::operator+(other)); }
204
205 template<size_t M>
206 constexpr FixedStringList<ViewT, N + M> operator+(const ViewT (&other)[M]) const { return wrap(Base::operator+(other)); }
207
208 // Anything a ViewT can be constructed from (including explicitly, i.e. a char literal for a QLatin1StringView)
209 template<typename L>
210 requires std::constructible_from<ViewT, L>
211 constexpr FixedStringList<ViewT, N + 1> operator+(L&& other) const { return wrap(Base::operator+(ViewT(std::forward<L>(other)))); }
212};
213
214//-Deduction Guides-------------------------------------------------------------------------------------------------
216// char16_t literals (and QStrings/QStringViews) -> QStringView, char literals (and QLatin1StringViews) -> QLatin1StringView
217template<typename First, typename... Rest>
218 requires (std::constructible_from<_QxPrivate::string_view_for_t<First>, First> &&
219 (std::constructible_from<_QxPrivate::string_view_for_t<First>, Rest> && ...))
220FixedStringList(First&&, Rest&&...) -> FixedStringList<_QxPrivate::string_view_for_t<First>, 1 + sizeof...(Rest)>;
222
223//-Aliases----------------------------------------------------------------------------------------------------------
224/* TODO: These have the same problem as the would-be aliases in StringLiteral, which is that Clang didn't introduce
225 * CTAD for template aliases until Clang 19, which is not yet common place. This makes using these aliases straight-up
226 * worse than just sing FixedStringList since that can deduce the types anyway. Unlike with StringLiteral, temporarily
227 * implementing these as derived classes would be even more involved so I've deemed it not worth it.
228 *
229 * Instead we just gate these behind compilers that support them an note that in the documentation. This check is
230 * technically overly coarse in that it also requires CTAD for aggregates, P1816R0 (which we don't need here), but every
231 * compiler that matters has implemented that before P1814R0 so this check works anyway.
232 */
233#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201907L || defined(DOXYGEN)
234template<size_t N>
236
237template<size_t N>
239#endif
240
241//-Operators--------------------------------------------------------------------------------------------------------
247template<typename ViewT, size_t M, size_t N>
249{
250 return FixedStringList<ViewT, M + N>(a + static_cast<const FixedList<ViewT, N>&>(b));
251}
252
258template<typename L, typename ViewT, size_t N>
259 requires std::constructible_from<ViewT, L>
261{
262 return FixedStringList<ViewT, 1 + N>(ViewT(std::forward<L>(a)) + static_cast<const FixedList<ViewT, N>&>(b));
263}
264
265}
266
267// Tuple-like interface (structured bindings)
269namespace std
270{
271
272template<typename ViewT, size_t N>
273struct tuple_size<Qx::FixedStringList<ViewT, N>> : std::integral_constant<size_t, N> {};
274
275template<size_t I, typename ViewT, size_t N>
276struct tuple_element<I, Qx::FixedStringList<ViewT, N>>
277{
278 static_assert(I < N);
279 using type = ViewT;
280};
281
282}
284
285#endif // QX_FIXEDSTRINGLIST_H
constexpr FixedList()=default
constexpr reference first()
Definition qx-fixedlist.h:168
constexpr reference last()
Definition qx-fixedlist.h:174
static constexpr qsizetype size_v
Definition qx-fixedlist.h:47
The FixedStringList template class is a FixedList with a few added convenience functions for handling...
Definition qx-fixedstringlist.h:36
bool contains(QStringView str, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qx-fixedstringlist.h:133
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qx-fixedstringlist.h:134
constexpr FixedStringList(Args &&... args) noexcept
Definition qx-fixedstringlist.h:63
constexpr auto first() const
Definition qx-fixedstringlist.h:168
constexpr auto last() const
Definition qx-fixedstringlist.h:171
qsizetype lastIndexOf(QStringView str, qsizetype from=-1, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qx-fixedstringlist.h:139
constexpr auto sliced() const
Definition qx-fixedstringlist.h:193
constexpr FixedStringList< ViewT, N+M > operator+(const FixedStringList< ViewT, M > &other) const
Definition qx-fixedstringlist.h:203
qsizetype indexOf(QStringView str, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qx-fixedstringlist.h:136
QString join(QStringView separator) const
Definition qx-fixedstringlist.h:153
constexpr auto mid() const
Definition qx-fixedstringlist.h:199
QString join(QLatin1StringView separator) const
Definition qx-fixedstringlist.h:154
constexpr auto chopped() const
Definition qx-fixedstringlist.h:196
constexpr FixedStringList(B &&base)
Definition qx-fixedstringlist.h:58
constexpr FixedStringList()=default
constexpr FixedStringList< ViewT, 1+N > operator+(L &&a, const FixedStringList< ViewT, N > &b)
Definition qx-fixedstringlist.h:260
constexpr auto sliced() const
Definition qx-fixedstringlist.h:182
constexpr FixedStringList< ViewT, M+N > operator+(const ViewT(&a)[M], const FixedStringList< ViewT, N > &b)
Definition qx-fixedstringlist.h:248
constexpr FixedStringList(A &&arr)
Definition qx-fixedstringlist.h:54
QStringList toStringList() const
Definition qx-fixedstringlist.h:157
QString join(QChar separator) const
Definition qx-fixedstringlist.h:155
constexpr FixedStringList< ViewT, N+M > operator+(const ViewT(&other)[M]) const
Definition qx-fixedstringlist.h:206
constexpr FixedStringList(const ViewT(&arr)[M])
Definition qx-fixedstringlist.h:47
constexpr FixedStringList< ViewT, N+1 > operator+(L &&other) const
Definition qx-fixedstringlist.h:211
qsizetype lastIndexOf(QLatin1StringView str, qsizetype from=-1, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qx-fixedstringlist.h:140
qsizetype indexOf(QLatin1StringView str, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qx-fixedstringlist.h:137
Specifies that a type is one of several types.
Definition qx-concepts.h:509
FixedStringList< QLatin1StringView, N > Latin1StringViewList
Definition qx-fixedstringlist.h:238
FixedStringList< QStringView, N > StringViewList
Definition qx-fixedstringlist.h:235
The Qx namespace is the main namespace through which all non-global functionality of the Qx library i...
Definition qx-abstracterror.cpp:13
@ First
Definition qx-global.h:19
The qx-concepts header file provides a library of general purpose concepts as an extension of the sta...