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