mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
This associates debug information with the assertion sites, allowing clearer stack-traces for assertion failures and better accounting of the performance overhead of assertions. PiperOrigin-RevId: 910863016 Change-Id: Ic615a9eeb8ad4b3f8c035074df4ff8347190e5c7
199 lines
7.3 KiB
C++
199 lines
7.3 KiB
C++
// Copyright 2025 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.
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
// File: resize_and_overwrite.h
|
|
// -----------------------------------------------------------------------------
|
|
//
|
|
// This file contains a polyfill for C++23's
|
|
// std::basic_string<CharT,Traits,Allocator>::resize_and_overwrite
|
|
//
|
|
// The polyfill takes the form of a free function:
|
|
|
|
// template<typename T, typename Op>
|
|
// void StringResizeAndOverwrite(T& str, typename T::size_type count, Op op);
|
|
//
|
|
// This avoids the cost of initializing a suitably-sized std::string when it is
|
|
// intended to be used as a char array, for example, to be populated by a
|
|
// C-style API.
|
|
//
|
|
// Example usage:
|
|
//
|
|
// std::string IntToString(int n) {
|
|
// std::string result;
|
|
// constexpr size_t kMaxIntChars = 10;
|
|
// absl::StringResizeAndOverwrite(
|
|
// result, kMaxIntChars, [n](char* buffer, size_t buffer_size) {
|
|
// return snprintf(buffer, buffer_size, "%d", n);
|
|
// });
|
|
// return result;
|
|
// }
|
|
//
|
|
// https://en.cppreference.com/w/cpp/string/basic_string/resize_and_overwrite.html
|
|
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1072r10.html
|
|
|
|
#ifndef ABSL_STRINGS_RESIZE_AND_OVERWRITE_H_
|
|
#define ABSL_STRINGS_RESIZE_AND_OVERWRITE_H_
|
|
|
|
#include <cstddef>
|
|
#include <string> // IWYU pragma: keep
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include "absl/base/config.h"
|
|
#include "absl/base/dynamic_annotations.h"
|
|
#include "absl/base/internal/hardening.h"
|
|
#include "absl/base/macros.h"
|
|
#include "absl/base/optimization.h"
|
|
#include "absl/base/throw_delegate.h"
|
|
|
|
#if defined(__cpp_lib_string_resize_and_overwrite) && \
|
|
__cpp_lib_string_resize_and_overwrite >= 202110L
|
|
#define ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE 1
|
|
#endif
|
|
|
|
namespace absl {
|
|
ABSL_NAMESPACE_BEGIN
|
|
|
|
namespace strings_internal {
|
|
|
|
#ifndef ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE
|
|
|
|
inline size_t ProbeResizeAndOverwriteOp(char*, size_t) { return 0; }
|
|
|
|
// Prior to C++23, Google's libc++ backports resize_and_overwrite as
|
|
// __google_nonstandard_backport_resize_and_overwrite
|
|
template <typename T, typename = void>
|
|
struct has__google_nonstandard_backport_resize_and_overwrite : std::false_type {
|
|
};
|
|
|
|
template <typename T>
|
|
struct has__google_nonstandard_backport_resize_and_overwrite<
|
|
T,
|
|
std::void_t<
|
|
decltype(std::declval<T&>()
|
|
.__google_nonstandard_backport_resize_and_overwrite(
|
|
std::declval<size_t>(), ProbeResizeAndOverwriteOp))>>
|
|
: std::true_type {};
|
|
|
|
// Prior to C++23, the version of libstdc++ that shipped with GCC >= 14
|
|
// has __resize_and_overwrite.
|
|
template <typename T, typename = void>
|
|
struct has__resize_and_overwrite : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct has__resize_and_overwrite<
|
|
T, std::void_t<decltype(std::declval<T&>().__resize_and_overwrite(
|
|
std::declval<size_t>(), ProbeResizeAndOverwriteOp))>>
|
|
: std::true_type {};
|
|
|
|
// libc++ used __resize_default_init to achieve uninitialized string resizes
|
|
// before removing it September 2025, in favor of resize_and_overwrite.
|
|
// https://github.com/llvm/llvm-project/commit/92f5d8df361bb1bb6dea88f86faeedfd295ab970
|
|
template <typename T, typename = void>
|
|
struct has__resize_default_init : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct has__resize_default_init<
|
|
T, std::void_t<decltype(std::declval<T&>().__resize_default_init(42))>>
|
|
: std::true_type {};
|
|
|
|
// Prior to C++23, some versions of MSVC have _Resize_and_overwrite.
|
|
template <typename T, typename = void>
|
|
struct has_Resize_and_overwrite : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct has_Resize_and_overwrite<
|
|
T, std::void_t<decltype(std::declval<T&>()._Resize_and_overwrite(
|
|
std::declval<size_t>(), ProbeResizeAndOverwriteOp))>>
|
|
: std::true_type {};
|
|
|
|
#endif // ifndef ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE
|
|
|
|
// A less-efficient fallback implementation that uses resize().
|
|
template <typename T, typename Op>
|
|
void StringResizeAndOverwriteFallback(T& str, typename T::size_type n, Op op) {
|
|
if (ABSL_PREDICT_FALSE(n > str.max_size())) {
|
|
ThrowStdLengthError("absl::StringResizeAndOverwrite");
|
|
}
|
|
#ifdef ABSL_HAVE_MEMORY_SANITIZER
|
|
auto old_size = str.size();
|
|
#endif
|
|
str.resize(n);
|
|
#ifdef ABSL_HAVE_MEMORY_SANITIZER
|
|
if (old_size < n) {
|
|
ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(str.data() + old_size, n - old_size);
|
|
}
|
|
#endif
|
|
typename T::size_type new_size =
|
|
static_cast<typename T::size_type>(std::move(op)(str.data(), n));
|
|
absl::base_internal::HardeningAssertGE(new_size, typename T::size_type{0});
|
|
absl::base_internal::HardeningAssertLE(new_size, n);
|
|
absl::base_internal::HardeningAssert(str.data()[n] ==
|
|
typename T::value_type{});
|
|
str.erase(new_size);
|
|
}
|
|
|
|
template <typename T, typename Op>
|
|
void StringResizeAndOverwriteImpl(T& str, typename T::size_type n, Op op) {
|
|
#ifdef ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE
|
|
str.resize_and_overwrite(n, std::move(op));
|
|
#else
|
|
if constexpr (strings_internal::
|
|
has__google_nonstandard_backport_resize_and_overwrite<
|
|
T>::value) {
|
|
str.__google_nonstandard_backport_resize_and_overwrite(n, std::move(op));
|
|
} else if constexpr (strings_internal::has__resize_and_overwrite<T>::value) {
|
|
str.__resize_and_overwrite(n, std::move(op));
|
|
} else if constexpr (strings_internal::has__resize_default_init<T>::value) {
|
|
str.__resize_default_init(n);
|
|
str.__resize_default_init(
|
|
static_cast<typename T::size_type>(std::move(op)(str.data(), n)));
|
|
} else if constexpr (strings_internal::has_Resize_and_overwrite<T>::value) {
|
|
str._Resize_and_overwrite(n, std::move(op));
|
|
} else {
|
|
strings_internal::StringResizeAndOverwriteFallback(str, n, std::move(op));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
} // namespace strings_internal
|
|
|
|
// Resizes `str` to contain at most `n` characters, using the user-provided
|
|
// operation `op` to modify the possibly indeterminate contents. `op` must
|
|
// return the finalized length of `str`.
|
|
//
|
|
// Invalidates all iterators, pointers, and references into `str`, regardless
|
|
// of whether reallocation occurs.
|
|
//
|
|
// `op(value_type* buf, size_t buf_size)` is allowed to write `value_type{}` to
|
|
// `buf[buf_size]`, which facilitiates interoperation with functions that write
|
|
// a trailing NUL. Please note that this requirement is more strict than
|
|
// `basic_string::resize_and_overwrite()`, which allows writing an abitrary
|
|
// value to `buf[buf_size]`.
|
|
template <typename T, typename Op>
|
|
void StringResizeAndOverwrite(T& str, typename T::size_type n, Op op) {
|
|
strings_internal::StringResizeAndOverwriteImpl(str, n, std::move(op));
|
|
#if defined(ABSL_HAVE_MEMORY_SANITIZER)
|
|
__msan_check_mem_is_initialized(str.data(), str.size());
|
|
#endif
|
|
}
|
|
|
|
ABSL_NAMESPACE_END
|
|
} // namespace absl
|
|
|
|
#undef ABSL_INTERNAL_HAS_RESIZE_AND_OVERWRITE
|
|
|
|
#endif // ABSL_STRINGS_RESIZE_AND_OVERWRITE_H_
|