1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef API_BASE_CONTAINERS_BASIC_FIXED_STRING_H 17 #define API_BASE_CONTAINERS_BASIC_FIXED_STRING_H 18 19 #include <cstddef> 20 #include <cstdint> 21 22 #include <base/containers/allocator.h> 23 #include <base/containers/string_view.h> 24 #include <base/containers/type_traits.h> 25 #include <base/namespace.h> 26 27 BASE_BEGIN_NAMESPACE() 28 template<class CharT, size_t maxSize> 29 class basic_fixed_string; 30 31 template<size_t maxSize> 32 using fixed_string = BASE_NS::basic_fixed_string<char, maxSize>; 33 34 template<size_t maxSize> 35 using fixed_wstring = BASE_NS::basic_fixed_string<wchar_t, maxSize>; 36 37 template<class CharT, size_t maxSize> 38 class basic_fixed_string { 39 public: 40 using string_view = basic_string_view<CharT>; 41 using value_type = CharT; 42 using size_type = typename string_view::size_type; 43 static constexpr size_type npos = string_view::npos; 44 basic_fixed_string() = default; 45 ~basic_fixed_string() = default; 46 basic_fixed_string(const basic_fixed_string & a)47 constexpr basic_fixed_string(const basic_fixed_string& a) noexcept 48 { 49 initialize({ a.data_, a.len_ }); 50 } 51 basic_fixed_string(basic_fixed_string && a)52 constexpr basic_fixed_string(basic_fixed_string&& a) noexcept 53 { 54 initialize({ a.data_, a.len_ }); 55 } 56 57 template<size_t N> basic_fixed_string(const basic_fixed_string<CharT,N> & a)58 constexpr basic_fixed_string(const basic_fixed_string<CharT, N>& a) noexcept 59 { 60 initialize({ a.data(), a.size() }); 61 } 62 63 template<size_t N> basic_fixed_string(const CharT (& a)[N])64 constexpr basic_fixed_string(const CharT (&a)[N]) 65 { 66 initialize({ a, N - 1 }); 67 } 68 basic_fixed_string(const CharT * const a)69 constexpr basic_fixed_string(const CharT* const a) noexcept 70 { 71 initialize({ a, constexpr_strlen(a) }); 72 } 73 basic_fixed_string(CharT a)74 constexpr basic_fixed_string(CharT a) noexcept 75 { 76 initialize({ &a, 1 }); 77 } 78 basic_fixed_string(const basic_string_view<CharT> & a)79 constexpr basic_fixed_string(const basic_string_view<CharT>& a) noexcept 80 { 81 initialize(a); 82 } 83 basic_fixed_string(const size_t size)84 constexpr basic_fixed_string(const size_t size) noexcept : len_((size < maxSize) ? size : maxSize) {} 85 86 template<typename T, typename = void> 87 struct HasData : false_type {}; 88 template<typename T> 89 struct HasData<T, void_t<decltype(declval<T>().data())>> : true_type {}; 90 template<typename T, typename = void> 91 struct HasSize : false_type {}; 92 template<typename T> 93 struct HasSize<T, void_t<decltype(declval<T>().size())>> : true_type {}; 94 template<typename T> 95 using HasDataAndSize = enable_if_t<(HasData<T>::value && HasSize<T>::value)>; 96 template<class StringT, class = HasDataAndSize<StringT>> 97 constexpr explicit basic_fixed_string(const StringT& s) noexcept; 98 99 constexpr bool empty() const noexcept 100 { 101 return len_ == 0; 102 } 103 104 constexpr size_t size() const noexcept 105 { 106 return len_; 107 } 108 109 constexpr size_t length() const noexcept 110 { 111 return len_; 112 } 113 114 constexpr size_t capacity() const noexcept 115 { 116 return maxSize; 117 } 118 119 constexpr basic_fixed_string& operator=(const basic_fixed_string& a) noexcept 120 { 121 initialize({ a.data_, a.len_ }); 122 return *this; 123 } 124 125 constexpr basic_fixed_string& operator=(basic_fixed_string&& a) noexcept 126 { 127 initialize({ a.data_, a.len_ }); 128 return *this; 129 } 130 131 template<size_t N> 132 constexpr basic_fixed_string& operator=(const basic_fixed_string<CharT, N>& a) noexcept 133 { 134 initialize({ a.data(), a.size() }); 135 return *this; 136 } 137 138 template<size_t N> 139 constexpr basic_fixed_string& operator=(basic_fixed_string<CharT, N>&& a) noexcept 140 { 141 initialize({ a.data(), a.size() }); 142 return *this; 143 } 144 145 constexpr basic_fixed_string& operator=(const string_view& a) noexcept 146 { 147 initialize(a); 148 return *this; 149 } 150 151 constexpr basic_fixed_string& operator=(CharT const* const& a) noexcept 152 { 153 initialize({ a, constexpr_strlen(a) }); 154 return *this; 155 } 156 157 constexpr basic_fixed_string operator+(const string_view& b) const 158 { 159 basic_fixed_string res(*this); 160 res.append_impl(b); 161 return res; 162 } 163 164 constexpr basic_fixed_string operator+(CharT const* const& a) const 165 { 166 basic_fixed_string res(*this); 167 res.append_impl({ a, constexpr_strlen(a) }); 168 return res; 169 } 170 171 constexpr basic_fixed_string& operator+=(const string_view& a) 172 { 173 append_impl(a); 174 return *this; 175 } 176 177 constexpr basic_fixed_string& operator+=(CharT const* const& a) 178 { 179 append_impl({ a, constexpr_strlen(a) }); 180 return *this; 181 } 182 183 constexpr basic_fixed_string& operator+=(CharT a) 184 { 185 append_impl({ &a, 1 }); 186 return *this; 187 } 188 189 constexpr CharT const* data() const 190 { 191 return data_; 192 } 193 194 constexpr CharT* data() 195 { 196 return data_; 197 } 198 199 constexpr CharT const* c_str() const 200 { 201 return data_; 202 } 203 204 constexpr operator string_view() const noexcept 205 { 206 return string_view(data_, len_); 207 } 208 209 constexpr size_type copy(CharT* const dst, size_type todo, size_type pos = 0) const 210 { 211 return string_view(*this).copy(dst, todo, pos); 212 } 213 214 /** find substring in the view */ 215 constexpr size_type find(const CharT str, size_type pos = 0) const noexcept 216 { 217 return string_view(*this).find(str, pos); 218 } 219 220 constexpr size_type find(const string_view& str, size_type pos = 0) const noexcept 221 { 222 return string_view(*this).find(str, pos); 223 } 224 225 /* find the last occurrence of a substring in the view */ 226 constexpr size_type rfind(const CharT str, size_type pos = npos) const noexcept 227 { 228 return string_view(*this).rfind(str, pos); 229 } 230 231 constexpr size_type rfind(const string_view& str, size_type pos = npos) const noexcept 232 { 233 return string_view(*this).rfind(str, pos); 234 } 235 236 /* find first occurance of characters in the view */ 237 constexpr size_type find_first_of(const string_view& str, size_type pos = 0) const noexcept 238 { 239 return string_view(*this).find_first_of(str, pos); 240 } 241 242 constexpr size_type find_first_of(CharT ch, size_type pos = 0) const noexcept 243 { 244 return string_view(*this).find_first_of(ch, pos); 245 } 246 247 /* find last occurrence of characters in the view */ 248 constexpr size_type find_last_of(const string_view& str, size_type pos = npos) const noexcept 249 { 250 return string_view(*this).find_last_of(str, pos); 251 } 252 253 constexpr size_type find_last_of(CharT ch, size_type pos = npos) const noexcept 254 { 255 return string_view(*this).find_last_of(ch, pos); 256 } 257 258 /* find first absence of characters 259 find_first_not_of 260 261 find last absence of characters 262 find_last_not_of */ 263 constexpr basic_fixed_string& append(const string_view& b) 264 { 265 append_impl(b); 266 return *this; 267 } 268 269 constexpr basic_fixed_string& append(CharT const* const a) 270 { 271 append_impl({ a, constexpr_strlen(a) }); 272 return *this; 273 } 274 275 constexpr basic_fixed_string& append(CharT a) 276 { 277 append_impl({ &a, 1 }); 278 return *this; 279 } 280 281 basic_fixed_string& replace(size_t first, size_t last, const basic_string_view<CharT>& str) 282 { 283 const auto replace = last - first; 284 const auto add = str.length(); 285 const auto newSize = len_ + add - replace; 286 if (add < replace) { 287 CloneData(data() + first, replace, str.data(), add); 288 MoveData(data() + first + add, len_ - first - add, data() + last, len_ - last); 289 } else if (add > replace) { 290 const auto start = newSize < maxSize ? newSize : maxSize; 291 for (auto i = start; i > last; --i) { 292 data_[i] = data_[i - add + replace]; 293 } 294 CloneData(data() + first, len_, str.data(), add); 295 } else { 296 CloneData(data() + first, replace, str.data(), add); 297 } 298 len_ = newSize < maxSize ? newSize : maxSize; 299 data_[len_] = 0; 300 return *this; 301 } 302 303 protected: 304 constexpr void initialize(const string_view& other) 305 { 306 len_ = other.length(); 307 len_ = (len_ < maxSize) ? len_ : maxSize; 308 other.copy(data_, len_); 309 data_[len_] = 0; 310 } 311 312 constexpr void append_impl(const string_view& other) 313 { 314 size_t todo = other.length(); 315 todo = ((todo + len_) > maxSize) ? (maxSize - len_) : todo; 316 other.copy(data_ + len_, todo); 317 len_ += todo; 318 data_[len_] = 0; 319 } 320 321 size_t len_ { 0 }; 322 CharT data_[maxSize + 1] { 0 }; 323 }; 324 325 template<class CharT, size_t maxSize> 326 template<class StringT, class> 327 constexpr basic_fixed_string<CharT, maxSize>::basic_fixed_string(const StringT& s) noexcept 328 { 329 initialize({ s.data(), s.length() }); 330 } 331 template<class CharT, size_t N> 332 basic_fixed_string(const CharT (&)[N]) -> basic_fixed_string<CharT, N - 1>; 333 334 template<class CharT, size_t M, size_t N> 335 constexpr basic_fixed_string<CharT, M + N> operator+( 336 const basic_fixed_string<CharT, M>& lhs, const basic_fixed_string<CharT, N>& rhs) noexcept 337 { 338 basic_fixed_string<CharT, M + N> res { lhs }; 339 res.append(rhs); 340 return res; 341 } 342 343 template<class CharT, size_t M, size_t N> 344 constexpr basic_fixed_string<CharT, M + N> operator+( 345 const CharT (&lhs)[M], const basic_fixed_string<CharT, N>& rhs) noexcept 346 { 347 basic_fixed_string<CharT, M + N> res { lhs }; 348 res.append(rhs); 349 return res; 350 } 351 352 template<class CharT, size_t M, size_t N> 353 constexpr basic_fixed_string<CharT, M + N> operator+( 354 const basic_fixed_string<CharT, M>& lhs, const CharT (&rhs)[N]) noexcept 355 { 356 basic_fixed_string<CharT, M + N> res { lhs }; 357 res.append(rhs); 358 return res; 359 } 360 361 template<class CharT, size_t N> 362 constexpr basic_fixed_string<CharT, 1 + N> operator+(CharT lhs, const basic_fixed_string<CharT, N>& rhs) noexcept 363 { 364 basic_fixed_string<CharT, 1 + N> res(string_view(&lhs, 1)); 365 res.append(rhs); 366 return res; 367 } 368 369 template<class CharT, size_t M, size_t N> 370 constexpr bool operator==(const basic_fixed_string<CharT, M>& lhs, const basic_fixed_string<CharT, N>& rhs) noexcept 371 { 372 return string_view(lhs) == string_view(rhs); 373 } 374 375 template<class CharT, size_t M, int = 1> 376 constexpr bool operator==( 377 const basic_fixed_string<CharT, M>& lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept 378 { 379 return string_view(lhs) == rhs; 380 } 381 382 template<class CharT, size_t M, int = 2> 383 constexpr bool operator==( 384 const type_identity_t<basic_string_view<CharT>> lhs, const basic_fixed_string<CharT, M>& rhs) noexcept 385 { 386 return lhs == string_view(rhs); 387 } 388 389 template<class CharT, size_t M, size_t N> 390 constexpr bool operator!=(const basic_fixed_string<CharT, M>& lhs, const basic_fixed_string<CharT, N>& rhs) noexcept 391 { 392 return string_view(lhs) != string_view(rhs); 393 } 394 395 template<class CharT, size_t M, int = 1> 396 constexpr bool operator!=( 397 const basic_fixed_string<CharT, M>& lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept 398 { 399 return string_view(lhs) != rhs; 400 } 401 402 template<class CharT, size_t M, int = 2> 403 constexpr bool operator!=( 404 const type_identity_t<basic_string_view<CharT>> lhs, const basic_fixed_string<CharT, M>& rhs) noexcept 405 { 406 return lhs != string_view(rhs); 407 } 408 409 template<class CharT, size_t M, size_t N> 410 constexpr bool operator<(const basic_fixed_string<CharT, M>& lhs, const basic_fixed_string<CharT, N>& rhs) noexcept 411 { 412 return string_view(lhs) < string_view(rhs); 413 } 414 415 template<class CharT, size_t M, int = 1> 416 constexpr bool operator<( 417 const basic_fixed_string<CharT, M>& lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept 418 { 419 return string_view(lhs) < rhs; 420 } 421 422 template<class CharT, size_t M, int = 2> 423 constexpr bool operator<( 424 const type_identity_t<basic_string_view<CharT>> lhs, const basic_fixed_string<CharT, M>& rhs) noexcept 425 { 426 return lhs < string_view(rhs); 427 } 428 429 template<typename Number, typename = enable_if_t<is_integral_v<Number>>> 430 constexpr fixed_string<21u> to_string(Number num) 431 { 432 fixed_string<21u> str; 433 uint64_t n = static_cast<uint64_t>(num); 434 // negate negative values 435 if constexpr (is_signed<Number>::value) { 436 if (num < 0) { 437 n = static_cast<uint64_t>(-num); 438 } 439 } 440 441 // write starting from the end 442 const auto end = str.data() + str.capacity(); 443 auto p = end - 1; 444 do { 445 *p-- = '0' + static_cast<char>(n % 10U); 446 n /= 10U; 447 } while (n != 0U); 448 449 // add sign if needed 450 if constexpr (is_signed<Number>::value) { 451 if (num < 0) { 452 *p-- = '-'; 453 } 454 } 455 456 ++p; 457 str.append(string_view(p, static_cast<size_t>(end - p))); 458 return str; 459 } 460 461 template<typename Number, typename = enable_if_t<is_integral_v<Number>>> 462 constexpr fixed_string<21u> to_hex(Number num) 463 { 464 fixed_string<21u> str; 465 uint64_t n = static_cast<uint64_t>(num); 466 // negate negative values 467 if constexpr (is_signed<Number>::value) { 468 if (num < 0) { 469 n = static_cast<uint64_t>(-num); 470 } 471 } 472 473 // write starting from the end 474 const auto end = str.data() + str.capacity(); 475 auto p = end - 1; 476 const char* hex = "0123456789ABCDEF"; 477 do { 478 *p-- = hex[(n % 16U)]; 479 n /= 16U; 480 } while (n != 0U); 481 482 // add sign if needed 483 if constexpr (is_signed<Number>::value) { 484 if (num < 0) { 485 *p-- = '-'; 486 } 487 } 488 489 ++p; 490 str.append(string_view(p, static_cast<string_view::size_type>(end - p))); 491 return str; 492 } 493 494 template<size_t maxSize> 495 inline uint64_t hash(const fixed_string<maxSize>& value) 496 { 497 return BASE_NS::FNV1aHash(value.data(), value.size()); 498 } 499 BASE_END_NAMESPACE() 500 #endif // API_BASE_CONTAINERS_BASIC_FIXED_STRING_H