Skip to content

Commit b1b63f7

Browse files
Abseil Teamvslashg
authored andcommitted
Export of internal Abseil changes
-- d6f0dab708b123a5e24b98da1de0b11e36a7a86e by Evan Brown <[email protected]>: In STLStringResizeUninitializedAmortized, use basic_string::__append_default_init for amortized growth rather than conditionally adding reserve in STLStringReserveAmortized. This way, we can avoid extra branches, e.g. in basic_string::__shrink_or_extend. PiperOrigin-RevId: 398761382 GitOrigin-RevId: d6f0dab708b123a5e24b98da1de0b11e36a7a86e Change-Id: Ib2d99411c95d61300519c32b885ce586b410c3bf
1 parent 1ce4cec commit b1b63f7

File tree

2 files changed

+61
-10
lines changed

2 files changed

+61
-10
lines changed

absl/strings/internal/resize_uninitialized.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ namespace absl {
2929
ABSL_NAMESPACE_BEGIN
3030
namespace strings_internal {
3131

32-
// Is a subclass of true_type or false_type, depending on whether or not
33-
// T has a __resize_default_init member.
32+
// In this type trait, we look for a __resize_default_init member function, and
33+
// we use it if available, otherwise, we use resize. We provide HasMember to
34+
// indicate whether __resize_default_init is present.
3435
template <typename string_type, typename = void>
3536
struct ResizeUninitializedTraits {
3637
using HasMember = std::false_type;
@@ -79,14 +80,36 @@ void STLStringReserveAmortized(string_type* s, size_t new_size) {
7980
}
8081
}
8182

83+
// In this type trait, we look for an __append_default_init member function, and
84+
// we use it if available, otherwise, we use append.
85+
template <typename string_type, typename = void>
86+
struct AppendUninitializedTraits {
87+
static void Append(string_type* s, size_t n) {
88+
s->append(n, typename string_type::value_type());
89+
}
90+
};
91+
92+
template <typename string_type>
93+
struct AppendUninitializedTraits<
94+
string_type, absl::void_t<decltype(std::declval<string_type&>()
95+
.__append_default_init(237))> > {
96+
static void Append(string_type* s, size_t n) {
97+
s->__append_default_init(n);
98+
}
99+
};
100+
82101
// Like STLStringResizeUninitialized(str, new_size), except guaranteed to use
83102
// exponential growth so that the amortized complexity of increasing the string
84103
// size by a small amount is O(1), in contrast to O(str->size()) in the case of
85104
// precise growth.
86105
template <typename string_type>
87106
void STLStringResizeUninitializedAmortized(string_type* s, size_t new_size) {
88-
STLStringReserveAmortized(s, new_size);
89-
STLStringResizeUninitialized(s, new_size);
107+
const size_t size = s->size();
108+
if (new_size > size) {
109+
AppendUninitializedTraits<string_type>::Append(s, new_size - size);
110+
} else {
111+
s->erase(new_size);
112+
}
90113
}
91114

92115
} // namespace strings_internal

absl/strings/internal/resize_uninitialized_test.cc

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,31 @@
1919
namespace {
2020

2121
int resize_call_count = 0;
22+
int append_call_count = 0;
2223

2324
// A mock string class whose only purpose is to track how many times its
24-
// resize() method has been called.
25+
// resize()/append() methods have been called.
2526
struct resizable_string {
27+
using value_type = char;
2628
size_t size() const { return 0; }
2729
size_t capacity() const { return 0; }
2830
char& operator[](size_t) {
2931
static char c = '\0';
3032
return c;
3133
}
3234
void resize(size_t) { resize_call_count += 1; }
35+
void append(size_t, value_type) { append_call_count += 1; }
3336
void reserve(size_t) {}
37+
resizable_string& erase(size_t = 0, size_t = 0) { return *this; }
3438
};
3539

3640
int resize_default_init_call_count = 0;
41+
int append_default_init_call_count = 0;
3742

3843
// A mock string class whose only purpose is to track how many times its
39-
// resize() and __resize_default_init() methods have been called.
40-
struct resize_default_init_string {
44+
// resize()/__resize_default_init()/append()/__append_default_init() methods
45+
// have been called.
46+
struct default_init_string {
4147
size_t size() const { return 0; }
4248
size_t capacity() const { return 0; }
4349
char& operator[](size_t) {
@@ -46,46 +52,68 @@ struct resize_default_init_string {
4652
}
4753
void resize(size_t) { resize_call_count += 1; }
4854
void __resize_default_init(size_t) { resize_default_init_call_count += 1; }
55+
void __append_default_init(size_t) { append_default_init_call_count += 1; }
4956
void reserve(size_t) {}
57+
default_init_string& erase(size_t = 0, size_t = 0) { return *this; }
5058
};
5159

5260
TEST(ResizeUninit, WithAndWithout) {
5361
resize_call_count = 0;
62+
append_call_count = 0;
5463
resize_default_init_call_count = 0;
64+
append_default_init_call_count = 0;
5565
{
5666
resizable_string rs;
5767

5868
EXPECT_EQ(resize_call_count, 0);
69+
EXPECT_EQ(append_call_count, 0);
5970
EXPECT_EQ(resize_default_init_call_count, 0);
71+
EXPECT_EQ(append_default_init_call_count, 0);
6072
EXPECT_FALSE(
6173
absl::strings_internal::STLStringSupportsNontrashingResize(&rs));
6274
EXPECT_EQ(resize_call_count, 0);
75+
EXPECT_EQ(append_call_count, 0);
6376
EXPECT_EQ(resize_default_init_call_count, 0);
77+
EXPECT_EQ(append_default_init_call_count, 0);
6478
absl::strings_internal::STLStringResizeUninitialized(&rs, 237);
6579
EXPECT_EQ(resize_call_count, 1);
80+
EXPECT_EQ(append_call_count, 0);
6681
EXPECT_EQ(resize_default_init_call_count, 0);
82+
EXPECT_EQ(append_default_init_call_count, 0);
6783
absl::strings_internal::STLStringResizeUninitializedAmortized(&rs, 1000);
68-
EXPECT_EQ(resize_call_count, 2);
84+
EXPECT_EQ(resize_call_count, 1);
85+
EXPECT_EQ(append_call_count, 1);
6986
EXPECT_EQ(resize_default_init_call_count, 0);
87+
EXPECT_EQ(append_default_init_call_count, 0);
7088
}
7189

7290
resize_call_count = 0;
91+
append_call_count = 0;
7392
resize_default_init_call_count = 0;
93+
append_default_init_call_count = 0;
7494
{
75-
resize_default_init_string rus;
95+
default_init_string rus;
7696

7797
EXPECT_EQ(resize_call_count, 0);
98+
EXPECT_EQ(append_call_count, 0);
7899
EXPECT_EQ(resize_default_init_call_count, 0);
100+
EXPECT_EQ(append_default_init_call_count, 0);
79101
EXPECT_TRUE(
80102
absl::strings_internal::STLStringSupportsNontrashingResize(&rus));
81103
EXPECT_EQ(resize_call_count, 0);
104+
EXPECT_EQ(append_call_count, 0);
82105
EXPECT_EQ(resize_default_init_call_count, 0);
106+
EXPECT_EQ(append_default_init_call_count, 0);
83107
absl::strings_internal::STLStringResizeUninitialized(&rus, 237);
84108
EXPECT_EQ(resize_call_count, 0);
109+
EXPECT_EQ(append_call_count, 0);
85110
EXPECT_EQ(resize_default_init_call_count, 1);
111+
EXPECT_EQ(append_default_init_call_count, 0);
86112
absl::strings_internal::STLStringResizeUninitializedAmortized(&rus, 1000);
87113
EXPECT_EQ(resize_call_count, 0);
88-
EXPECT_EQ(resize_default_init_call_count, 2);
114+
EXPECT_EQ(append_call_count, 0);
115+
EXPECT_EQ(resize_default_init_call_count, 1);
116+
EXPECT_EQ(append_default_init_call_count, 1);
89117
}
90118
}
91119

0 commit comments

Comments
 (0)