// Protocol Buffers - Google's data interchange format
// Copyright 2023 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
//
#include "google/protobuf/port.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include "absl/log/absl_log.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
// Must be included last
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace internal {
size_t StringSpaceUsedExcludingSelfLong(
const std::string& str) {
const void* start = &str;
const void* end = &str +
1;
if (start <= str.data() && str.data() < end) {
// The string's data is stored inside the string object itself.
return 0;
}
else {
return str.capacity() +
/* NULL terminator */ 1;
}
}
// protobuf_assumption_failed() is declared and used in port_def.inc to assert
// PROTOBUF_ASSUME conditions in debug mode. This function avoids having
// port_def.inc depend on assert.h or other headers, minimizing the compilation
// footprint.
void protobuf_assumption_failed(
const char* pred,
const char* file,
int line) {
fprintf(stderr,
"%s: %d: Assumption failed: '%s'\n", file, line, pred);
abort();
}
static void PrintAllCounters();
static auto& CounterMap() {
using Map = std::map<absl::string_view,
std::map<std::variant<int64_t, absl::string_view>,
std::vector<
const RealDebugCounter*>>>;
static auto* counter_map =
new Map{};
static bool dummy = std::atexit(PrintAllCounters);
(
void)dummy;
return *counter_map;
}
static void PrintAllCounters() {
auto& counters = CounterMap();
if (counters.empty())
return;
absl::FPrintF(stderr,
"Protobuf debug counters:\n");
for (
auto& [category_name, category_map] : counters) {
// Example output:
//
// Category :
// Value 1 : 1234 (12.34%)
// Value 2 : 2345 (23.45%)
// Total : 3579
absl::FPrintF(stderr,
" %-12s:\n", category_name);
size_t total =
0;
for (
auto& entry : category_map) {
for (
auto* counter : entry.second) {
total += counter->value();
}
}
for (
auto& [subname, counter_vector] : category_map) {
size_t value =
0;
for (
auto* counter : counter_vector) {
value += counter->value();
}
if (std::holds_alternative<int64_t>(subname)) {
// For integers, right align
absl::FPrintF(stderr,
" %9d : %10zu", std::get<int64_t>(subname),
value);
}
else {
// For strings, left align
absl::FPrintF(stderr,
" %-10s: %10zu",
std::get<absl::string_view>(subname), value);
}
if (total !=
0 && category_map.size() >
1) {
absl::FPrintF(
stderr,
" (%5.2f%%)",
100. * static_cast<
double>(value) / static_cast<
double>(total));
}
absl::FPrintF(stderr,
"\n");
}
if (total !=
0 && category_map.size() >
1) {
absl::FPrintF(stderr,
" %-10s: %10zu\n",
"Total", total);
}
}
}
void RealDebugCounter::
Register(absl::string_view name) {
std::pair<absl::string_view, absl::string_view> parts =
absl::StrSplit(name,
'.');
int64_t as_int;
if (absl::SimpleAtoi(parts.second, &as_int)) {
CounterMap()[parts.first][as_int].push_back(this);
}
else {
CounterMap()[parts.first][parts.second].push_back(this);
}
}
PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GlobalEmptyString
fixed_address_empty_string{};
void HandleAddOverflow(
int a,
int b) {
ABSL_LOG(FATAL) <<
"Integer overflow in CheckedAdd: " << a <<
" + " << b;
}
}
// namespace internal
}
// namespace protobuf
}
// namespace google
#include "google/protobuf/port_undef.inc"