Files
abseil-cpp/absl/strings/internal/resize_uninitialized_test.cc
Derek Mauro fa3783ec81 Reimplement STLStringResizeUninitializedAmortized() using
StringResizeAndOverwriteImpl()

This change bridges the gap between the legacy uninitialized resize
behavior and the modern absl::StringResizeAndOverwrite(). The internal
StringResizeAndOverwriteImpl function is used directly because the
public Abseil API requires the buffer to be initialized, whereas these
legacy functions rely on the behavior of leaving it uninitialized
(which is technically UB but relied upon here).

This is part of the work to migrate away from these legacy
utilities.

PiperOrigin-RevId: 855779916
Change-Id: If22484048024eae8ddedd29ebb08e8884e0198a3
2026-01-13 10:18:30 -08:00

109 lines
3.5 KiB
C++

// Copyright 2017 The Abseil Authors.
//
// 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
//
// https://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.
#include "absl/strings/internal/resize_uninitialized.h"
#include <cstddef>
#include <limits>
#include "gtest/gtest.h"
namespace {
int resize_call_count = 0;
// A mock string class whose only purpose is to track how many times its
// resize() method has been called.
struct resizable_string {
using value_type = char;
using size_type = size_t;
size_t size() const { return 0; }
size_t capacity() const { return 0; }
char* data() { return buffer; }
char& operator[](size_t) { return buffer[0]; }
void resize(size_t) { resize_call_count += 1; }
void reserve(size_t) {}
resizable_string& erase(size_t = 0, size_t = 0) { return *this; }
size_t max_size() const { return std::numeric_limits<size_t>::max(); }
char buffer[1] = {};
};
int resize_default_init_call_count = 0;
// A mock string class whose only purpose is to track how many times its
// resize()/__resize_default_init() methods have been called.
struct default_init_string {
using value_type = char;
using size_type = size_t;
size_t size() const { return 0; }
size_t capacity() const { return 0; }
char* data() { return buffer; }
char& operator[](size_t) { return buffer[0]; }
void resize(size_t) { resize_call_count += 1; }
void __resize_default_init(size_t) { resize_default_init_call_count += 1; }
void reserve(size_t) {}
default_init_string& erase(size_t = 0, size_t = 0) { return *this; }
size_t max_size() const { return std::numeric_limits<size_t>::max(); }
char buffer[1];
};
TEST(ResizeUninit, WithAndWithout) {
resize_call_count = 0;
resize_default_init_call_count = 0;
{
resizable_string rs;
EXPECT_EQ(resize_call_count, 0);
EXPECT_EQ(resize_default_init_call_count, 0);
EXPECT_FALSE(
absl::strings_internal::STLStringSupportsNontrashingResize(&rs));
EXPECT_EQ(resize_call_count, 0);
EXPECT_EQ(resize_default_init_call_count, 0);
absl::strings_internal::STLStringResizeUninitialized(&rs, 237);
EXPECT_EQ(resize_call_count, 1);
EXPECT_EQ(resize_default_init_call_count, 0);
}
resize_call_count = 0;
resize_default_init_call_count = 0;
{
default_init_string rus;
EXPECT_EQ(resize_call_count, 0);
EXPECT_EQ(resize_default_init_call_count, 0);
EXPECT_TRUE(
absl::strings_internal::STLStringSupportsNontrashingResize(&rus));
EXPECT_EQ(resize_call_count, 0);
EXPECT_EQ(resize_default_init_call_count, 0);
absl::strings_internal::STLStringResizeUninitialized(&rus, 237);
EXPECT_EQ(resize_call_count, 0);
EXPECT_EQ(resize_default_init_call_count, 1);
}
}
TEST(ResizeUninit, Amortized) {
std::string str;
size_t prev_cap = str.capacity();
int cap_increase_count = 0;
for (int i = 0; i < 1000; ++i) {
absl::strings_internal::STLStringResizeUninitializedAmortized(&str, i);
size_t new_cap = str.capacity();
if (new_cap > prev_cap) ++cap_increase_count;
prev_cap = new_cap;
}
EXPECT_LT(cap_increase_count, 50);
}
} // namespace