resize_uninitialized.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. //
  2. // Copyright 2017 The Abseil Authors.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // https://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #ifndef ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
  17. #define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
  18. #include <algorithm>
  19. #include <string>
  20. #include <type_traits>
  21. #include <utility>
  22. #include "absl/base/port.h"
  23. #include "absl/meta/type_traits.h" // for void_t
  24. namespace absl {
  25. ABSL_NAMESPACE_BEGIN
  26. namespace strings_internal {
  27. // In this type trait, we look for a __resize_default_init member function, and
  28. // we use it if available, otherwise, we use resize. We provide HasMember to
  29. // indicate whether __resize_default_init is present.
  30. template <typename string_type, typename = void>
  31. struct ResizeUninitializedTraits {
  32. using HasMember = std::false_type;
  33. static void Resize(string_type* s, size_t new_size) { s->resize(new_size); }
  34. };
  35. // __resize_default_init is provided by libc++ >= 8.0
  36. template <typename string_type>
  37. struct ResizeUninitializedTraits<
  38. string_type, absl::void_t<decltype(std::declval<string_type&>()
  39. .__resize_default_init(237))> > {
  40. using HasMember = std::true_type;
  41. static void Resize(string_type* s, size_t new_size) {
  42. s->__resize_default_init(new_size);
  43. }
  44. };
  45. // Returns true if the std::string implementation supports a resize where
  46. // the new characters added to the std::string are left untouched.
  47. //
  48. // (A better name might be "STLStringSupportsUninitializedResize", alluding to
  49. // the previous function.)
  50. template <typename string_type>
  51. inline constexpr bool STLStringSupportsNontrashingResize(string_type*) {
  52. return ResizeUninitializedTraits<string_type>::HasMember::value;
  53. }
  54. // Like str->resize(new_size), except any new characters added to "*str" as a
  55. // result of resizing may be left uninitialized, rather than being filled with
  56. // '0' bytes. Typically used when code is then going to overwrite the backing
  57. // store of the std::string with known data.
  58. template <typename string_type, typename = void>
  59. inline void STLStringResizeUninitialized(string_type* s, size_t new_size) {
  60. ResizeUninitializedTraits<string_type>::Resize(s, new_size);
  61. }
  62. // Used to ensure exponential growth so that the amortized complexity of
  63. // increasing the string size by a small amount is O(1), in contrast to
  64. // O(str->size()) in the case of precise growth.
  65. template <typename string_type>
  66. void STLStringReserveAmortized(string_type* s, size_t new_size) {
  67. const size_t cap = s->capacity();
  68. if (new_size > cap) {
  69. // Make sure to always grow by at least a factor of 2x.
  70. s->reserve((std::max)(new_size, 2 * cap));
  71. }
  72. }
  73. // In this type trait, we look for an __append_default_init member function, and
  74. // we use it if available, otherwise, we use append.
  75. template <typename string_type, typename = void>
  76. struct AppendUninitializedTraits {
  77. static void Append(string_type* s, size_t n) {
  78. s->append(n, typename string_type::value_type());
  79. }
  80. };
  81. template <typename string_type>
  82. struct AppendUninitializedTraits<
  83. string_type, absl::void_t<decltype(std::declval<string_type&>()
  84. .__append_default_init(237))> > {
  85. static void Append(string_type* s, size_t n) {
  86. s->__append_default_init(n);
  87. }
  88. };
  89. // Like STLStringResizeUninitialized(str, new_size), except guaranteed to use
  90. // exponential growth so that the amortized complexity of increasing the string
  91. // size by a small amount is O(1), in contrast to O(str->size()) in the case of
  92. // precise growth.
  93. template <typename string_type>
  94. void STLStringResizeUninitializedAmortized(string_type* s, size_t new_size) {
  95. const size_t size = s->size();
  96. if (new_size > size) {
  97. AppendUninitializedTraits<string_type>::Append(s, new_size - size);
  98. } else {
  99. s->erase(new_size);
  100. }
  101. }
  102. } // namespace strings_internal
  103. ABSL_NAMESPACE_END
  104. } // namespace absl
  105. #endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_