1 /*
2  * DQt - D bindings for the Qt Toolkit
3  *
4  * GNU Lesser General Public License Usage
5  * This file may be used under the terms of the GNU Lesser
6  * General Public License version 3 as published by the Free Software
7  * Foundation and appearing in the file LICENSE.LGPL3 included in the
8  * packaging of this file. Please review the following information to
9  * ensure the GNU Lesser General Public License version 3 requirements
10  * will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
11  */
12 module qt.core.bytearrayview;
13 extern(C++):
14 
15 import qt.config;
16 import qt.core.bytearray;
17 import qt.core.global;
18 import qt.core.namespace;
19 import qt.core.typeinfo;
20 import qt.helpers;
21 
22 
23 extern(C++, "QtPrivate") {
24 
25 struct IsCompatibleByteTypeHelper(Byte)
26  {
27     /+ std:: +/integral_constant!(bool,
28                                  /+ std:: +/is_same_v!(Byte, char) ||
29                                  /+ std:: +/is_same_v!(Byte, uchar) ||
30                                  /+ std:: +/is_same_v!(Byte, byte) ||
31                                  /+ std:: +/is_same_v!(Byte, /+ std:: +/byte_)) base0;
32     alias base0 this;
33 }
34 
35 struct IsCompatibleByteType(Byte)
36  {
37     IsCompatibleByteTypeHelper!(
38                   /+ std:: +/remove_cv_t!(/+ std:: +/remove_reference_t!(Byte))) base0;
39     alias base0 this;
40 }
41 
42 struct IsCompatibleByteArrayPointerHelper(Pointer) {
43     /+ std:: +/false_type base0;
44     alias base0 this;
45 }
46 /+ template <typename Byte>
47 struct IsCompatibleByteArrayPointerHelper<Byte *>
48     : IsCompatibleByteType<Byte> {}; +/
49 struct IsCompatibleByteArrayPointer(Pointer)
50  {
51     IsCompatibleByteArrayPointerHelper!(
52                   /+ std:: +/remove_cv_t!(/+ std:: +/remove_reference_t!(Pointer))) base0;
53     alias base0 this;
54 }
55 
56 struct IsContainerCompatibleWithQByteArrayView(T, Enable) {
57     /+ std:: +/false_type base0;
58     alias base0 this;
59 }
60 
61 /+ template <typename T>
62 struct IsContainerCompatibleWithQByteArrayView<T, std::enable_if_t<
63         std::conjunction_v<
64                 // lacking concepts and ranges, we accept any T whose std::data yields a suitable
65                 // pointer ...
66                 IsCompatibleByteArrayPointer<decltype(std::data(std::declval<const T &>()))>,
67                 // ... and that has a suitable size ...
68                 std::is_convertible<decltype(std::size(std::declval<const T &>())), qsizetype>,
69                 // ... and it's a range as it defines an iterator-like API
70                 IsCompatibleByteType<typename std::iterator_traits<decltype(
71                         std::begin(std::declval<const T &>()))>::value_type>,
72                 std::is_convertible<decltype(std::begin(std::declval<const T &>())
73                                              != std::end(std::declval<const T &>())),
74                                     bool>,
75 
76                 // This needs to be treated specially due to the empty vs null distinction
77                 std::negation<std::is_same<std::decay_t<T>, QByteArray>>,
78 
79                 // We handle array literals specially for source compat reasons
80                 std::negation<std::is_array<T>>,
81 
82                 // Don't make an accidental copy constructor
83                 std::negation<std::is_same<std::decay_t<T>, QByteArrayView>>>>> : std::true_type {}; +/
84 
85 } // namespace QtPrivate
86 
87 /// Binding for C++ class [QByteArrayView](https://doc.qt.io/qt-6/qbytearrayview.html).
88 @Q_PRIMITIVE_TYPE extern(C++, class) struct /+ Q_CORE_EXPORT +/ QByteArrayView
89 {
90 public:
91     alias storage_type = char;
92     alias value_type = const(char);
93     alias difference_type = qptrdiff;
94     alias size_type = qsizetype;
95     /+ typedef value_type &reference; +/
96     /+ typedef value_type &const_reference; +/
97     alias pointer = value_type*;
98     alias const_pointer = value_type*;
99 
100     alias iterator = pointer;
101     alias const_iterator = const_pointer;
102     /+ typedef std::reverse_iterator<iterator> reverse_iterator; +/
103     /+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator; +/
104 
105 private:
106     /+ template <typename Byte> +/
107     alias if_compatible_byte(Byte) =
108                 /+ std:: +/enable_if_t!(/+ QtPrivate:: +/IsCompatibleByteType!(Byte).value, bool);
109 
110     /+ template <typename Pointer> +/
111     /+ using if_compatible_pointer =
112             typename std::enable_if_t<QtPrivate::IsCompatibleByteArrayPointer<Pointer>::value,
113                                       bool>; +/
114 
115     /+ template <typename T> +/
116     alias if_compatible_qbytearray_like(T) =
117                 /+ std:: +/enable_if_t!(bool, bool);
118 
119     /+ template <typename T> +/
120     alias if_compatible_container(T) =
121                 /+ std:: +/enable_if_t!(/+ QtPrivate:: +/IsContainerCompatibleWithQByteArrayView!(T).value,
122                                           bool);
123 
124     /+ template <typename Char> +/
125     /+ static constexpr qsizetype lengthHelperPointer(const Char *data) noexcept
126     {
127         return qsizetype(std::char_traits<Char>::length(data));
128     } +/
129 
130     /+ template <typename Container> +/
131     static qsizetype lengthHelperContainer(Container)(ref const(Container) c)/+ noexcept+/
132     {
133         return qsizetype(/+ std:: +/size(c));
134     }
135 
136     /+static qsizetype lengthHelperCharArray(const(char)* data, size_t size)/+ noexcept+/
137     {
138         const it = /+ std:: +/char_traits!(char).find(cast(const(char_traits.char_type)*)(data), size, '\0');
139         const end = it ? it : /+ std:: +/next(data, size);
140         return qsizetype(/+ std:: +/distance(data, end));
141     }+/
142 
143     /+ template <typename Byte> +/
144     static const(storage_type)* castHelper(Byte)(const(Byte)* data)/+ noexcept+/
145     { return reinterpret_cast!(const(storage_type)*)(data); }
146     static const(storage_type)* castHelper(const(storage_type)* data)/+ noexcept+/
147     { return data; }
148 
149 public:
150     //@disable this();
151     /+this()/+ noexcept+/
152     {
153         this.m_size = 0;
154         this.m_data = null;
155     }+/
156     this(typeof(null))/+ noexcept+/
157     {
158         //this();
159     }
160 
161     /+ template <typename Byte, if_compatible_byte<Byte> = true> +/
162     this(Byte,)(const(Byte)* data, qsizetype len)
163     {
164         this.m_size = ((){(){ (mixin(Q_ASSERT(q{len >= 0})));
165         return /+ Q_ASSERT(data || !len) +/ mixin(Q_ASSERT(q{data || !len}));
166         }();
167         return len;
168         }());
169         this.m_data = castHelper(data);
170     }
171 
172     /+ template <typename Byte, if_compatible_byte<Byte> = true> +/
173     this(Byte,)(const(Byte)* first, const(Byte)* last)
174     {
175         this(first, last - first);
176     }
177 
178 /+ #ifdef Q_QDOC
179     template <typename Byte>
180     constexpr QByteArrayView(const Byte *data) noexcept;
181 #else +/
182     /+ template <typename Pointer, if_compatible_pointer<Pointer> = true> +/
183     this(Pointer)(ref const(Pointer) data)/+ noexcept+/ if(is(Pointer: const(char)*))
184     {
185         import core.stdc.string: strlen;
186         this(
187                       data, data ? strlen(data) : 0);
188     }
189 /+ #endif
190 
191 #ifdef Q_QDOC
192     QByteArrayView(const QByteArray &data) noexcept;
193 #else +/
194     /+ template <typename ByteArray, if_compatible_qbytearray_like<ByteArray> = true> +/
195     this(ByteArray)(ref const(ByteArray) ba)/+ noexcept+/ if(is(ByteArray == QByteArray))
196     {
197         this(ba.isNull() ? null : ba.data(), qsizetype(ba.size()));
198     }
199 /+ #endif +/
200 
201     /+ template <typename Container, if_compatible_container<Container> = true> +/
202     /+this(Container,)(ref const(Container) c)/+ noexcept+/
203     {
204         this(/+ std:: +/data(c), lengthHelperContainer(c));
205     }+/
206     /+ template <size_t Size> +/
207     /+this(size_t Size)(ref const(char)[Size] data)/+ noexcept+/
208     {
209         this(data, lengthHelperCharArray(data.ptr, Size));
210     }+/
211 
212 /+ #ifdef Q_QDOC
213     template <typename Byte, size_t Size>
214 #else +/
215     /+ template <typename Byte, size_t Size, if_compatible_byte<Byte> = true>
216 #endif +/
217     /+ [[nodiscard]] +/ static QByteArrayView fromArray(Byte,size_t Size,)(ref const(Byte)[Size] data)/+ noexcept+/
218     { return QByteArrayView(data.ptr, Size); }
219     //
220     // QByteArrayView members that require QByteArray:
221     //
222     /+ [[nodiscard]] +/ pragma(inline, true) QByteArray toByteArray() const
223     {
224         return QByteArray(data(), size());
225     } // defined in qbytearray.h
226 
227     /+ [[nodiscard]] +/ qsizetype size() const/+ noexcept+/ { return m_size; }
228     /+ [[nodiscard]] +/ const_pointer data() const/+ noexcept+/ { return m_data; }
229     /+ [[nodiscard]] +/ const_pointer constData() const/+ noexcept+/ { return data(); }
230 
231     /+ [[nodiscard]] +/ char opIndex(qsizetype n) const
232     { (mixin(Q_ASSERT(q{n >= 0}))); (mixin(Q_ASSERT(q{n < QByteArrayView.size()}))); return m_data[n]; }
233 
234     //
235     // QByteArray API
236     //
237     /+ [[nodiscard]] +/ char at(qsizetype n) const { return (this)[n]; }
238 
239     /+ [[nodiscard]] +/ QByteArrayView first(qsizetype n) const
240     { (mixin(Q_ASSERT(q{n >= 0}))); (mixin(Q_ASSERT(q{n <= QByteArrayView.size()}))); return QByteArrayView(data(), n); }
241     /+ [[nodiscard]] +/ QByteArrayView last(qsizetype n) const
242     { (mixin(Q_ASSERT(q{n >= 0}))); (mixin(Q_ASSERT(q{n <= QByteArrayView.size()}))); return QByteArrayView(data() + size() - n, n); }
243     /+ [[nodiscard]] +/ QByteArrayView sliced(qsizetype pos) const
244     { (mixin(Q_ASSERT(q{pos >= 0}))); (mixin(Q_ASSERT(q{pos <= QByteArrayView.size()}))); return QByteArrayView(data() + pos, size() - pos); }
245     /+ [[nodiscard]] +/ QByteArrayView sliced(qsizetype pos, qsizetype n) const
246     { (mixin(Q_ASSERT(q{pos >= 0}))); (mixin(Q_ASSERT(q{n >= 0}))); (mixin(Q_ASSERT(q{size_t(pos) + size_t(n) <= size_t(QByteArrayView.size())}))); return QByteArrayView(data() + pos, n); }
247     /+ [[nodiscard]] +/ QByteArrayView chopped(qsizetype len) const
248     { (mixin(Q_ASSERT(q{len >= 0}))); (mixin(Q_ASSERT(q{len <= QByteArrayView.size()}))); return first(size() - len); }
249 
250     void truncate(qsizetype n)
251     { (mixin(Q_ASSERT(q{n >= 0}))); (mixin(Q_ASSERT(q{n <= QByteArrayView.size()}))); m_size = n; }
252     void chop(qsizetype n)
253     { (mixin(Q_ASSERT(q{n >= 0}))); (mixin(Q_ASSERT(q{n <= QByteArrayView.size()}))); m_size -= n; }
254 
255     /+ [[nodiscard]] +/ bool startsWith(QByteArrayView other) const/+ noexcept+/
256     {
257         import qt.core.bytearrayalgorithms;
258         return /+ QtPrivate:: +/qt.core.bytearrayalgorithms.startsWith(this, other);
259     }
260     /+ [[nodiscard]] +/ bool startsWith(char c) const/+ noexcept+/
261     { return !empty() && front() == c; }
262 
263     /+ [[nodiscard]] +/ bool endsWith(QByteArrayView other) const/+ noexcept+/
264     {
265         import qt.core.bytearrayalgorithms;
266         return /+ QtPrivate:: +/qt.core.bytearrayalgorithms.endsWith(this, other);
267     }
268     /+ [[nodiscard]] +/ bool endsWith(char c) const/+ noexcept+/
269     { return !empty() && back() == c; }
270 
271     /+ [[nodiscard]] +/ qsizetype indexOf(QByteArrayView a, qsizetype from = 0) const/+ noexcept+/
272     {
273         import qt.core.bytearrayalgorithms;
274         return /+ QtPrivate:: +/qt.core.bytearrayalgorithms.findByteArray(this, from, a);
275     }
276     /+ [[nodiscard]] +/ qsizetype indexOf(char ch, qsizetype from = 0) const/+ noexcept+/
277     {
278         import qt.core.bytearrayalgorithms;
279         return /+ QtPrivate:: +/qt.core.bytearrayalgorithms.findByteArray(this, from, QByteArrayView(&ch, 1));
280     }
281 
282     /+ [[nodiscard]] +/ bool contains(QByteArrayView a) const/+ noexcept+/
283     { return indexOf(a) != qsizetype(-1); }
284     /+ [[nodiscard]] +/ bool contains(char c) const/+ noexcept+/
285     { return indexOf(c) != qsizetype(-1); }
286 
287     /+ [[nodiscard]] +/ qsizetype lastIndexOf(QByteArrayView a) const/+ noexcept+/
288     { return lastIndexOf(a, size()); }
289     /+ [[nodiscard]] +/ qsizetype lastIndexOf(QByteArrayView a, qsizetype from) const/+ noexcept+/
290     {
291         import qt.core.bytearrayalgorithms;
292         return /+ QtPrivate:: +/qt.core.bytearrayalgorithms.lastIndexOf(this, from, a);
293     }
294     /+ [[nodiscard]] +/ qsizetype lastIndexOf(char ch, qsizetype from = -1) const/+ noexcept+/
295     {
296         import qt.core.bytearrayalgorithms;
297         return /+ QtPrivate:: +/qt.core.bytearrayalgorithms.lastIndexOf(this, from, QByteArrayView(&ch, 1));
298     }
299 
300     /+ [[nodiscard]] +/ qsizetype count(QByteArrayView a) const/+ noexcept+/
301     {
302         import qt.core.bytearrayalgorithms;
303         return /+ QtPrivate:: +/qt.core.bytearrayalgorithms.count(this, a);
304     }
305     /+ [[nodiscard]] +/ qsizetype count(char ch) const/+ noexcept+/
306     {
307         import qt.core.bytearrayalgorithms;
308         return /+ QtPrivate:: +/qt.core.bytearrayalgorithms.count(this, QByteArrayView(&ch, 1));
309     }
310 
311     pragma(inline, true) int compare(QByteArrayView a, /+ Qt:: +/qt.core.namespace.CaseSensitivity cs = /+ Qt:: +/qt.core.namespace.CaseSensitivity.CaseSensitive) const/+ noexcept+/
312     {
313         import qt.core.bytearrayalgorithms;
314 
315         return cs == /+ Qt:: +/qt.core.namespace.CaseSensitivity.CaseSensitive ? /+ QtPrivate:: +/qt.core.bytearrayalgorithms.compareMemory(this, a) :
316                                          qstrnicmp(data(), size(), a.data(), a.size());
317     }
318 
319     //
320     // STL compatibility API:
321     //
322     /+ [[nodiscard]] +/ const_iterator begin()   const/+ noexcept+/ { return data(); }
323     /+ [[nodiscard]] +/ const_iterator end()     const/+ noexcept+/ { return data() + size(); }
324     /+ [[nodiscard]] +/ const_iterator cbegin()  const/+ noexcept+/ { return begin(); }
325     /+ [[nodiscard]] +/ const_iterator cend()    const/+ noexcept+/ { return end(); }
326     /+ [[nodiscard]] constexpr const_reverse_iterator rbegin()  const noexcept { return const_reverse_iterator(end()); } +/
327     /+ [[nodiscard]] constexpr const_reverse_iterator rend()    const noexcept { return const_reverse_iterator(begin()); } +/
328     /+ [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } +/
329     /+ [[nodiscard]] constexpr const_reverse_iterator crend()   const noexcept { return rend(); } +/
330 
331     /+ [[nodiscard]] +/ bool empty() const/+ noexcept+/ { return size() == 0; }
332     /+ [[nodiscard]] +/ char front() const { (mixin(Q_ASSERT(q{!QByteArrayView.empty()}))); return m_data[0]; }
333     /+ [[nodiscard]] +/ char back()  const { (mixin(Q_ASSERT(q{!QByteArrayView.empty()}))); return m_data[m_size - 1]; }
334 
335     //
336     // Qt compatibility API:
337     //
338     /+ [[nodiscard]] +/ bool isNull() const/+ noexcept+/ { return !m_data; }
339     /+ [[nodiscard]] +/ bool isEmpty() const/+ noexcept+/ { return empty(); }
340     /+ [[nodiscard]] +/ qsizetype length() const/+ noexcept+/
341     { return size(); }
342     /+ [[nodiscard]] +/ char first() const { return front(); }
343     /+ [[nodiscard]] +/ char last()  const { return back(); }
344 
345     /+ friend inline bool operator==(QByteArrayView lhs, QByteArrayView rhs) noexcept
346     { return lhs.size() == rhs.size() && QtPrivate::compareMemory(lhs, rhs) == 0; } +/
347     /+ friend inline bool operator!=(QByteArrayView lhs, QByteArrayView rhs) noexcept
348     { return !(lhs == rhs); } +/
349     /+ friend inline bool operator< (QByteArrayView lhs, QByteArrayView rhs) noexcept
350     { return QtPrivate::compareMemory(lhs, rhs) <  0; } +/
351     /+ friend inline bool operator<=(QByteArrayView lhs, QByteArrayView rhs) noexcept
352     { return QtPrivate::compareMemory(lhs, rhs) <= 0; } +/
353     /+ friend inline bool operator> (QByteArrayView lhs, QByteArrayView rhs) noexcept
354     { return !(lhs <= rhs); } +/
355     /+ friend inline bool operator>=(QByteArrayView lhs, QByteArrayView rhs) noexcept
356     { return !(lhs < rhs); } +/
357 
358 private:
359     qsizetype m_size = 0;
360     const(storage_type)* m_data = null;
361     mixin(CREATE_CONVENIENCE_WRAPPERS);
362 }
363 /+ Q_DECLARE_TYPEINFO(QByteArrayView, Q_PRIMITIVE_TYPE); +/
364 
365 /+ [[nodiscard]] +/ pragma(inline, true) QByteArrayView qToByteArrayViewIgnoringNull(QByteArrayLike,
366          /+ std::enable_if_t<std::is_same_v<QByteArrayLike, QByteArray>, bool> +/ /+ = true +/)(ref const(QByteArrayLike) b)/+ noexcept+/
367 { return QByteArrayView(b.data(), b.size()); }
368 
369 /+ #if QT_DEPRECATED_SINCE(6, 0) +/
370 /+ QT_DEPRECATED_VERSION_X_6_0("Use the QByteArrayView overload.") +/
371 pragma(inline, true) quint16 qChecksum(const(char)* s, qsizetype len,
372                          /+ Qt:: +/qt.core.namespace.ChecksumType standard = /+ Qt:: +/qt.core.namespace.ChecksumType.ChecksumIso3309)
373 {
374     import qt.core.bytearrayalgorithms;
375     return qt.core.bytearrayalgorithms.qChecksum(QByteArrayView(s, len), standard);
376 }
377 /+ #endif +/
378