| 1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
| 2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 |
| 3 | |
| 4 | #pragma once |
| 5 | #include <string_view> |
| 6 | #include "slint_string_internal.h" |
| 7 | |
| 8 | namespace slint { |
| 9 | |
| 10 | /// A string type used by the Slint run-time. |
| 11 | /// |
| 12 | /// SharedString uses implicit data sharing to make it efficient to pass around copies. When |
| 13 | /// copying, a reference to the data is cloned, not the data itself. |
| 14 | /// |
| 15 | /// The class provides constructors from std::string_view as well as the automatic conversion to |
| 16 | /// a std::string_view. |
| 17 | /// |
| 18 | /// For convenience, it's also possible to convert a number to a string using |
| 19 | /// SharedString::from_number(double). |
| 20 | /// |
| 21 | /// Under the hood the string data is UTF-8 encoded and it is always terminated with a null |
| 22 | /// character. |
| 23 | struct SharedString |
| 24 | { |
| 25 | /// Creates an empty default constructed string. |
| 26 | SharedString() { cbindgen_private::slint_shared_string_from_bytes(out: this, bytes: "" , len: 0); } |
| 27 | /// Creates a new SharedString from the string view \a s. The underlying string data |
| 28 | /// is copied. |
| 29 | SharedString(std::string_view s) |
| 30 | { |
| 31 | cbindgen_private::slint_shared_string_from_bytes(out: this, bytes: s.data(), len: s.size()); |
| 32 | } |
| 33 | /// Creates a new SharedString from the null-terminated string pointer \a s. The underlying |
| 34 | /// string data is copied. It is assumed that the string is UTF-8 encoded. |
| 35 | SharedString(const char *s) : SharedString(std::string_view(s)) { } |
| 36 | /// Creates a new SharedString from the null-terminated string pointer \a s. The underlying |
| 37 | /// string data is copied. |
| 38 | SharedString(const char8_t *s) : SharedString(reinterpret_cast<const char *>(s)) { } |
| 39 | /// Creates a new SharedString from the string view \a s. The underlying string data is copied. |
| 40 | SharedString(std::u8string_view s) |
| 41 | { |
| 42 | cbindgen_private::slint_shared_string_from_bytes( |
| 43 | out: this, bytes: reinterpret_cast<const char *>(s.data()), len: s.size()); |
| 44 | } |
| 45 | /// Creates a new SharedString from \a other. |
| 46 | SharedString(const SharedString &other) |
| 47 | { |
| 48 | cbindgen_private::slint_shared_string_clone(out: this, ss: &other); |
| 49 | } |
| 50 | /// Destroys this SharedString and frees the memory if this is the last instance |
| 51 | /// referencing it. |
| 52 | ~SharedString() { cbindgen_private::slint_shared_string_drop(ss: this); } |
| 53 | /// Assigns \a other to this string and returns a reference to this string. |
| 54 | SharedString &operator=(const SharedString &other) |
| 55 | { |
| 56 | cbindgen_private::slint_shared_string_drop(ss: this); |
| 57 | cbindgen_private::slint_shared_string_clone(out: this, ss: &other); |
| 58 | return *this; |
| 59 | } |
| 60 | /// Assigns the string view \a s to this string and returns a reference to this string. |
| 61 | /// The underlying string data is copied. It is assumed that the string is UTF-8 encoded. |
| 62 | SharedString &operator=(std::string_view s) |
| 63 | { |
| 64 | cbindgen_private::slint_shared_string_drop(ss: this); |
| 65 | cbindgen_private::slint_shared_string_from_bytes(out: this, bytes: s.data(), len: s.size()); |
| 66 | return *this; |
| 67 | } |
| 68 | /// Assigns null-terminated string pointer \a s to this string and returns a reference |
| 69 | /// to this string. The underlying string data is copied. It is assumed that the string |
| 70 | /// is UTF-8 encoded. |
| 71 | SharedString &operator=(const char *s) { return *this = std::string_view(s); } |
| 72 | |
| 73 | /// Move-assigns \a other to this SharedString instance. |
| 74 | SharedString &operator=(SharedString &&other) |
| 75 | { |
| 76 | std::swap(a&: inner, b&: other.inner); |
| 77 | return *this; |
| 78 | } |
| 79 | |
| 80 | /// Provides a view to the string data. The returned view is only valid as long as at |
| 81 | /// least this SharedString exists. |
| 82 | operator std::string_view() const { return cbindgen_private::slint_shared_string_bytes(ss: this); } |
| 83 | /// Provides a raw pointer to the string data. The returned pointer is only valid as long as at |
| 84 | /// least this SharedString exists. |
| 85 | auto data() const -> const char * { return cbindgen_private::slint_shared_string_bytes(ss: this); } |
| 86 | /// Size of the string, in bytes. This excludes the terminating null character. |
| 87 | std::size_t size() const { return std::string_view(*this).size(); } |
| 88 | |
| 89 | /// Returns a pointer to the first character. It is only safe to dereference the pointer if the |
| 90 | /// string contains at least one character. |
| 91 | const char *begin() const { return data(); } |
| 92 | /// Returns a point past the last character of the string. It is not safe to dereference the |
| 93 | /// pointer, but it is suitable for comparison. |
| 94 | const char *end() const |
| 95 | { |
| 96 | std::string_view view(*this); |
| 97 | return view.data() + view.size(); |
| 98 | } |
| 99 | |
| 100 | /// \return true if the string contains no characters; false otherwise. |
| 101 | bool empty() const { return std::string_view(*this).empty(); } |
| 102 | |
| 103 | /// \return true if the string starts with the specified prefix string; false otherwise |
| 104 | bool starts_with(std::string_view prefix) const |
| 105 | { |
| 106 | return std::string_view(*this).substr(pos: 0, n: prefix.size()) == prefix; |
| 107 | } |
| 108 | |
| 109 | /// \return true if the string ends with the specified prefix string; false otherwise |
| 110 | bool ends_with(std::string_view prefix) const |
| 111 | { |
| 112 | std::string_view self_view(*this); |
| 113 | return self_view.size() >= prefix.size() |
| 114 | && self_view.compare(pos1: self_view.size() - prefix.size(), n1: std::string_view::npos, |
| 115 | str: prefix) |
| 116 | == 0; |
| 117 | } |
| 118 | |
| 119 | /// Creates a new SharedString from the given number \a n. The string representation of the |
| 120 | /// number uses a minimal formatting scheme: If \a n has no fractional part, the number will be |
| 121 | /// formatted as an integer. |
| 122 | /// |
| 123 | /// For example: |
| 124 | /// \code |
| 125 | /// auto str = slint::SharedString::from_number(42); // creates "42" |
| 126 | /// auto str2 = slint::SharedString::from_number(100.5) // creates "100.5" |
| 127 | /// \endcode |
| 128 | static SharedString from_number(double n) { return SharedString(n); } |
| 129 | |
| 130 | /// Returns the lowercase equivalent of this string, as a new SharedString. |
| 131 | /// |
| 132 | /// For example: |
| 133 | /// \code |
| 134 | /// auto str = slint::SharedString("Hello"); |
| 135 | /// auto str2 = str.to_lowercase(); // creates "hello" |
| 136 | /// \endcode |
| 137 | SharedString to_lowercase() const |
| 138 | { |
| 139 | auto out = SharedString(); |
| 140 | cbindgen_private::slint_shared_string_to_lowercase(out: &out, ss: this); |
| 141 | return out; |
| 142 | } |
| 143 | |
| 144 | /// Returns the uppercase equivalent of this string, as a new SharedString. |
| 145 | /// |
| 146 | /// For example: |
| 147 | /// \code |
| 148 | /// auto str = slint::SharedString("Hello"); |
| 149 | /// auto str2 = str.to_uppercase(); // creates "HELLO" |
| 150 | /// \endcode |
| 151 | SharedString to_uppercase() const |
| 152 | { |
| 153 | auto out = SharedString(); |
| 154 | cbindgen_private::slint_shared_string_to_uppercase(out: &out, ss: this); |
| 155 | return out; |
| 156 | } |
| 157 | |
| 158 | /// Returns true if \a a is equal to \a b; otherwise returns false. |
| 159 | friend bool operator==(const SharedString &a, const SharedString &b) |
| 160 | { |
| 161 | return std::string_view(a) == std::string_view(b); |
| 162 | } |
| 163 | /// Returns true if \a a is not equal to \a b; otherwise returns false. |
| 164 | friend bool operator!=(const SharedString &a, const SharedString &b) |
| 165 | { |
| 166 | return std::string_view(a) != std::string_view(b); |
| 167 | } |
| 168 | |
| 169 | /// Returns true if \a a is lexicographically less than \a b; false otherwise. |
| 170 | friend bool operator<(const SharedString &a, const SharedString &b) |
| 171 | { |
| 172 | return std::string_view(a) < std::string_view(b); |
| 173 | } |
| 174 | /// Returns true if \a a is lexicographically less or equal than \a b; false otherwise. |
| 175 | friend bool operator<=(const SharedString &a, const SharedString &b) |
| 176 | { |
| 177 | return std::string_view(a) <= std::string_view(b); |
| 178 | } |
| 179 | /// Returns true if \a a is lexicographically greater than \a b; false otherwise. |
| 180 | friend bool operator>(const SharedString &a, const SharedString &b) |
| 181 | { |
| 182 | return std::string_view(a) > std::string_view(b); |
| 183 | } |
| 184 | /// Returns true if \a a is lexicographically greater or equal than \a b; false otherwise. |
| 185 | friend bool operator>=(const SharedString &a, const SharedString &b) |
| 186 | { |
| 187 | return std::string_view(a) >= std::string_view(b); |
| 188 | } |
| 189 | |
| 190 | /// Writes the \a shared_string to the specified \a stream and returns a reference to the |
| 191 | /// stream. |
| 192 | friend std::ostream &operator<<(std::ostream &stream, const SharedString &shared_string) |
| 193 | { |
| 194 | return stream << std::string_view(shared_string); |
| 195 | } |
| 196 | |
| 197 | /// Concatenates \a a and \a and returns the result as a new SharedString. |
| 198 | friend SharedString operator+(const SharedString &a, std::string_view b) |
| 199 | { |
| 200 | SharedString a2 = a; |
| 201 | return a2 += b; |
| 202 | } |
| 203 | /// Move-concatenates \a b to \a and returns a reference to \a a. |
| 204 | friend SharedString operator+(SharedString &&a, std::string_view b) |
| 205 | { |
| 206 | a += b; |
| 207 | return a; |
| 208 | } |
| 209 | /// Appends \a other to this string and returns a reference to this. |
| 210 | SharedString &operator+=(std::string_view other) |
| 211 | { |
| 212 | cbindgen_private::slint_shared_string_append(self_: this, bytes: other.data(), len: other.size()); |
| 213 | return *this; |
| 214 | } |
| 215 | |
| 216 | private: |
| 217 | /// Use SharedString::from_number |
| 218 | explicit SharedString(double n) { cbindgen_private::slint_shared_string_from_number(out: this, n); } |
| 219 | void *inner; // opaque |
| 220 | }; |
| 221 | |
| 222 | namespace private_api { |
| 223 | inline cbindgen_private::Slice<uint8_t> string_to_slice(std::string_view str) |
| 224 | { |
| 225 | return cbindgen_private::Slice<uint8_t> { |
| 226 | const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(str.data())), str.size() |
| 227 | }; |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | } |
| 232 | |