12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_STRINGS_STRCAT_INTERNAL_H_
- #define BASE_STRINGS_STRCAT_INTERNAL_H_
- #include <string>
- #include "base/containers/span.h"
- #include "base/template_util.h"
- namespace base {
- namespace internal {
- // Optimized version of `std::basic_string::resize()` that skips zero
- // initialization of appended characters. Reading from the newly allocated
- // characters results in undefined behavior if they are not explicitly
- // initialized afterwards. Currently proposed for standardization as
- // std::basic_string::resize_and_overwrite: https://wg21.link/P1072R6
- template <typename CharT>
- auto Resize(std::basic_string<CharT>& str, size_t total_size, priority_tag<1>)
- -> decltype(str.__resize_default_init(total_size)) {
- str.__resize_default_init(total_size);
- }
- // Fallback to regular std::basic_string::resize() if invoking
- // __resize_default_init is ill-formed.
- template <typename CharT>
- void Resize(std::basic_string<CharT>& str, size_t total_size, priority_tag<0>) {
- str.resize(total_size);
- }
- // Appends `pieces` to `dest`. Instead of simply calling `dest.append()`
- // `pieces.size()` times, this method first resizes `dest` to be of the desired
- // size, and then appends each piece via `std::char_traits::copy`. This achieves
- // two goals:
- // 1) Allocating the desired size all at once avoids other allocations that
- // could happen if intermediate allocations did not reserve enough capacity.
- // 2) Invoking std::char_traits::copy instead of std::basic_string::append
- // avoids having to write the terminating '\0' character n times.
- template <typename CharT, typename StringT>
- void StrAppendT(std::basic_string<CharT>& dest, span<const StringT> pieces) {
- const size_t initial_size = dest.size();
- size_t total_size = initial_size;
- for (const auto& cur : pieces)
- total_size += cur.size();
- // Note: As opposed to `reserve()` calling `resize()` with an argument smaller
- // than the current `capacity()` does not result in the string releasing spare
- // capacity. Furthermore, common std::string implementations apply a geometric
- // growth strategy if the current capacity is not sufficient for the newly
- // added characters. Since this codepath is also triggered by `resize()`, we
- // don't have to manage the std::string's capacity ourselves here to avoid
- // performance hits in case `StrAppend()` gets called in a loop.
- Resize(dest, total_size, priority_tag<1>());
- CharT* dest_char = &dest[initial_size];
- for (const auto& cur : pieces) {
- std::char_traits<CharT>::copy(dest_char, cur.data(), cur.size());
- dest_char += cur.size();
- }
- }
- template <typename StringT>
- auto StrCatT(span<const StringT> pieces) {
- std::basic_string<typename StringT::value_type> result;
- StrAppendT(result, pieces);
- return result;
- }
- } // namespace internal
- } // namespace base
- #endif // BASE_STRINGS_STRCAT_INTERNAL_H_
|