- 3a9532fb2d6ae45c3cba44c9bb0dbdfc1558b7d3 Fix the description of Span::subspan(). by Abseil Team <absl-team@google.com>
- bae1a1c21924bd31fa7315eff05ea6158d9e7947 Port the symbolizer to Windows. by Derek Mauro <dmauro@google.com> - 2253c04c1a4f39d9581772f1dc4491878aa3831f Support absl::Hex() and absl::Dec() as arguments to absl:... by Jorg Brown <jorg@google.com> - 552c3ac259e9c254fda9244755487f3423d2fe4b Internal change by Jorg Brown <jorg@google.com> GitOrigin-RevId: 3a9532fb2d6ae45c3cba44c9bb0dbdfc1558b7d3 Change-Id: I448133c9bb6d837037c12b45a9a16a7945049453
This commit is contained in:
		
							parent
							
								
									af7882601a
								
							
						
					
					
						commit
						19b3c95727
					
				
					 10 changed files with 223 additions and 26 deletions
				
			
		| 
						 | 
					@ -46,6 +46,7 @@ cc_library(
 | 
				
			||||||
        "symbolize.cc",
 | 
					        "symbolize.cc",
 | 
				
			||||||
        "symbolize_elf.inc",
 | 
					        "symbolize_elf.inc",
 | 
				
			||||||
        "symbolize_unimplemented.inc",
 | 
					        "symbolize_unimplemented.inc",
 | 
				
			||||||
 | 
					        "symbolize_win32.inc",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    hdrs = [
 | 
					    hdrs = [
 | 
				
			||||||
        "internal/symbolize.h",
 | 
					        "internal/symbolize.h",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,7 @@ list(APPEND SYMBOLIZE_SRC
 | 
				
			||||||
  "symbolize.cc"
 | 
					  "symbolize.cc"
 | 
				
			||||||
  "symbolize_elf.inc"
 | 
					  "symbolize_elf.inc"
 | 
				
			||||||
  "symbolize_unimplemented.inc"
 | 
					  "symbolize_unimplemented.inc"
 | 
				
			||||||
 | 
					  "symbolize_win32.inc"
 | 
				
			||||||
  "internal/demangle.cc"
 | 
					  "internal/demangle.cc"
 | 
				
			||||||
  ${DEBUGGING_PUBLIC_HEADERS}
 | 
					  ${DEBUGGING_PUBLIC_HEADERS}
 | 
				
			||||||
  ${DEBUGGING_INTERNAL_HEADERS}
 | 
					  ${DEBUGGING_INTERNAL_HEADERS}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,8 +14,15 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "absl/debugging/symbolize.h"
 | 
					#include "absl/debugging/symbolize.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
 | 
					#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE)
 | 
				
			||||||
#include "absl/debugging/symbolize_elf.inc"
 | 
					#include "absl/debugging/symbolize_elf.inc"
 | 
				
			||||||
 | 
					#elif defined(_WIN32) && defined(_DEBUG)
 | 
				
			||||||
 | 
					// The Windows Symbolizer only works in debug mode. Note that _DEBUG
 | 
				
			||||||
 | 
					// is the macro that defines whether or not MS C-Runtime debug info is
 | 
				
			||||||
 | 
					// available. Note that the PDB files containing the debug info must
 | 
				
			||||||
 | 
					// also be available to the program at runtime for the symbolizer to
 | 
				
			||||||
 | 
					// work.
 | 
				
			||||||
 | 
					#include "absl/debugging/symbolize_win32.inc"
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#include "absl/debugging/symbolize_unimplemented.inc"
 | 
					#include "absl/debugging/symbolize_unimplemented.inc"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,8 +90,6 @@ static constexpr size_t kHpageSize = 1 << 21;
 | 
				
			||||||
const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
 | 
					const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
 | 
				
			||||||
    ".text") = "";
 | 
					    ".text") = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static char try_symbolize_buffer[4096];
 | 
					static char try_symbolize_buffer[4096];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A wrapper function for absl::Symbolize() to make the unit test simple.  The
 | 
					// A wrapper function for absl::Symbolize() to make the unit test simple.  The
 | 
				
			||||||
| 
						 | 
					@ -120,6 +118,8 @@ static const char *TrySymbolize(void *pc) {
 | 
				
			||||||
  return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
 | 
					  return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(Symbolize, Cached) {
 | 
					TEST(Symbolize, Cached) {
 | 
				
			||||||
  // Compilers should give us pointers to them.
 | 
					  // Compilers should give us pointers to them.
 | 
				
			||||||
  EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
 | 
					  EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
 | 
				
			||||||
| 
						 | 
					@ -442,6 +442,45 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(_WIN32) && defined(_DEBUG)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(Symbolize, Basics) {
 | 
				
			||||||
 | 
					  EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The name of an internal linkage symbol is not specified; allow either a
 | 
				
			||||||
 | 
					  // mangled or an unmangled name here.
 | 
				
			||||||
 | 
					  const char* static_func_symbol = TrySymbolize((void *)(&static_func));
 | 
				
			||||||
 | 
					  ASSERT_TRUE(static_func_symbol != nullptr);
 | 
				
			||||||
 | 
					  EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(Symbolize, Truncation) {
 | 
				
			||||||
 | 
					  constexpr char kNonStaticFunc[] = "nonstatic_func";
 | 
				
			||||||
 | 
					  EXPECT_STREQ("nonstatic_func",
 | 
				
			||||||
 | 
					               TrySymbolizeWithLimit((void *)(&nonstatic_func),
 | 
				
			||||||
 | 
					                                     strlen(kNonStaticFunc) + 1));
 | 
				
			||||||
 | 
					  EXPECT_STREQ("nonstatic_...",
 | 
				
			||||||
 | 
					               TrySymbolizeWithLimit((void *)(&nonstatic_func),
 | 
				
			||||||
 | 
					                                     strlen(kNonStaticFunc) + 0));
 | 
				
			||||||
 | 
					  EXPECT_STREQ("nonstatic...",
 | 
				
			||||||
 | 
					               TrySymbolizeWithLimit((void *)(&nonstatic_func),
 | 
				
			||||||
 | 
					                                     strlen(kNonStaticFunc) - 1));
 | 
				
			||||||
 | 
					  EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5));
 | 
				
			||||||
 | 
					  EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4));
 | 
				
			||||||
 | 
					  EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3));
 | 
				
			||||||
 | 
					  EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2));
 | 
				
			||||||
 | 
					  EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1));
 | 
				
			||||||
 | 
					  EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(Symbolize, SymbolizeWithDemangling) {
 | 
				
			||||||
 | 
					  const char* result = TrySymbolize((void *)(&Foo::func));
 | 
				
			||||||
 | 
					  ASSERT_TRUE(result != nullptr);
 | 
				
			||||||
 | 
					  EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else  // Symbolizer unimplemented
 | 
					#else  // Symbolizer unimplemented
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(Symbolize, Unimplemented) {
 | 
					TEST(Symbolize, Unimplemented) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										74
									
								
								absl/debugging/symbolize_win32.inc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								absl/debugging/symbolize_win32.inc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,74 @@
 | 
				
			||||||
 | 
					// Copyright 2018 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
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//      http://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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// See "Retrieving Symbol Information by Address":
 | 
				
			||||||
 | 
					// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <windows.h>
 | 
				
			||||||
 | 
					#include <DbgHelp.h>
 | 
				
			||||||
 | 
					#pragma comment(lib, "DbgHelp")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "absl/base/internal/raw_logging.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace absl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static HANDLE process = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InitializeSymbolizer(const char *argv0) {
 | 
				
			||||||
 | 
					  if (process != nullptr) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  process = GetCurrentProcess();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Symbols are not loaded until a reference is made requiring the
 | 
				
			||||||
 | 
					  // symbols be loaded. This is the fastest, most efficient way to use
 | 
				
			||||||
 | 
					  // the symbol handler.
 | 
				
			||||||
 | 
					  SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
 | 
				
			||||||
 | 
					  if (!SymInitialize(process, nullptr, true)) {
 | 
				
			||||||
 | 
					    // GetLastError() returns a Win32 DWORD, but we assign to
 | 
				
			||||||
 | 
					    // unsigned long to simplify the ABSL_RAW_LOG case below.  The uniform
 | 
				
			||||||
 | 
					    // initialization guarantees this is not a narrowing conversion.
 | 
				
			||||||
 | 
					    const unsigned long long error{GetLastError()};  // NOLINT(runtime/int)
 | 
				
			||||||
 | 
					    ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Symbolize(const void *pc, char *out, int out_size) {
 | 
				
			||||||
 | 
					  if (out_size <= 0) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  std::aligned_storage<sizeof(SYMBOL_INFO) + MAX_SYM_NAME,
 | 
				
			||||||
 | 
					                       alignof(SYMBOL_INFO)>::type buf;
 | 
				
			||||||
 | 
					  SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(&buf);
 | 
				
			||||||
 | 
					  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
 | 
				
			||||||
 | 
					  symbol->MaxNameLen = MAX_SYM_NAME;
 | 
				
			||||||
 | 
					  if (!SymFromAddr(process, reinterpret_cast<DWORD64>(pc), nullptr, symbol)) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  strncpy(out, symbol->Name, out_size);
 | 
				
			||||||
 | 
					  if (out[out_size - 1] != '\0') {
 | 
				
			||||||
 | 
					    // strncpy() does not '\0' terminate when it truncates.
 | 
				
			||||||
 | 
					    static constexpr char kEllipsis[] = "...";
 | 
				
			||||||
 | 
					    int ellipsis_size =
 | 
				
			||||||
 | 
					        std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
 | 
				
			||||||
 | 
					    memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
 | 
				
			||||||
 | 
					    out[out_size - 1] = '\0';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace absl
 | 
				
			||||||
| 
						 | 
					@ -94,6 +94,7 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format,
 | 
				
			||||||
  assert(target == output->data() + output->size());
 | 
					  assert(target == output->data() + output->size());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char kHexDigits[] = "0123456789abcdef";
 | 
				
			||||||
Arg::Arg(const void* value) {
 | 
					Arg::Arg(const void* value) {
 | 
				
			||||||
  static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
 | 
					  static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
 | 
				
			||||||
                "fix sizeof(scratch_)");
 | 
					                "fix sizeof(scratch_)");
 | 
				
			||||||
| 
						 | 
					@ -102,7 +103,6 @@ Arg::Arg(const void* value) {
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    char* ptr = scratch_ + sizeof(scratch_);
 | 
					    char* ptr = scratch_ + sizeof(scratch_);
 | 
				
			||||||
    uintptr_t num = reinterpret_cast<uintptr_t>(value);
 | 
					    uintptr_t num = reinterpret_cast<uintptr_t>(value);
 | 
				
			||||||
    static const char kHexDigits[] = "0123456789abcdef";
 | 
					 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
      *--ptr = kHexDigits[num & 0xf];
 | 
					      *--ptr = kHexDigits[num & 0xf];
 | 
				
			||||||
      num >>= 4;
 | 
					      num >>= 4;
 | 
				
			||||||
| 
						 | 
					@ -113,5 +113,58 @@ Arg::Arg(const void* value) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
 | 
				
			||||||
 | 
					Arg::Arg(Hex hex) {
 | 
				
			||||||
 | 
					  char* const end = &scratch_[numbers_internal::kFastToBufferSize];
 | 
				
			||||||
 | 
					  char* writer = end;
 | 
				
			||||||
 | 
					  uint64_t value = hex.value;
 | 
				
			||||||
 | 
					  do {
 | 
				
			||||||
 | 
					    *--writer = kHexDigits[value & 0xF];
 | 
				
			||||||
 | 
					    value >>= 4;
 | 
				
			||||||
 | 
					  } while (value != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  char* beg;
 | 
				
			||||||
 | 
					  if (end - writer < hex.width) {
 | 
				
			||||||
 | 
					    beg = end - hex.width;
 | 
				
			||||||
 | 
					    std::fill_n(beg, writer - beg, hex.fill);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    beg = writer;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  piece_ = absl::string_view(beg, end - beg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
 | 
				
			||||||
 | 
					Arg::Arg(Dec dec) {
 | 
				
			||||||
 | 
					  assert(dec.width <= numbers_internal::kFastToBufferSize);
 | 
				
			||||||
 | 
					  char* const end = &scratch_[numbers_internal::kFastToBufferSize];
 | 
				
			||||||
 | 
					  char* const minfill = end - dec.width;
 | 
				
			||||||
 | 
					  char* writer = end;
 | 
				
			||||||
 | 
					  uint64_t value = dec.value;
 | 
				
			||||||
 | 
					  bool neg = dec.neg;
 | 
				
			||||||
 | 
					  while (value > 9) {
 | 
				
			||||||
 | 
					    *--writer = '0' + (value % 10);
 | 
				
			||||||
 | 
					    value /= 10;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  *--writer = '0' + value;
 | 
				
			||||||
 | 
					  if (neg) *--writer = '-';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ptrdiff_t fillers = writer - minfill;
 | 
				
			||||||
 | 
					  if (fillers > 0) {
 | 
				
			||||||
 | 
					    // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
 | 
				
			||||||
 | 
					    // But...: if the fill character is '0', then it's <+/-><fill><digits>
 | 
				
			||||||
 | 
					    bool add_sign_again = false;
 | 
				
			||||||
 | 
					    if (neg && dec.fill == '0') {  // If filling with '0',
 | 
				
			||||||
 | 
					      ++writer;                    // ignore the sign we just added
 | 
				
			||||||
 | 
					      add_sign_again = true;       // and re-add the sign later.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    writer -= fillers;
 | 
				
			||||||
 | 
					    std::fill_n(writer, fillers, dec.fill);
 | 
				
			||||||
 | 
					    if (add_sign_again) *--writer = '-';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  piece_ = absl::string_view(writer, end - writer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace substitute_internal
 | 
					}  // namespace substitute_internal
 | 
				
			||||||
}  // namespace absl
 | 
					}  // namespace absl
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@
 | 
				
			||||||
#include "absl/strings/ascii.h"
 | 
					#include "absl/strings/ascii.h"
 | 
				
			||||||
#include "absl/strings/escaping.h"
 | 
					#include "absl/strings/escaping.h"
 | 
				
			||||||
#include "absl/strings/numbers.h"
 | 
					#include "absl/strings/numbers.h"
 | 
				
			||||||
#include "absl/strings/str_join.h"
 | 
					#include "absl/strings/str_cat.h"
 | 
				
			||||||
#include "absl/strings/str_split.h"
 | 
					#include "absl/strings/str_split.h"
 | 
				
			||||||
#include "absl/strings/string_view.h"
 | 
					#include "absl/strings/string_view.h"
 | 
				
			||||||
#include "absl/strings/strip.h"
 | 
					#include "absl/strings/strip.h"
 | 
				
			||||||
| 
						 | 
					@ -113,10 +113,10 @@ class Arg {
 | 
				
			||||||
  // what to do.
 | 
					  // what to do.
 | 
				
			||||||
  Arg(char value)  // NOLINT(runtime/explicit)
 | 
					  Arg(char value)  // NOLINT(runtime/explicit)
 | 
				
			||||||
      : piece_(scratch_, 1) { scratch_[0] = value; }
 | 
					      : piece_(scratch_, 1) { scratch_[0] = value; }
 | 
				
			||||||
  Arg(short value)  // NOLINT(runtime/explicit)
 | 
					  Arg(short value)  // NOLINT(*)
 | 
				
			||||||
      : piece_(scratch_,
 | 
					      : piece_(scratch_,
 | 
				
			||||||
               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
					               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
				
			||||||
  Arg(unsigned short value)  // NOLINT(runtime/explicit)
 | 
					  Arg(unsigned short value)  // NOLINT(*)
 | 
				
			||||||
      : piece_(scratch_,
 | 
					      : piece_(scratch_,
 | 
				
			||||||
               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
					               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
				
			||||||
  Arg(int value)  // NOLINT(runtime/explicit)
 | 
					  Arg(int value)  // NOLINT(runtime/explicit)
 | 
				
			||||||
| 
						 | 
					@ -125,16 +125,16 @@ class Arg {
 | 
				
			||||||
  Arg(unsigned int value)  // NOLINT(runtime/explicit)
 | 
					  Arg(unsigned int value)  // NOLINT(runtime/explicit)
 | 
				
			||||||
      : piece_(scratch_,
 | 
					      : piece_(scratch_,
 | 
				
			||||||
               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
					               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
				
			||||||
  Arg(long value)  // NOLINT(runtime/explicit)
 | 
					  Arg(long value)  // NOLINT(*)
 | 
				
			||||||
      : piece_(scratch_,
 | 
					      : piece_(scratch_,
 | 
				
			||||||
               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
					               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
				
			||||||
  Arg(unsigned long value)  // NOLINT(runtime/explicit)
 | 
					  Arg(unsigned long value)  // NOLINT(*)
 | 
				
			||||||
      : piece_(scratch_,
 | 
					      : piece_(scratch_,
 | 
				
			||||||
               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
					               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
				
			||||||
  Arg(long long value)  // NOLINT(runtime/explicit)
 | 
					  Arg(long long value)  // NOLINT(*)
 | 
				
			||||||
      : piece_(scratch_,
 | 
					      : piece_(scratch_,
 | 
				
			||||||
               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
					               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
				
			||||||
  Arg(unsigned long long value)  // NOLINT(runtime/explicit)
 | 
					  Arg(unsigned long long value)  // NOLINT(*)
 | 
				
			||||||
      : piece_(scratch_,
 | 
					      : piece_(scratch_,
 | 
				
			||||||
               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
					               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
 | 
				
			||||||
  Arg(float value)  // NOLINT(runtime/explicit)
 | 
					  Arg(float value)  // NOLINT(runtime/explicit)
 | 
				
			||||||
| 
						 | 
					@ -145,6 +145,10 @@ class Arg {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  Arg(bool value)  // NOLINT(runtime/explicit)
 | 
					  Arg(bool value)  // NOLINT(runtime/explicit)
 | 
				
			||||||
      : piece_(value ? "true" : "false") {}
 | 
					      : piece_(value ? "true" : "false") {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Arg(Hex hex);  // NOLINT(runtime/explicit)
 | 
				
			||||||
 | 
					  Arg(Dec dec);  // NOLINT(runtime/explicit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // `void*` values, with the exception of `char*`, are printed as
 | 
					  // `void*` values, with the exception of `char*`, are printed as
 | 
				
			||||||
  // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
 | 
					  // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
 | 
				
			||||||
  Arg(const void* value);  // NOLINT(runtime/explicit)
 | 
					  Arg(const void* value);  // NOLINT(runtime/explicit)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,24 @@ TEST(SubstituteTest, Substitute) {
 | 
				
			||||||
          -1234567890, 3234567890U, -1234567890L, 3234567890UL,
 | 
					          -1234567890, 3234567890U, -1234567890L, 3234567890UL,
 | 
				
			||||||
          -int64_t{1234567890123456789}, uint64_t{9234567890123456789u}));
 | 
					          -int64_t{1234567890123456789}, uint64_t{9234567890123456789u}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Hex format
 | 
				
			||||||
 | 
					  EXPECT_EQ("0 1 f ffff0ffff 0123456789abcdef",
 | 
				
			||||||
 | 
					            absl::Substitute("$0$1$2$3$4 $5",  //
 | 
				
			||||||
 | 
					                             absl::Hex(0), absl::Hex(1, absl::kSpacePad2),
 | 
				
			||||||
 | 
					                             absl::Hex(0xf, absl::kSpacePad2),
 | 
				
			||||||
 | 
					                             absl::Hex(int16_t{-1}, absl::kSpacePad5),
 | 
				
			||||||
 | 
					                             absl::Hex(int16_t{-1}, absl::kZeroPad5),
 | 
				
			||||||
 | 
					                             absl::Hex(0x123456789abcdef, absl::kZeroPad16)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Dec format
 | 
				
			||||||
 | 
					  EXPECT_EQ("0 115   -1-0001 81985529216486895",
 | 
				
			||||||
 | 
					            absl::Substitute("$0$1$2$3$4 $5",  //
 | 
				
			||||||
 | 
					                             absl::Dec(0), absl::Dec(1, absl::kSpacePad2),
 | 
				
			||||||
 | 
					                             absl::Dec(0xf, absl::kSpacePad2),
 | 
				
			||||||
 | 
					                             absl::Dec(int16_t{-1}, absl::kSpacePad5),
 | 
				
			||||||
 | 
					                             absl::Dec(int16_t{-1}, absl::kZeroPad5),
 | 
				
			||||||
 | 
					                             absl::Dec(0x123456789abcdef, absl::kZeroPad16)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Pointer.
 | 
					  // Pointer.
 | 
				
			||||||
  const int* int_p = reinterpret_cast<const int*>(0x12345);
 | 
					  const int* int_p = reinterpret_cast<const int*>(0x12345);
 | 
				
			||||||
  std::string str = absl::Substitute("$0", int_p);
 | 
					  std::string str = absl::Substitute("$0", int_p);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -458,10 +458,20 @@ class Span {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Span::subspan()
 | 
					  // Span::subspan()
 | 
				
			||||||
  //
 | 
					  //
 | 
				
			||||||
  // Returns a `Span` starting at element `pos` and of length `len`, with
 | 
					  // Returns a `Span` starting at element `pos` and of length `len`. Both `pos`
 | 
				
			||||||
  // proper bounds checking to ensure `len` does not exceed the ptr+size of the
 | 
					  // and `len` are of type `size_type` and thus non-negative. Parameter `pos`
 | 
				
			||||||
  // original array. (Spans whose `len` would point past the end of the array
 | 
					  // must be <= size(). Any `len` value that points past the end of the span
 | 
				
			||||||
  // will throw a `std::out_of_range`.)
 | 
					  // will be trimmed to at most size() - `pos`. A default `len` value of `npos`
 | 
				
			||||||
 | 
					  // ensures the returned subspan continues until the end of the span.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Examples:
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  //   std::vector<int> vec = {10, 11, 12, 13};
 | 
				
			||||||
 | 
					  //   absl::MakeSpan(vec).subspan(1, 2);  // {11, 12}
 | 
				
			||||||
 | 
					  //   absl::MakeSpan(vec).subspan(2, 8);  // {12, 13}
 | 
				
			||||||
 | 
					  //   absl::MakeSpan(vec).subspan(1);     // {11, 12, 13}
 | 
				
			||||||
 | 
					  //   absl::MakeSpan(vec).subspan(4);     // {}
 | 
				
			||||||
 | 
					  //   absl::MakeSpan(vec).subspan(5);     // throws std::out_of_range
 | 
				
			||||||
  constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
 | 
					  constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
 | 
				
			||||||
    return (pos <= len_)
 | 
					    return (pos <= len_)
 | 
				
			||||||
               ? Span(ptr_ + pos, span_internal::Min(len_ - pos, len))
 | 
					               ? Span(ptr_ + pos, span_internal::Min(len_ - pos, len))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,19 +119,9 @@ struct ConversionException {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <class T>
 | 
					template <class T>
 | 
				
			||||||
struct ExceptionOnConversion {
 | 
					struct ExceptionOnConversion {
 | 
				
			||||||
  // Suppress MSVC 2017 warning "noreturn function has a non-void return type".
 | 
					  operator T() const {  // NOLINT(runtime/explicit)
 | 
				
			||||||
#ifdef _MSC_VER
 | 
					 | 
				
			||||||
#pragma warning(push)
 | 
					 | 
				
			||||||
#pragma warning(disable : 4646)
 | 
					 | 
				
			||||||
#endif  // _MSC_VER
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [[noreturn]] operator T() const {  // NOLINT(runtime/explicit)
 | 
					 | 
				
			||||||
    throw ConversionException();
 | 
					    throw ConversionException();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef _MSC_VER
 | 
					 | 
				
			||||||
#pragma warning(pop)
 | 
					 | 
				
			||||||
#endif  // _MSC_VER
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Forces a variant into the valueless by exception state.
 | 
					// Forces a variant into the valueless by exception state.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue