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