forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PA] Add CStringBuilder to replace std::ostringstream used by LogMess…
…age. Since std::ostringstream allocates and deallocates memory from heap, c.f. https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:buildtools/third_party/libc++/trunk/src/ios.cpp std::ostringstream is not available inside memory allocation. Instead add CStringBuilder (not resize, fixed buffer size) for LogMessage. Change-Id: I8051978487acc5fc9b976d6085909b43f81d9d0d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4744311 Reviewed-by: Yuki Shiino <[email protected]> Commit-Queue: Takashi Sakamoto <[email protected]> Cr-Commit-Position: refs/heads/main@{#1179481}
- Loading branch information
Showing
5 changed files
with
421 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
216 changes: 216 additions & 0 deletions
216
base/allocator/partition_allocator/partition_alloc_base/strings/cstring_builder.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "base/allocator/partition_allocator/partition_alloc_base/strings/cstring_builder.h" | ||
|
||
#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h" | ||
#include "base/allocator/partition_allocator/partition_alloc_base/strings/safe_sprintf.h" | ||
#include "build/build_config.h" | ||
|
||
#if !BUILDFLAG(IS_WIN) | ||
#include <unistd.h> | ||
#endif | ||
|
||
#include <cmath> | ||
#include <cstring> | ||
|
||
#if BUILDFLAG(PA_DCHECK_IS_ON) | ||
#include "base/allocator/partition_allocator/partition_alloc_base/check.h" | ||
#define PA_RAW_DCHECK PA_RAW_CHECK | ||
#else | ||
#define PA_RAW_DCHECK(x) \ | ||
do { \ | ||
if (x) { \ | ||
} \ | ||
} while (0) | ||
#endif | ||
|
||
namespace partition_alloc::internal::base::strings { | ||
|
||
namespace { | ||
|
||
constexpr size_t kNumDigits10 = 5u; | ||
|
||
constexpr uint64_t Pow10(unsigned exp) { | ||
uint64_t ret = 1; | ||
for (unsigned i = 0; i < exp; ++i) { | ||
ret *= 10U; | ||
} | ||
return ret; | ||
} | ||
|
||
constexpr uint64_t Log10(uint64_t value) { | ||
uint64_t ret = 0; | ||
while (value != 0u) { | ||
value = value / 10u; | ||
++ret; | ||
} | ||
return ret; | ||
} | ||
|
||
constexpr uint64_t GetDigits10(unsigned num_digits10) { | ||
return Pow10(num_digits10); | ||
} | ||
|
||
} // namespace | ||
|
||
template <typename T> | ||
void CStringBuilder::PutInteger(T value) { | ||
// We need an array of chars whose size is: | ||
// - floor(log10(max value)) + 1 chars for the give value, and | ||
// - 1 char for '-' (if negative) | ||
// - 1 char for '\0' | ||
char buffer[Log10(std::numeric_limits<T>::max()) + 3]; | ||
ssize_t n = base::strings::SafeSPrintf(buffer, "%d", value); | ||
PA_RAW_DCHECK(n >= 0); | ||
PA_RAW_DCHECK(static_cast<size_t>(n) < sizeof(buffer)); | ||
PutText(buffer, n); | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(char ch) { | ||
PutText(&ch, 1); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(const char* text) { | ||
PutText(text); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(float value) { | ||
PutFloatingPoint(value, kNumDigits10); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(double value) { | ||
PutFloatingPoint(value, kNumDigits10); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(int value) { | ||
PutInteger(value); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(unsigned int value) { | ||
PutInteger(value); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(long value) { | ||
PutInteger(value); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(unsigned long value) { | ||
PutInteger(value); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(long long value) { | ||
PutInteger(value); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(unsigned long long value) { | ||
PutInteger(value); | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(const void* value) { | ||
if (!value) { | ||
PutText("(nil)"); | ||
} else { | ||
// We need an array of chars whose size is: | ||
// - 2 chars per 1 byte(00-FF), totally sizeof(const void*) * 2 chars, | ||
// - 2 chars for "0x", | ||
// - 1 char for '\0', | ||
char buffer[sizeof(const void*) * 2 + 2 + 1]; | ||
ssize_t n = base::strings::SafeSPrintf(buffer, "%p", value); | ||
PA_RAW_DCHECK(n > 0); | ||
PA_RAW_DCHECK(static_cast<size_t>(n) < sizeof(buffer)); | ||
PutText(buffer, n); | ||
} | ||
return *this; | ||
} | ||
|
||
CStringBuilder& CStringBuilder::operator<<(std::nullptr_t) { | ||
PutText("nullptr"); | ||
return *this; | ||
} | ||
|
||
const char* CStringBuilder::c_str() { | ||
PA_RAW_DCHECK(buffer_ <= ptr_ && ptr_ < buffer_ + kBufferSize); | ||
if (*ptr_ != '\0') { | ||
*ptr_ = '\0'; | ||
} | ||
return buffer_; | ||
} | ||
|
||
void CStringBuilder::PutFloatingPoint(double value, unsigned num_digits10) { | ||
switch (fpclassify(value)) { | ||
case FP_INFINITE: | ||
PutText(value < 0 ? "-inf" : "inf"); | ||
break; | ||
case FP_NAN: | ||
PutText("NaN"); | ||
break; | ||
case FP_ZERO: | ||
PutText("0"); | ||
break; | ||
case FP_SUBNORMAL: | ||
// Denormalized values are not supported. | ||
PutNormalFloatingPoint(value > 0 ? std::numeric_limits<double>::min() | ||
: -std::numeric_limits<double>::min(), | ||
num_digits10); | ||
break; | ||
case FP_NORMAL: | ||
default: | ||
PutNormalFloatingPoint(value, num_digits10); | ||
break; | ||
} | ||
} | ||
|
||
void CStringBuilder::PutNormalFloatingPoint(double value, | ||
unsigned num_digits10) { | ||
if (value < 0) { | ||
PutText("-", 1); | ||
value = -value; | ||
} | ||
|
||
int exponent = floor(log10(value)); | ||
double significand = value / pow(10, exponent); | ||
|
||
char buffer[64]; | ||
ssize_t n = base::strings::SafeSPrintf( | ||
buffer, "%d", lrint(significand * GetDigits10(num_digits10))); | ||
PA_RAW_DCHECK(n > 0); | ||
PA_RAW_DCHECK(static_cast<size_t>(n) < sizeof(buffer)); | ||
PutText(buffer, 1); | ||
if (n > 1) { | ||
PutText(".", 1); | ||
PutText(buffer + 1, n - 1); | ||
} | ||
if (exponent != 0) { | ||
n = base::strings::SafeSPrintf(buffer, "e%s%d", exponent > 0 ? "+" : "", | ||
exponent); | ||
PA_RAW_DCHECK(n > 0); | ||
PA_RAW_DCHECK(static_cast<size_t>(n) < sizeof(buffer)); | ||
PutText(buffer, n); | ||
} | ||
} | ||
|
||
void CStringBuilder::PutText(const char* text) { | ||
PutText(text, strlen(text)); | ||
} | ||
|
||
void CStringBuilder::PutText(const char* text, size_t length) { | ||
PA_RAW_DCHECK(buffer_ <= ptr_ && ptr_ < buffer_ + kBufferSize); | ||
while (ptr_ < buffer_ + kBufferSize - 1 && length > 0 && *text != '\0') { | ||
*ptr_++ = *text++; | ||
--length; | ||
} | ||
} | ||
|
||
} // namespace partition_alloc::internal::base::strings |
57 changes: 57 additions & 0 deletions
57
base/allocator/partition_allocator/partition_alloc_base/strings/cstring_builder.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_STRINGS_CSTRING_BUILDER_H_ | ||
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_STRINGS_CSTRING_BUILDER_H_ | ||
|
||
#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h" | ||
#include "build/build_config.h" | ||
|
||
#include <cstddef> | ||
|
||
#if !BUILDFLAG(IS_WIN) | ||
#include <unistd.h> | ||
#endif | ||
|
||
namespace partition_alloc::internal::base::strings { | ||
|
||
// Similar to std::ostringstream, but creates a C string, i.e. nul-terminated | ||
// char-type string, instead of std::string. To use inside memory allocation, | ||
// this method must not allocate any memory with malloc, aligned_malloc, | ||
// calloc, and so on. | ||
class PA_COMPONENT_EXPORT(PARTITION_ALLOC) CStringBuilder { | ||
public: | ||
static constexpr size_t kBufferSize = 1024u; | ||
|
||
CStringBuilder() : ptr_(buffer_) {} | ||
|
||
CStringBuilder& operator<<(char ch); | ||
CStringBuilder& operator<<(const char* text); | ||
CStringBuilder& operator<<(float value); | ||
CStringBuilder& operator<<(double value); | ||
CStringBuilder& operator<<(int value); | ||
CStringBuilder& operator<<(unsigned int value); | ||
CStringBuilder& operator<<(long value); | ||
CStringBuilder& operator<<(unsigned long value); | ||
CStringBuilder& operator<<(long long value); | ||
CStringBuilder& operator<<(unsigned long long value); | ||
CStringBuilder& operator<<(const void* value); | ||
CStringBuilder& operator<<(std::nullptr_t); | ||
const char* c_str(); | ||
|
||
private: | ||
template <typename T> | ||
void PutInteger(T value); | ||
void PutFloatingPoint(double value, unsigned num_digits10); | ||
void PutNormalFloatingPoint(double value, unsigned num_digits10); | ||
void PutText(const char* text); | ||
void PutText(const char* text, size_t length); | ||
|
||
char buffer_[kBufferSize]; | ||
char* ptr_; | ||
}; | ||
|
||
} // namespace partition_alloc::internal::base::strings | ||
|
||
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_STRINGS_CSTRING_BUILDER_H_ |
Oops, something went wrong.