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.utf8stringview; 13 extern(C++): 14 15 import qt.config; 16 import qt.core.bytearray; 17 import qt.core.global; 18 import qt.core.string; 19 import qt.helpers; 20 21 22 extern(C++, "QtPrivate") { 23 /+alias IsCompatibleChar8TypeHelper(Char) = /+ std:: +/ 24 disjunction!( 25 /+ #ifdef __cpp_char8_t +/ 26 /+ std:: +/is_same!(Char, char8_t), 27 /+ #endif +/ 28 /+ std:: +/is_same!(Char, char), 29 /+ std:: +/is_same!(Char, uchar), 30 /+ std:: +/is_same!(Char, byte)); 31 alias IsCompatibleChar8Type(Char) 32 = IsCompatibleChar8TypeHelper!(/+ std:: +/remove_cv_t!(/+ std:: +/remove_reference_t!(Char))); 33 34 struct IsCompatiblePointer8Helper(Pointer) { 35 /+ std:: +/false_type base0; 36 alias base0 this; 37 } 38 /+ template <typename Char> 39 struct IsCompatiblePointer8Helper<Char*> 40 : IsCompatibleChar8Type<Char> {}; +/ 41 alias IsCompatiblePointer8(Pointer) 42 = IsCompatiblePointer8Helper!(/+ std:: +/remove_cv_t!(/+ std:: +/remove_reference_t!(Pointer))); 43 +/ 44 struct IsContainerCompatibleWithQUtf8StringView(T, Enable) { 45 /+ std:: +/false_type base0; 46 alias base0 this; 47 } 48 49 /+ template <typename T> 50 struct IsContainerCompatibleWithQUtf8StringView<T, std::enable_if_t<std::conjunction_v< 51 // lacking concepts and ranges, we accept any T whose std::data yields a suitable pointer ... 52 IsCompatiblePointer8<decltype(std::data(std::declval<const T &>()))>, 53 // ... and that has a suitable size ... 54 std::is_convertible< 55 decltype(std::size(std::declval<const T &>())), 56 qsizetype 57 >, 58 // ... and it's a range as it defines an iterator-like API 59 IsCompatibleChar8Type<typename std::iterator_traits< 60 decltype(std::begin(std::declval<const T &>()))>::value_type 61 >, 62 std::is_convertible< 63 decltype( std::begin(std::declval<const T &>()) != std::end(std::declval<const T &>()) ), 64 bool 65 >, 66 67 // This needs to be treated specially due to the empty vs null distinction 68 std::negation<std::is_same<std::decay_t<T>, QByteArray>>, 69 70 // This has a compatible value_type, but explicitly a different encoding 71 std::negation<std::is_same<std::decay_t<T>, QLatin1String>>, 72 73 // Don't make an accidental copy constructor 74 std::negation<std::disjunction< 75 std::is_same<std::decay_t<T>, QBasicUtf8StringView<true>>, 76 std::is_same<std::decay_t<T>, QBasicUtf8StringView<false>> 77 >> 78 >>> : std::true_type {}; +/ 79 80 struct hide_char8_t { 81 /+ #ifdef __cpp_char8_t +/ 82 alias type = char; 83 /+ #endif +/ 84 } 85 86 struct wrap_char { alias type = char; } 87 88 } // namespace QtPrivate 89 90 /+ #ifdef Q_CLANG_QDOC +/ 91 static if(false) 92 { 93 /+ #define QBasicUtf8StringView QUtf8StringView +/ 94 } 95 /+ #else +/ 96 /+ #endif +/ 97 extern(C++, class) struct QBasicUtf8StringView(bool UseChar8T) 98 { 99 public: 100 /+ #ifndef Q_CLANG_QDOC +/ 101 /+ alias storage_type = /+ typename std::conditional<UseChar8T, 102 QtPrivate::hide_char8_t, 103 QtPrivate::wrap_char 104 >::type::type +/UnknownType!q{};+/ 105 alias storage_type = char; 106 /+ #else 107 using storage_type = typename QtPrivate::hide_char8_t; 108 #endif +/ 109 alias value_type = const(storage_type); 110 alias difference_type = qptrdiff; 111 alias size_type = qsizetype; 112 /+ typedef value_type &reference; +/ 113 /+ typedef value_type &const_reference; +/ 114 alias pointer = value_type*; 115 alias const_pointer = value_type*; 116 117 alias iterator = pointer; 118 alias const_iterator = const_pointer; 119 /+ typedef std::reverse_iterator<iterator> reverse_iterator; +/ 120 /+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator; +/ 121 122 private: 123 /+ template <typename Char> +/ 124 /+ using if_compatible_char = std::enable_if_t<QtPrivate::IsCompatibleChar8Type<Char>::value, bool>; +/ 125 126 /+ template <typename Pointer> +/ 127 /+ using if_compatible_pointer = std::enable_if_t<QtPrivate::IsCompatiblePointer8<Pointer>::value, bool>; +/ 128 129 /+ template <typename T> +/ 130 /+ using if_compatible_qstring_like = std::enable_if_t<std::is_same_v<T, QByteArray>, bool>; +/ 131 132 /+ template <typename T> +/ 133 alias if_compatible_container(T) = /+ std:: +/enable_if_t!(/+ QtPrivate:: +/IsContainerCompatibleWithQUtf8StringView!(T).value, bool); 134 135 /+ template <typename Container> +/ 136 static qsizetype lengthHelperContainer(Container)(ref const(Container) c)/+ noexcept+/ 137 { 138 return qsizetype(/+ std:: +/size(c)); 139 } 140 141 // Note: Do not replace with std::size(const Char (&)[N]), cause the result 142 // will be of by one. 143 /+ template <typename Char, size_t N> +/ 144 static qsizetype lengthHelperContainer(Char,size_t N)(ref const(Char)[N] str)/+ noexcept+/ 145 { 146 const it = /+ std:: +/char_traits!(Char).find(str.ptr, N, Char(0)); 147 const end = it ? it : /+ std:: +/next(str, N); 148 return qsizetype(/+ std:: +/distance(str, end)); 149 } 150 151 /+ template <typename Char> +/ 152 static const(storage_type)* castHelper(Char)(const(Char)* str)/+ noexcept+/ 153 { return reinterpret_cast!(const(storage_type)*)(str); } 154 static const(storage_type)* castHelper(const(storage_type)* str)/+ noexcept+/ 155 { return str; } 156 157 public: 158 @disable this(); 159 /+this()/+ noexcept+/ 160 { 161 this.m_data = null; 162 this.m_size = 0; 163 }+/ 164 this(typeof(null))/+ noexcept+/ 165 { 166 } 167 168 /+ template <typename Char, if_compatible_char<Char> = true> +/ 169 this(Char,)(const(Char)* str, qsizetype len) 170 { 171 this.m_data = castHelper(str); 172 this.m_size = ((){(){ (mixin(Q_ASSERT(q{len >= 0}))); 173 return /+ Q_ASSERT(str || !len) +/ mixin(Q_ASSERT(q{str || !len})); 174 }(); 175 return len; 176 }()); 177 } 178 179 /+ template <typename Char, if_compatible_char<Char> = true> +/ 180 this(Char,)(const(Char)* f, const(Char)* l) 181 { 182 this(f, l - f); 183 } 184 185 /+ #ifdef Q_CLANG_QDOC 186 template <typename Char, size_t N> 187 constexpr QBasicUtf8StringView(const Char (&array)[N]) noexcept; 188 189 template <typename Char> 190 constexpr QBasicUtf8StringView(const Char *str) noexcept; 191 #else +/ 192 /+ template <typename Pointer, if_compatible_pointer<Pointer> = true> +/ 193 this(Pointer,)(ref const(Pointer) str)/+ noexcept+/ 194 { 195 this(str, 196 str ? /+ std:: +/char_traits!(/+ std:: +/remove_cv_t!(/+ std:: +/remove_pointer_t!(Pointer))).length(str) : 0); 197 } 198 /+ #endif 199 200 #ifdef Q_CLANG_QDOC 201 QBasicUtf8StringView(const QByteArray &str) noexcept; 202 #else +/ 203 /+ template <typename String, if_compatible_qstring_like<String> = true> +/ 204 this(String,)(ref const(String) str)/+ noexcept+/ 205 { 206 this(str.isNull() ? null : str.data(), qsizetype(str.size())); 207 } 208 /+ #endif +/ 209 210 /+ template <typename Container, if_compatible_container<Container> = true> +/ 211 this(Container,)(ref const(Container) c)/+ noexcept+/ 212 { 213 this(/+ std:: +/data(c), lengthHelperContainer(c)); 214 } 215 216 /+ #ifdef __cpp_char8_t +/ 217 this(QBasicUtf8StringView!(!UseChar8T) other) 218 { 219 this(other.data(), other.size()); 220 } 221 /+ #endif +/ 222 223 /+ template <typename Char, size_t Size, if_compatible_char<Char> = true> +/ 224 /+ [[nodiscard]] +/ static QBasicUtf8StringView fromArray(Char,size_t Size,)(ref const(Char)[Size] string)/+ noexcept+/ 225 { return QBasicUtf8StringView(string.ptr, Size); } 226 227 /+ [[nodiscard]] +/ pragma(inline, true) QString toString() const 228 { 229 (mixin(Q_ASSERT(q{QBasicUtf8StringView.size() == cast(int)(QBasicUtf8StringView.size())}))); 230 return QString.fromUtf8(data(), cast(int)(size())); 231 } // defined in qstring.h 232 233 /+ [[nodiscard]] +/ qsizetype size() const/+ noexcept+/ { return m_size; } 234 /+ [[nodiscard]] +/ const_pointer data() const/+ noexcept+/ { return reinterpret_cast!(const_pointer)(m_data); } 235 /+ #if defined(__cpp_char8_t) || defined(Q_CLANG_QDOC) +/ 236 /+ [[nodiscard]] +/ const(char)* utf8() const/+ noexcept+/ { return reinterpret_cast!(const(char)*)(m_data); } 237 /+ #endif +/ 238 239 /+ [[nodiscard]] +/ storage_type opIndex(qsizetype n) const 240 { return (){(){ (mixin(Q_ASSERT(q{n >= 0}))); 241 return /+ Q_ASSERT(n < size()) +/ mixin(Q_ASSERT(q{n < QBasicUtf8StringView.size()})); 242 }(); 243 return m_data[n]; 244 }(); } 245 246 // 247 // QString API 248 // 249 250 /+ [[nodiscard]] +/ storage_type at(qsizetype n) const { return (this)[n]; } 251 252 /+ /+ [[nodiscard]] +/ 253 QBasicUtf8StringView mid(qsizetype pos, qsizetype n = -1) const 254 { 255 //using namespace QtPrivate; 256 auto result = QContainerImplHelper.mid(size(), &pos, &n); 257 return result == QContainerImplHelper.Null ? QBasicUtf8StringView() : QBasicUtf8StringView(m_data + pos, n); 258 }+/ 259 /+ [[nodiscard]] +/ 260 QBasicUtf8StringView left(qsizetype n) const 261 { 262 if (size_t(n) >= size_t(size())) 263 n = size(); 264 return QBasicUtf8StringView(m_data, n); 265 } 266 /+ [[nodiscard]] +/ 267 QBasicUtf8StringView right(qsizetype n) const 268 { 269 if (size_t(n) >= size_t(size())) 270 n = size(); 271 return QBasicUtf8StringView(m_data + m_size - n, n); 272 } 273 274 /+ [[nodiscard]] +/ QBasicUtf8StringView sliced(qsizetype pos) const 275 { verify(pos); return QBasicUtf8StringView(m_data + pos, m_size - pos); } 276 /+ [[nodiscard]] +/ QBasicUtf8StringView sliced(qsizetype pos, qsizetype n) const 277 { verify(pos, n); return QBasicUtf8StringView(m_data + pos, n); } 278 /+ [[nodiscard]] +/ QBasicUtf8StringView first(qsizetype n) const 279 { verify(n); return QBasicUtf8StringView(m_data, n); } 280 /+ [[nodiscard]] +/ QBasicUtf8StringView last(qsizetype n) const 281 { verify(n); return QBasicUtf8StringView(m_data + m_size - n, n); } 282 /+ [[nodiscard]] +/ QBasicUtf8StringView chopped(qsizetype n) const 283 { verify(n); return QBasicUtf8StringView(m_data, m_size - n); } 284 285 void truncate(qsizetype n) 286 { verify(n); m_size = n; } 287 void chop(qsizetype n) 288 { verify(n); m_size -= n; } 289 290 // 291 // STL compatibility API: 292 // 293 /+ [[nodiscard]] +/ const_iterator begin() const/+ noexcept+/ { return data(); } 294 /+ [[nodiscard]] +/ const_iterator end() const/+ noexcept+/ { return data() + size(); } 295 /+ [[nodiscard]] +/ const_iterator cbegin() const/+ noexcept+/ { return begin(); } 296 /+ [[nodiscard]] +/ const_iterator cend() const/+ noexcept+/ { return end(); } 297 /+ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } +/ 298 /+ [[nodiscard]] const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } +/ 299 /+ [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return rbegin(); } +/ 300 /+ [[nodiscard]] const_reverse_iterator crend() const noexcept { return rend(); } +/ 301 302 /+ [[nodiscard]] +/ bool empty() const/+ noexcept+/ { return size() == 0; } 303 /+ [[nodiscard]] +/ storage_type front() const { return (){ (mixin(Q_ASSERT(q{!QBasicUtf8StringView.empty()}))); 304 return m_data[0]; 305 }(); } 306 /+ [[nodiscard]] +/ storage_type back() const { return (){ (mixin(Q_ASSERT(q{!QBasicUtf8StringView.empty()}))); 307 return m_data[m_size - 1]; 308 }(); } 309 310 // 311 // Qt compatibility API: 312 // 313 /+ [[nodiscard]] +/ bool isNull() const/+ noexcept+/ { return !m_data; } 314 /+ [[nodiscard]] +/ bool isEmpty() const/+ noexcept+/ { return empty(); } 315 /+ [[nodiscard]] +/ qsizetype length() const/+ noexcept+/ 316 { return size(); } 317 318 private: 319 /+ /+ [[nodiscard]] +/ pragma(inline, true) static int compare(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs)/+ noexcept+/ 320 { 321 import qt.core.stringalgorithms; 322 323 return /+ QtPrivate:: +/qt.core.stringalgorithms.compareStrings(QBasicUtf8StringView!(false)(lhs.data(),lhs.size()),QBasicUtf8StringView!(false)(rhs.data(),rhs.size())); 324 }+/ 325 326 /+ [[nodiscard]] friend inline bool operator==(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept 327 { 328 return lhs.size() == rhs.size() 329 && QtPrivate::equalStrings(QBasicUtf8StringView<false>(lhs.data(), lhs.size()), 330 QBasicUtf8StringView<false>(rhs.data(), rhs.size())); 331 } +/ 332 /+ [[nodiscard]] friend inline bool operator!=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept 333 { return !operator==(lhs, rhs); } +/ 334 335 /+ #ifdef __cpp_impl_three_way_comparison 336 [[nodiscard]] friend inline auto operator<=>(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept 337 { return QBasicUtf8StringView::compare(lhs, rhs) <=> 0; } 338 #else +/ 339 /+ [[nodiscard]] friend inline bool operator<=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept 340 { return QBasicUtf8StringView::compare(lhs, rhs) <= 0; } +/ 341 /+ [[nodiscard]] friend inline bool operator>=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept 342 { return QBasicUtf8StringView::compare(lhs, rhs) >= 0; } +/ 343 /+ [[nodiscard]] friend inline bool operator<(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept 344 { return QBasicUtf8StringView::compare(lhs, rhs) < 0; } +/ 345 /+ [[nodiscard]] friend inline bool operator>(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept 346 { return QBasicUtf8StringView::compare(lhs, rhs) > 0; } +/ 347 /+ #endif +/ 348 349 /+ Q_ALWAYS_INLINE +/ pragma(inline, true) void verify(qsizetype pos, qsizetype n = 0) const 350 { 351 (mixin(Q_ASSERT(q{pos >= 0}))); 352 (mixin(Q_ASSERT(q{pos <= QBasicUtf8StringView.size()}))); 353 (mixin(Q_ASSERT(q{n >= 0}))); 354 (mixin(Q_ASSERT(q{n <= QBasicUtf8StringView.size() - pos}))); 355 } 356 const(storage_type)* m_data = null; 357 qsizetype m_size = 0; 358 } 359 360 /+ #ifdef Q_CLANG_QDOC 361 #undef QBasicUtf8StringView 362 #else +/ 363 /+ inline +/ extern(C++,"q_no_char8_t"){ 364 /+ template <bool UseChar8T> 365 Q_DECLARE_TYPEINFO_BODY(QBasicUtf8StringView<UseChar8T>, Q_PRIMITIVE_TYPE); 366 367 // ### Qt 7: remove the non-char8_t version of QUtf8StringView 368 QT_BEGIN_NO_CHAR8_T_NAMESPACE +/ 369 //alias QUtf8StringView = QBasicUtf8StringView!(false); 370 } 371 /+ QT_END_NO_CHAR8_T_NAMESPACE +/ 372 extern(C++,"q_has_char8_t"){ 373 374 /+ QT_BEGIN_HAS_CHAR8_T_NAMESPACE +/ 375 alias QUtf8StringView = QBasicUtf8StringView!(true); 376 } 377 /+ QT_END_HAS_CHAR8_T_NAMESPACE +/ 378 /+ #endif +/ // Q_CLANG_QDOC 379 380 /+ [[nodiscard]] +/ pragma(inline, true) /+ q_no_char8_t:: +/QUtf8StringView qToUtf8StringViewIgnoringNull(QStringLike, /+ std::enable_if_t<std::is_same_v<QStringLike, QByteArray>, bool> +/ /+ = true +/)(ref const(QStringLike) s)/+ noexcept+/ 381 { return /+ q_no_char8_t:: +/QUtf8StringView(s.data(), s.size()); } 382