/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef API_BASE_CONTAINERS_BASIC_FIXED_STRING_H #define API_BASE_CONTAINERS_BASIC_FIXED_STRING_H #include #include #include #include #include #include BASE_BEGIN_NAMESPACE() template class basic_fixed_string; template using fixed_string = BASE_NS::basic_fixed_string; template using fixed_wstring = BASE_NS::basic_fixed_string; template class basic_fixed_string { public: using string_view = basic_string_view; using value_type = CharT; using size_type = typename string_view::size_type; static constexpr size_type npos = string_view::npos; basic_fixed_string() = default; ~basic_fixed_string() = default; constexpr basic_fixed_string(const basic_fixed_string& a) noexcept { initialize({ a.data_, a.len_ }); } constexpr basic_fixed_string(basic_fixed_string&& a) noexcept { initialize({ a.data_, a.len_ }); } template constexpr basic_fixed_string(const basic_fixed_string& a) noexcept { initialize({ a.data(), a.size() }); } template constexpr basic_fixed_string(const CharT (&a)[N]) { initialize({ a, N - 1 }); } constexpr basic_fixed_string(const CharT* const a) noexcept { initialize({ a, constexpr_strlen(a) }); } constexpr basic_fixed_string(CharT a) noexcept { initialize({ &a, 1 }); } constexpr basic_fixed_string(const basic_string_view& a) noexcept { initialize(a); } constexpr basic_fixed_string(const size_t size) noexcept : len_((size < maxSize) ? size : maxSize) {} template struct HasData : false_type {}; template struct HasData().data())>> : true_type {}; template struct HasSize : false_type {}; template struct HasSize().size())>> : true_type {}; template using HasDataAndSize = enable_if_t<(HasData::value && HasSize::value)>; template> constexpr explicit basic_fixed_string(const StringT& s) noexcept; constexpr bool empty() const noexcept { return len_ == 0; } constexpr size_t size() const noexcept { return len_; } constexpr size_t length() const noexcept { return len_; } constexpr size_t capacity() const noexcept { return maxSize; } constexpr basic_fixed_string& operator=(const basic_fixed_string& a) noexcept { initialize({ a.data_, a.len_ }); return *this; } constexpr basic_fixed_string& operator=(basic_fixed_string&& a) noexcept { initialize({ a.data_, a.len_ }); return *this; } template constexpr basic_fixed_string& operator=(const basic_fixed_string& a) noexcept { initialize({ a.data(), a.size() }); return *this; } template constexpr basic_fixed_string& operator=(basic_fixed_string&& a) noexcept { initialize({ a.data(), a.size() }); return *this; } constexpr basic_fixed_string& operator=(const string_view& a) noexcept { initialize(a); return *this; } constexpr basic_fixed_string& operator=(CharT const* const& a) noexcept { initialize({ a, constexpr_strlen(a) }); return *this; } constexpr basic_fixed_string operator+(const string_view& b) const { basic_fixed_string res(*this); res.append_impl(b); return res; } constexpr basic_fixed_string operator+(CharT const* const& a) const { basic_fixed_string res(*this); res.append_impl({ a, constexpr_strlen(a) }); return res; } constexpr basic_fixed_string& operator+=(const string_view& a) { append_impl(a); return *this; } constexpr basic_fixed_string& operator+=(CharT const* const& a) { append_impl({ a, constexpr_strlen(a) }); return *this; } constexpr basic_fixed_string& operator+=(CharT a) { append_impl({ &a, 1 }); return *this; } constexpr CharT const* data() const { return data_; } constexpr CharT* data() { return data_; } constexpr CharT const* c_str() const { return data_; } constexpr operator string_view() const noexcept { return string_view(data_, len_); } constexpr size_type copy(CharT* const dst, size_type todo, size_type pos = 0) const { return string_view(*this).copy(dst, todo, pos); } /** find substring in the view */ constexpr size_type find(const CharT str, size_type pos = 0) const noexcept { return string_view(*this).find(str, pos); } constexpr size_type find(const string_view& str, size_type pos = 0) const noexcept { return string_view(*this).find(str, pos); } /* find the last occurrence of a substring in the view */ constexpr size_type rfind(const CharT str, size_type pos = npos) const noexcept { return string_view(*this).rfind(str, pos); } constexpr size_type rfind(const string_view& str, size_type pos = npos) const noexcept { return string_view(*this).rfind(str, pos); } /* find first occurance of characters in the view */ constexpr size_type find_first_of(const string_view& str, size_type pos = 0) const noexcept { return string_view(*this).find_first_of(str, pos); } constexpr size_type find_first_of(CharT ch, size_type pos = 0) const noexcept { return string_view(*this).find_first_of(ch, pos); } /* find last occurrence of characters in the view */ constexpr size_type find_last_of(const string_view& str, size_type pos = npos) const noexcept { return string_view(*this).find_last_of(str, pos); } constexpr size_type find_last_of(CharT ch, size_type pos = npos) const noexcept { return string_view(*this).find_last_of(ch, pos); } /* find first absence of characters find_first_not_of find last absence of characters find_last_not_of */ constexpr basic_fixed_string& append(const string_view& b) { append_impl(b); return *this; } constexpr basic_fixed_string& append(CharT const* const a) { append_impl({ a, constexpr_strlen(a) }); return *this; } constexpr basic_fixed_string& append(CharT a) { append_impl({ &a, 1 }); return *this; } basic_fixed_string& replace(size_t first, size_t last, const basic_string_view& str) { const auto replace = last - first; const auto add = str.length(); const auto newSize = len_ + add - replace; if (add < replace) { CloneData(data() + first, replace, str.data(), add); MoveData(data() + first + add, len_ - first - add, data() + last, len_ - last); } else if (add > replace) { const auto start = newSize < maxSize ? newSize : maxSize; for (auto i = start; i > last; --i) { data_[i] = data_[i - add + replace]; } CloneData(data() + first, len_, str.data(), add); } else { CloneData(data() + first, replace, str.data(), add); } len_ = newSize < maxSize ? newSize : maxSize; data_[len_] = 0; return *this; } protected: constexpr void initialize(const string_view& other) { len_ = other.length(); len_ = (len_ < maxSize) ? len_ : maxSize; other.copy(data_, len_); data_[len_] = 0; } constexpr void append_impl(const string_view& other) { size_t todo = other.length(); todo = ((todo + len_) > maxSize) ? (maxSize - len_) : todo; other.copy(data_ + len_, todo); len_ += todo; data_[len_] = 0; } size_t len_ { 0 }; CharT data_[maxSize + 1] { 0 }; }; template template constexpr basic_fixed_string::basic_fixed_string(const StringT& s) noexcept { initialize({ s.data(), s.length() }); } template basic_fixed_string(const CharT (&)[N]) -> basic_fixed_string; template constexpr basic_fixed_string operator+( const basic_fixed_string& lhs, const basic_fixed_string& rhs) noexcept { basic_fixed_string res { lhs }; res.append(rhs); return res; } template constexpr basic_fixed_string operator+( const CharT (&lhs)[M], const basic_fixed_string& rhs) noexcept { basic_fixed_string res { lhs }; res.append(rhs); return res; } template constexpr basic_fixed_string operator+( const basic_fixed_string& lhs, const CharT (&rhs)[N]) noexcept { basic_fixed_string res { lhs }; res.append(rhs); return res; } template constexpr basic_fixed_string operator+(CharT lhs, const basic_fixed_string& rhs) noexcept { basic_fixed_string res(string_view(&lhs, 1)); res.append(rhs); return res; } template constexpr bool operator==(const basic_fixed_string& lhs, const basic_fixed_string& rhs) noexcept { return string_view(lhs) == string_view(rhs); } template constexpr bool operator==( const basic_fixed_string& lhs, const type_identity_t> rhs) noexcept { return string_view(lhs) == rhs; } template constexpr bool operator==( const type_identity_t> lhs, const basic_fixed_string& rhs) noexcept { return lhs == string_view(rhs); } template constexpr bool operator!=(const basic_fixed_string& lhs, const basic_fixed_string& rhs) noexcept { return string_view(lhs) != string_view(rhs); } template constexpr bool operator!=( const basic_fixed_string& lhs, const type_identity_t> rhs) noexcept { return string_view(lhs) != rhs; } template constexpr bool operator!=( const type_identity_t> lhs, const basic_fixed_string& rhs) noexcept { return lhs != string_view(rhs); } template constexpr bool operator<(const basic_fixed_string& lhs, const basic_fixed_string& rhs) noexcept { return string_view(lhs) < string_view(rhs); } template constexpr bool operator<( const basic_fixed_string& lhs, const type_identity_t> rhs) noexcept { return string_view(lhs) < rhs; } template constexpr bool operator<( const type_identity_t> lhs, const basic_fixed_string& rhs) noexcept { return lhs < string_view(rhs); } template>> constexpr fixed_string<21u> to_string(Number num) { fixed_string<21u> str; uint64_t n = static_cast(num); // negate negative values if constexpr (is_signed::value) { if (num < 0) { n = static_cast(-num); } } // write starting from the end const auto end = str.data() + str.capacity(); auto p = end - 1; do { *p-- = '0' + static_cast(n % 10U); n /= 10U; } while (n != 0U); // add sign if needed if constexpr (is_signed::value) { if (num < 0) { *p-- = '-'; } } ++p; str.append(string_view(p, static_cast(end - p))); return str; } template>> constexpr fixed_string<21u> to_hex(Number num) { fixed_string<21u> str; uint64_t n = static_cast(num); // negate negative values if constexpr (is_signed::value) { if (num < 0) { n = static_cast(-num); } } // write starting from the end const auto end = str.data() + str.capacity(); auto p = end - 1; const char* hex = "0123456789ABCDEF"; do { *p-- = hex[(n % 16U)]; n /= 16U; } while (n != 0U); // add sign if needed if constexpr (is_signed::value) { if (num < 0) { *p-- = '-'; } } ++p; str.append(string_view(p, static_cast(end - p))); return str; } template inline uint64_t hash(const fixed_string& value) { return BASE_NS::FNV1aHash(value.data(), value.size()); } BASE_END_NAMESPACE() #endif // API_BASE_CONTAINERS_BASIC_FIXED_STRING_H