strcat_internal.h 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_STRINGS_STRCAT_INTERNAL_H_
  5. #define BASE_STRINGS_STRCAT_INTERNAL_H_
  6. #include <string>
  7. #include "base/containers/span.h"
  8. #include "base/template_util.h"
  9. namespace base {
  10. namespace internal {
  11. // Optimized version of `std::basic_string::resize()` that skips zero
  12. // initialization of appended characters. Reading from the newly allocated
  13. // characters results in undefined behavior if they are not explicitly
  14. // initialized afterwards. Currently proposed for standardization as
  15. // std::basic_string::resize_and_overwrite: https://wg21.link/P1072R6
  16. template <typename CharT>
  17. auto Resize(std::basic_string<CharT>& str, size_t total_size, priority_tag<1>)
  18. -> decltype(str.__resize_default_init(total_size)) {
  19. str.__resize_default_init(total_size);
  20. }
  21. // Fallback to regular std::basic_string::resize() if invoking
  22. // __resize_default_init is ill-formed.
  23. template <typename CharT>
  24. void Resize(std::basic_string<CharT>& str, size_t total_size, priority_tag<0>) {
  25. str.resize(total_size);
  26. }
  27. // Appends `pieces` to `dest`. Instead of simply calling `dest.append()`
  28. // `pieces.size()` times, this method first resizes `dest` to be of the desired
  29. // size, and then appends each piece via `std::char_traits::copy`. This achieves
  30. // two goals:
  31. // 1) Allocating the desired size all at once avoids other allocations that
  32. // could happen if intermediate allocations did not reserve enough capacity.
  33. // 2) Invoking std::char_traits::copy instead of std::basic_string::append
  34. // avoids having to write the terminating '\0' character n times.
  35. template <typename CharT, typename StringT>
  36. void StrAppendT(std::basic_string<CharT>& dest, span<const StringT> pieces) {
  37. const size_t initial_size = dest.size();
  38. size_t total_size = initial_size;
  39. for (const auto& cur : pieces)
  40. total_size += cur.size();
  41. // Note: As opposed to `reserve()` calling `resize()` with an argument smaller
  42. // than the current `capacity()` does not result in the string releasing spare
  43. // capacity. Furthermore, common std::string implementations apply a geometric
  44. // growth strategy if the current capacity is not sufficient for the newly
  45. // added characters. Since this codepath is also triggered by `resize()`, we
  46. // don't have to manage the std::string's capacity ourselves here to avoid
  47. // performance hits in case `StrAppend()` gets called in a loop.
  48. Resize(dest, total_size, priority_tag<1>());
  49. CharT* dest_char = &dest[initial_size];
  50. for (const auto& cur : pieces) {
  51. std::char_traits<CharT>::copy(dest_char, cur.data(), cur.size());
  52. dest_char += cur.size();
  53. }
  54. }
  55. template <typename StringT>
  56. auto StrCatT(span<const StringT> pieces) {
  57. std::basic_string<typename StringT::value_type> result;
  58. StrAppendT(result, pieces);
  59. return result;
  60. }
  61. } // namespace internal
  62. } // namespace base
  63. #endif // BASE_STRINGS_STRCAT_INTERNAL_H_