mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1287426 Part 3: Update security/sandbox/chromium/ to commit 4ec79b7f2379a60cdc15599e93255c0fa417f1ed. r=aklotz, r=jld
MozReview-Commit-ID: 14eHMsYZznA
This commit is contained in:
parent
add3717103
commit
d453628509
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1289951 maybe needed a clobber to fix xpcshell tests?
|
||||
Bug 1287426 - Clobber required because of Linux Chromium sandbox file moves.
|
||||
|
19
security/sandbox/chromium-shim/base/debug/debugging_flags.h
Normal file
19
security/sandbox/chromium-shim/base/debug/debugging_flags.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a copy of a file that is generated by the chromium build.
|
||||
|
||||
// Generated by build/write_buildflag_header.py
|
||||
// From "//base:debugging_flags"
|
||||
|
||||
#ifndef BASE_DEBUG_DEBUGGING_FLAGS_H_
|
||||
#define BASE_DEBUG_DEBUGGING_FLAGS_H_
|
||||
|
||||
#include "build/buildflag.h"
|
||||
|
||||
#define BUILDFLAG_INTERNAL_ENABLE_PROFILING() (0)
|
||||
|
||||
#endif // BASE_DEBUG_DEBUGGING_FLAGS_H_
|
29
security/sandbox/chromium-shim/base/file_version_info_win.h
Normal file
29
security/sandbox/chromium-shim/base/file_version_info_win.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a dummy version of Chromium source file base/file_version_info_win.h
|
||||
// Within our copy of Chromium files FileVersionInfoWin is only used in
|
||||
// base/win/windows_version.cc in GetVersionFromKernel32, which we don't use.
|
||||
|
||||
#ifndef BASE_FILE_VERSION_INFO_WIN_H_
|
||||
#define BASE_FILE_VERSION_INFO_WIN_H_
|
||||
|
||||
struct tagVS_FIXEDFILEINFO;
|
||||
typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
class FileVersionInfoWin {
|
||||
public:
|
||||
static FileVersionInfoWin*
|
||||
CreateFileVersionInfo(const base::FilePath& file_path) { return nullptr; }
|
||||
|
||||
VS_FIXEDFILEINFO* fixed_file_info() { return nullptr; }
|
||||
};
|
||||
|
||||
#endif // BASE_FILE_VERSION_INFO_WIN_H_
|
19
security/sandbox/chromium-shim/base/files/file_path.cpp
Normal file
19
security/sandbox/chromium-shim/base/files/file_path.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This is a dummy version of Chromium source file base/file/file_path.cc.
|
||||
// To provide the functions required in base/win/windows_version.cc
|
||||
// GetVersionFromKernel32, which we don't use.
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
FilePath::FilePath(FilePath::StringPieceType path) {
|
||||
}
|
||||
|
||||
FilePath::~FilePath() {
|
||||
}
|
||||
|
||||
} // namespace base
|
@ -26,16 +26,41 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace logging {
|
||||
|
||||
namespace {
|
||||
|
||||
int min_log_level = 0;
|
||||
int g_min_log_level = 0;
|
||||
|
||||
LoggingDestination g_logging_destination = LOG_DEFAULT;
|
||||
|
||||
// For LOG_ERROR and above, always print to stderr.
|
||||
const int kAlwaysPrintErrorLevel = LOG_ERROR;
|
||||
|
||||
// A log message handler that gets notified of every log message we process.
|
||||
LogMessageHandlerFunction log_message_handler = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
void SetMinLogLevel(int level) {
|
||||
g_min_log_level = std::min(LOG_FATAL, level);
|
||||
}
|
||||
|
||||
int GetMinLogLevel() {
|
||||
return min_log_level;
|
||||
return g_min_log_level;
|
||||
}
|
||||
|
||||
bool ShouldCreateLogMessage(int severity) {
|
||||
if (severity < g_min_log_level)
|
||||
return false;
|
||||
|
||||
// Return true here unless we know ~LogMessage won't do anything. Note that
|
||||
// ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even
|
||||
// when g_logging_destination is LOG_NONE.
|
||||
return g_logging_destination != LOG_NONE || log_message_handler ||
|
||||
severity >= kAlwaysPrintErrorLevel;
|
||||
}
|
||||
|
||||
int GetVlogLevelHelper(const char* file, size_t N) {
|
||||
@ -67,6 +92,10 @@ LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
|
||||
: severity_(severity), file_(file), line_(line) {
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, const char* condition)
|
||||
: severity_(LOG_FATAL), file_(file), line_(line) {
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, std::string* result)
|
||||
: severity_(LOG_FATAL), file_(file), line_(line) {
|
||||
delete result;
|
||||
|
@ -48,6 +48,24 @@ typedef LPSTARTUPINFOEXA LPSTARTUPINFOEX;
|
||||
#define PROCESS_DEP_ENABLE 0x00000001
|
||||
#define PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION 0x00000002
|
||||
|
||||
// They dynamically load these, but they still use the functions to describe the
|
||||
// function pointers!
|
||||
WINBASEAPI
|
||||
int
|
||||
WINAPI
|
||||
GetUserDefaultLocaleName(
|
||||
_Out_writes_(cchLocaleName) LPWSTR lpLocaleName,
|
||||
_In_ int cchLocaleName
|
||||
);
|
||||
|
||||
WINBASEAPI
|
||||
BOOL
|
||||
WINAPI
|
||||
QueryThreadCycleTime(
|
||||
_In_ HANDLE ThreadHandle,
|
||||
_Out_ PULONG64 CycleTime
|
||||
);
|
||||
|
||||
#endif // (_WIN32_WINNT >= 0x0600)
|
||||
|
||||
#if (_WIN32_WINNT < 0x0601)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include <stack>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
|
||||
namespace base {
|
||||
|
@ -4,9 +4,6 @@
|
||||
|
||||
// This is a low level implementation of atomic semantics for reference
|
||||
// counting. Please use base/memory/ref_counted.h directly instead.
|
||||
//
|
||||
// The implementation includes annotations to avoid some false positives
|
||||
// when using data race detection tools.
|
||||
|
||||
#ifndef BASE_ATOMIC_REF_COUNT_H_
|
||||
#define BASE_ATOMIC_REF_COUNT_H_
|
||||
|
@ -6,7 +6,7 @@
|
||||
#define BASE_ATOMIC_SEQUENCE_NUM_H_
|
||||
|
||||
#include "base/atomicops.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/macros.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
|
@ -28,10 +28,14 @@
|
||||
#ifndef BASE_ATOMICOPS_H_
|
||||
#define BASE_ATOMICOPS_H_
|
||||
|
||||
#include <cassert> // Small C++ header which defines implementation specific
|
||||
// macros used to identify the STL implementation.
|
||||
#include <stdint.h>
|
||||
|
||||
// Small C++ header which defines implementation specific macros used to
|
||||
// identify the STL implementation.
|
||||
// - libc++: captures __config for _LIBCPP_VERSION
|
||||
// - libstdc++: captures bits/c++config.h for __GLIBCXX__
|
||||
#include <cstddef>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
@ -140,65 +144,13 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
|
||||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
// The following x86 CPU features are used in atomicops_internals_x86_gcc.h, but
|
||||
// this file is duplicated inside of Chrome: protobuf and tcmalloc rely on the
|
||||
// struct being present at link time. Some parts of Chrome can currently use the
|
||||
// portable interface whereas others still use GCC one. The include guards are
|
||||
// the same as in atomicops_internals_x86_gcc.cc.
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
// This struct is not part of the public API of this module; clients may not
|
||||
// use it. (However, it's exported via BASE_EXPORT because clients implicitly
|
||||
// do use it at link time by inlining these functions.)
|
||||
// Features of this x86. Values may not be correct before main() is run,
|
||||
// but are set conservatively.
|
||||
struct AtomicOps_x86CPUFeatureStruct {
|
||||
bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
|
||||
// after acquire compare-and-swap.
|
||||
// The following fields are unused by Chrome's base implementation but are
|
||||
// still used by copies of the same code in other parts of the code base. This
|
||||
// causes an ODR violation, and the other code is likely reading invalid
|
||||
// memory.
|
||||
// TODO(jfb) Delete these fields once the rest of the Chrome code base doesn't
|
||||
// depend on them.
|
||||
bool has_sse2; // Processor has SSE2.
|
||||
bool has_cmpxchg16b; // Processor supports cmpxchg16b instruction.
|
||||
};
|
||||
BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
|
||||
AtomicOps_Internalx86CPUFeatures;
|
||||
#endif
|
||||
|
||||
// Try to use a portable implementation based on C++11 atomics.
|
||||
//
|
||||
// Some toolchains support C++11 language features without supporting library
|
||||
// features (recent compiler, older STL). Whitelist libstdc++ and libc++ that we
|
||||
// know will have <atomic> when compiling C++11.
|
||||
#if ((__cplusplus >= 201103L) && \
|
||||
((defined(__GLIBCXX__) && (__GLIBCXX__ > 20110216)) || \
|
||||
(defined(_LIBCPP_VERSION) && (_LIBCPP_STD_VER >= 11))))
|
||||
# include "base/atomicops_internals_portable.h"
|
||||
#else // Otherwise use a platform specific implementation.
|
||||
# if defined(THREAD_SANITIZER)
|
||||
# error "Thread sanitizer must use the portable atomic operations"
|
||||
# elif (defined(OS_WIN) && defined(COMPILER_MSVC) && \
|
||||
defined(ARCH_CPU_X86_FAMILY))
|
||||
#if defined(OS_WIN)
|
||||
// TODO(jfb): The MSVC header includes windows.h, which other files end up
|
||||
// relying on. Fix this as part of crbug.com/559247.
|
||||
# include "base/atomicops_internals_x86_msvc.h"
|
||||
# elif defined(OS_MACOSX)
|
||||
# include "base/atomicops_internals_mac.h"
|
||||
# elif defined(OS_NACL)
|
||||
# include "base/atomicops_internals_gcc.h"
|
||||
# elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARMEL)
|
||||
# include "base/atomicops_internals_arm_gcc.h"
|
||||
# elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM64)
|
||||
# include "base/atomicops_internals_arm64_gcc.h"
|
||||
# elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
|
||||
# include "base/atomicops_internals_x86_gcc.h"
|
||||
# elif (defined(COMPILER_GCC) && \
|
||||
(defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY)))
|
||||
# include "base/atomicops_internals_mips_gcc.h"
|
||||
# else
|
||||
# error "Atomic operations are not supported on your platform"
|
||||
# endif
|
||||
#endif // Portable / non-portable includes.
|
||||
#else
|
||||
# include "base/atomicops_internals_portable.h"
|
||||
#endif
|
||||
|
||||
// On some platforms we need additional declarations to make
|
||||
// AtomicWord compatible with our other Atomic* types.
|
||||
|
@ -1,294 +0,0 @@
|
||||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file is an internal atomic implementation, use base/atomicops.h instead.
|
||||
//
|
||||
// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
|
||||
|
||||
#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
||||
#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
||||
|
||||
#if defined(OS_QNX)
|
||||
#include <sys/cpuinline.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
// Memory barriers on ARM are funky, but the kernel is here to help:
|
||||
//
|
||||
// * ARMv5 didn't support SMP, there is no memory barrier instruction at
|
||||
// all on this architecture, or when targeting its machine code.
|
||||
//
|
||||
// * Some ARMv6 CPUs support SMP. A full memory barrier can be produced by
|
||||
// writing a random value to a very specific coprocessor register.
|
||||
//
|
||||
// * On ARMv7, the "dmb" instruction is used to perform a full memory
|
||||
// barrier (though writing to the co-processor will still work).
|
||||
// However, on single core devices (e.g. Nexus One, or Nexus S),
|
||||
// this instruction will take up to 200 ns, which is huge, even though
|
||||
// it's completely un-needed on these devices.
|
||||
//
|
||||
// * There is no easy way to determine at runtime if the device is
|
||||
// single or multi-core. However, the kernel provides a useful helper
|
||||
// function at a fixed memory address (0xffff0fa0), which will always
|
||||
// perform a memory barrier in the most efficient way. I.e. on single
|
||||
// core devices, this is an empty function that exits immediately.
|
||||
// On multi-core devices, it implements a full memory barrier.
|
||||
//
|
||||
// * This source could be compiled to ARMv5 machine code that runs on a
|
||||
// multi-core ARMv6 or ARMv7 device. In this case, memory barriers
|
||||
// are needed for correct execution. Always call the kernel helper, even
|
||||
// when targeting ARMv5TE.
|
||||
//
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
// Note: This is a function call, which is also an implicit compiler barrier.
|
||||
typedef void (*KernelMemoryBarrierFunc)();
|
||||
((KernelMemoryBarrierFunc)0xffff0fa0)();
|
||||
#elif defined(OS_QNX)
|
||||
__cpu_membarrier();
|
||||
#else
|
||||
#error MemoryBarrier() is not implemented on this platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
// An ARM toolchain would only define one of these depending on which
|
||||
// variant of the target architecture is being used. This tests against
|
||||
// any known ARMv6 or ARMv7 variant, where it is possible to directly
|
||||
// use ldrex/strex instructions to implement fast atomic operations.
|
||||
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
|
||||
defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || \
|
||||
defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
|
||||
defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
|
||||
defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value;
|
||||
int reloop;
|
||||
do {
|
||||
// The following is equivalent to:
|
||||
//
|
||||
// prev_value = LDREX(ptr)
|
||||
// reloop = 0
|
||||
// if (prev_value != old_value)
|
||||
// reloop = STREX(ptr, new_value)
|
||||
__asm__ __volatile__(" ldrex %0, [%3]\n"
|
||||
" mov %1, #0\n"
|
||||
" cmp %0, %4\n"
|
||||
#ifdef __thumb2__
|
||||
" it eq\n"
|
||||
#endif
|
||||
" strexeq %1, %5, [%3]\n"
|
||||
: "=&r"(prev_value), "=&r"(reloop), "+m"(*ptr)
|
||||
: "r"(ptr), "r"(old_value), "r"(new_value)
|
||||
: "cc", "memory");
|
||||
} while (reloop != 0);
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 result = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
MemoryBarrier();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
MemoryBarrier();
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 value;
|
||||
int reloop;
|
||||
do {
|
||||
// Equivalent to:
|
||||
//
|
||||
// value = LDREX(ptr)
|
||||
// value += increment
|
||||
// reloop = STREX(ptr, value)
|
||||
//
|
||||
__asm__ __volatile__(" ldrex %0, [%3]\n"
|
||||
" add %0, %0, %4\n"
|
||||
" strex %1, %0, [%3]\n"
|
||||
: "=&r"(value), "=&r"(reloop), "+m"(*ptr)
|
||||
: "r"(ptr), "r"(increment)
|
||||
: "cc", "memory");
|
||||
} while (reloop);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
// TODO(digit): Investigate if it's possible to implement this with
|
||||
// a single MemoryBarrier() operation between the LDREX and STREX.
|
||||
// See http://crbug.com/246514
|
||||
MemoryBarrier();
|
||||
Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
|
||||
MemoryBarrier();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 old_value;
|
||||
int reloop;
|
||||
do {
|
||||
// old_value = LDREX(ptr)
|
||||
// reloop = STREX(ptr, new_value)
|
||||
__asm__ __volatile__(" ldrex %0, [%3]\n"
|
||||
" strex %1, %4, [%3]\n"
|
||||
: "=&r"(old_value), "=&r"(reloop), "+m"(*ptr)
|
||||
: "r"(ptr), "r"(new_value)
|
||||
: "cc", "memory");
|
||||
} while (reloop != 0);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
// This tests against any known ARMv5 variant.
|
||||
#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
|
||||
defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
|
||||
|
||||
// The kernel also provides a helper function to perform an atomic
|
||||
// compare-and-swap operation at the hard-wired address 0xffff0fc0.
|
||||
// On ARMv5, this is implemented by a special code path that the kernel
|
||||
// detects and treats specially when thread pre-emption happens.
|
||||
// On ARMv6 and higher, it uses LDREX/STREX instructions instead.
|
||||
//
|
||||
// Note that this always perform a full memory barrier, there is no
|
||||
// need to add calls MemoryBarrier() before or after it. It also
|
||||
// returns 0 on success, and 1 on exit.
|
||||
//
|
||||
// Available and reliable since Linux 2.6.24. Both Android and ChromeOS
|
||||
// use newer kernel revisions, so this should not be a concern.
|
||||
namespace {
|
||||
|
||||
inline int LinuxKernelCmpxchg(Atomic32 old_value,
|
||||
Atomic32 new_value,
|
||||
volatile Atomic32* ptr) {
|
||||
typedef int (*KernelCmpxchgFunc)(Atomic32, Atomic32, volatile Atomic32*);
|
||||
return ((KernelCmpxchgFunc)0xffff0fc0)(old_value, new_value, ptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value;
|
||||
for (;;) {
|
||||
prev_value = *ptr;
|
||||
if (prev_value != old_value)
|
||||
return prev_value;
|
||||
if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
|
||||
return old_value;
|
||||
}
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 old_value;
|
||||
do {
|
||||
old_value = *ptr;
|
||||
} while (LinuxKernelCmpxchg(old_value, new_value, ptr));
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
for (;;) {
|
||||
// Atomic exchange the old value with an incremented one.
|
||||
Atomic32 old_value = *ptr;
|
||||
Atomic32 new_value = old_value + increment;
|
||||
if (!LinuxKernelCmpxchg(old_value, new_value, ptr)) {
|
||||
// The exchange took place as expected.
|
||||
return new_value;
|
||||
}
|
||||
// Otherwise, *ptr changed mid-loop and we need to retry.
|
||||
}
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value;
|
||||
for (;;) {
|
||||
prev_value = *ptr;
|
||||
if (prev_value != old_value) {
|
||||
// Always ensure acquire semantics.
|
||||
MemoryBarrier();
|
||||
return prev_value;
|
||||
}
|
||||
if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
|
||||
return old_value;
|
||||
}
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
// This could be implemented as:
|
||||
// MemoryBarrier();
|
||||
// return NoBarrier_CompareAndSwap();
|
||||
//
|
||||
// But would use 3 barriers per succesful CAS. To save performance,
|
||||
// use Acquire_CompareAndSwap(). Its implementation guarantees that:
|
||||
// - A succesful swap uses only 2 barriers (in the kernel helper).
|
||||
// - An early return due to (prev_value != old_value) performs
|
||||
// a memory barrier with no store, which is equivalent to the
|
||||
// generic implementation above.
|
||||
return Acquire_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
#else
|
||||
# error "Your CPU's ARM architecture is not supported yet"
|
||||
#endif
|
||||
|
||||
// NOTE: Atomicity of the following load and store operations is only
|
||||
// guaranteed in case of 32-bit alignement of |ptr| values.
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; }
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
} // namespace base::subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
@ -34,6 +34,8 @@
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
@ -221,7 +223,7 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
}
|
||||
|
||||
#endif // defined(ARCH_CPU_64_BITS)
|
||||
}
|
||||
} // namespace base::subtle
|
||||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
|
||||
|
@ -1,228 +0,0 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file is an internal atomic implementation, use base/atomicops.h instead.
|
||||
|
||||
#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|
||||
#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|
||||
|
||||
#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
// 32-bit low-level operations on any platform.
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev;
|
||||
__asm__ __volatile__("lock; cmpxchgl %1,%2"
|
||||
: "=a" (prev)
|
||||
: "q" (new_value), "m" (*ptr), "0" (old_value)
|
||||
: "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
__asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg.
|
||||
: "=r" (new_value)
|
||||
: "m" (*ptr), "0" (new_value)
|
||||
: "memory");
|
||||
return new_value; // Now it's the previous value.
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddl %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now holds the old value of *ptr
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddl %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now holds the old value of *ptr
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
__asm__ __volatile__("mfence" : : : "memory");
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
*ptr = value; // An x86 store acts as a release barrier.
|
||||
// See comments in Atomic64 version of Release_Store(), below.
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
|
||||
// See comments in Atomic64 version of Release_Store(), below.
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
// 64-bit low-level operations on 64-bit platform.
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 prev;
|
||||
__asm__ __volatile__("lock; cmpxchgq %1,%2"
|
||||
: "=a" (prev)
|
||||
: "q" (new_value), "m" (*ptr), "0" (old_value)
|
||||
: "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
|
||||
Atomic64 new_value) {
|
||||
__asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg.
|
||||
: "=r" (new_value)
|
||||
: "m" (*ptr), "0" (new_value)
|
||||
: "memory");
|
||||
return new_value; // Now it's the previous value.
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
Atomic64 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddq %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now contains the previous value of *ptr
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
Atomic64 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddq %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now contains the previous value of *ptr
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
|
||||
*ptr = value; // An x86 store acts as a release barrier
|
||||
// for current AMD/Intel chips as of Jan 2008.
|
||||
// See also Acquire_Load(), below.
|
||||
|
||||
// When new chips come out, check:
|
||||
// IA-32 Intel Architecture Software Developer's Manual, Volume 3:
|
||||
// System Programming Guide, Chatper 7: Multiple-processor management,
|
||||
// Section 7.2, Memory Ordering.
|
||||
// Last seen at:
|
||||
// http://developer.intel.com/design/pentium4/manuals/index_new.htm
|
||||
//
|
||||
// x86 stores/loads fail to act as barriers for a few instructions (clflush
|
||||
// maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
|
||||
// not generated by the compiler, and are rare. Users of these instructions
|
||||
// need to know about cache behaviour in any case since all of these involve
|
||||
// either flushing cache lines or non-temporal cache hints.
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
|
||||
// for current AMD/Intel chips as of Jan 2008.
|
||||
// See also Release_Store(), above.
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
#endif // defined(__x86_64__)
|
||||
|
||||
} // namespace base::subtle
|
||||
} // namespace base
|
||||
|
||||
#undef ATOMICOPS_COMPILER_BARRIER
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|
@ -12,6 +12,7 @@
|
||||
#include <intrin.h>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
// windows.h #defines this (only on x64). This causes problems because the
|
||||
@ -55,9 +56,6 @@ inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
|
||||
#error "We require at least vs2005 for MemoryBarrier"
|
||||
#endif
|
||||
inline void MemoryBarrier() {
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
// See #undef and note at the top of this file.
|
||||
@ -112,7 +110,7 @@ inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
|
||||
// 64-bit low-level operations on 64-bit platform.
|
||||
|
||||
COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
|
||||
static_assert(sizeof(Atomic64) == sizeof(PVOID), "atomic word is atomic");
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
@ -192,7 +190,7 @@ inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
|
||||
#endif // defined(_WIN64)
|
||||
|
||||
} // namespace base::subtle
|
||||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
|
||||
|
@ -10,25 +10,20 @@
|
||||
|
||||
#if defined(BASE_IMPLEMENTATION)
|
||||
#define BASE_EXPORT __declspec(dllexport)
|
||||
#define BASE_EXPORT_PRIVATE __declspec(dllexport)
|
||||
#else
|
||||
#define BASE_EXPORT __declspec(dllimport)
|
||||
#define BASE_EXPORT_PRIVATE __declspec(dllimport)
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
|
||||
#else // defined(WIN32)
|
||||
#if defined(BASE_IMPLEMENTATION)
|
||||
#define BASE_EXPORT __attribute__((visibility("default")))
|
||||
#define BASE_EXPORT_PRIVATE __attribute__((visibility("default")))
|
||||
#else
|
||||
#define BASE_EXPORT
|
||||
#define BASE_EXPORT_PRIVATE
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
#endif
|
||||
|
||||
#else // defined(COMPONENT_BUILD)
|
||||
#define BASE_EXPORT
|
||||
#define BASE_EXPORT_PRIVATE
|
||||
#endif
|
||||
|
||||
#endif // BASE_BASE_EXPORT_H_
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_BASE_PATHS_WIN_H__
|
||||
#define BASE_BASE_PATHS_WIN_H__
|
||||
#ifndef BASE_BASE_PATHS_WIN_H_
|
||||
#define BASE_BASE_PATHS_WIN_H_
|
||||
|
||||
// This file declares windows-specific path keys for the base module.
|
||||
// These can be used with the PathService to access various special
|
||||
@ -16,8 +16,14 @@ enum {
|
||||
|
||||
DIR_WINDOWS, // Windows directory, usually "c:\windows"
|
||||
DIR_SYSTEM, // Usually c:\windows\system32"
|
||||
DIR_PROGRAM_FILES, // Usually c:\program files
|
||||
DIR_PROGRAM_FILESX86, // Usually c:\program files or c:\program files (x86)
|
||||
// 32-bit 32-bit on 64-bit 64-bit on 64-bit
|
||||
// DIR_PROGRAM_FILES 1 2 1
|
||||
// DIR_PROGRAM_FILESX86 1 2 2
|
||||
// DIR_PROGRAM_FILES6432 1 1 1
|
||||
// 1 - C:\Program Files 2 - C:\Program Files (x86)
|
||||
DIR_PROGRAM_FILES, // See table above.
|
||||
DIR_PROGRAM_FILESX86, // See table above.
|
||||
DIR_PROGRAM_FILES6432, // See table above.
|
||||
|
||||
DIR_IE_INTERNET_CACHE, // Temporary Internet Files directory.
|
||||
DIR_COMMON_START_MENU, // Usually "C:\Documents and Settings\All Users\
|
||||
@ -36,8 +42,8 @@ enum {
|
||||
DIR_COMMON_DESKTOP, // Directory for the common desktop (visible
|
||||
// on all user's Desktop).
|
||||
DIR_USER_QUICK_LAUNCH, // Directory for the quick launch shortcuts.
|
||||
DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar via
|
||||
// base::win::TaskbarPinShortcutLink().
|
||||
DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar
|
||||
// (Win7-8) via base::win::PinShortcutToTaskbar().
|
||||
DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts.
|
||||
|
||||
PATH_WIN_END
|
||||
@ -45,4 +51,4 @@ enum {
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BASE_PATHS_WIN_H__
|
||||
#endif // BASE_BASE_PATHS_WIN_H_
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/base_switches.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace switches {
|
||||
|
||||
@ -14,13 +15,29 @@ const char kDisableBreakpad[] = "disable-breakpad";
|
||||
// generated internally.
|
||||
const char kEnableCrashReporter[] = "enable-crash-reporter";
|
||||
|
||||
// Makes memory allocators keep track of their allocations and context, so a
|
||||
// detailed breakdown of memory usage can be presented in chrome://tracing when
|
||||
// the memory-infra category is enabled.
|
||||
const char kEnableHeapProfiling[] = "enable-heap-profiling";
|
||||
|
||||
// Generates full memory crash dump.
|
||||
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
|
||||
|
||||
// Force low-end device when set to 1;
|
||||
// Auto-detect low-end device when set to 2;
|
||||
// Force non-low-end device when set to other values or empty;
|
||||
const char kLowEndDeviceMode[] = "low-end-device-mode";
|
||||
// Force low-end device mode when set.
|
||||
const char kEnableLowEndDeviceMode[] = "enable-low-end-device-mode";
|
||||
|
||||
// Force disabling of low-end device mode when set.
|
||||
const char kDisableLowEndDeviceMode[] = "disable-low-end-device-mode";
|
||||
|
||||
// This option can be used to force field trials when testing changes locally.
|
||||
// The argument is a list of name and value pairs, separated by slashes. If a
|
||||
// trial name is prefixed with an asterisk, that trial will start activated.
|
||||
// For example, the following argument defines two trials, with the second one
|
||||
// activated: "GoogleNow/Enable/*MaterialDesignNTP/Default/" This option can
|
||||
// also be used by the browser process to send the list of trials to a
|
||||
// non-browser process, using the same format. See
|
||||
// FieldTrialList::CreateTrialsFromString() in field_trial.h for details.
|
||||
const char kForceFieldTrials[] = "force-fieldtrials";
|
||||
|
||||
// Suppresses all error dialogs when present.
|
||||
const char kNoErrorDialogs[] = "noerrdialogs";
|
||||
@ -47,9 +64,6 @@ const char kVModule[] = "vmodule";
|
||||
// Will wait for 60 seconds for a debugger to come to attach to the process.
|
||||
const char kWaitForDebugger[] = "wait-for-debugger";
|
||||
|
||||
// Sends a pretty-printed version of tracing info to the console.
|
||||
const char kTraceToConsole[] = "trace-to-console";
|
||||
|
||||
// Sends trace events from these categories to a file.
|
||||
// --trace-to-file on its own sends to default categories.
|
||||
const char kTraceToFile[] = "trace-to-file";
|
||||
@ -66,6 +80,11 @@ const char kProfilerTiming[] = "profiler-timing";
|
||||
// chrome://profiler.
|
||||
const char kProfilerTimingDisabledValue[] = "0";
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Disables the USB keyboard detection for blocking the OSK on Win8+.
|
||||
const char kDisableUsbKeyboardDetect[] = "disable-usb-keyboard-detect";
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// Used for turning on Breakpad crash reporting in a debug environment where
|
||||
// crash reporting is typically compiled but disabled.
|
||||
|
@ -12,20 +12,26 @@
|
||||
namespace switches {
|
||||
|
||||
extern const char kDisableBreakpad[];
|
||||
extern const char kDisableLowEndDeviceMode[];
|
||||
extern const char kEnableCrashReporter[];
|
||||
extern const char kEnableHeapProfiling[];
|
||||
extern const char kEnableLowEndDeviceMode[];
|
||||
extern const char kForceFieldTrials[];
|
||||
extern const char kFullMemoryCrashReport[];
|
||||
extern const char kLowEndDeviceMode[];
|
||||
extern const char kNoErrorDialogs[];
|
||||
extern const char kProfilerTiming[];
|
||||
extern const char kProfilerTimingDisabledValue[];
|
||||
extern const char kTestChildProcess[];
|
||||
extern const char kTraceToConsole[];
|
||||
extern const char kTraceToFile[];
|
||||
extern const char kTraceToFileName[];
|
||||
extern const char kV[];
|
||||
extern const char kVModule[];
|
||||
extern const char kWaitForDebugger[];
|
||||
|
||||
#if defined(OS_WIN)
|
||||
extern const char kDisableUsbKeyboardDetect[];
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
extern const char kEnableCrashReporterForTesting[];
|
||||
#endif
|
||||
|
@ -1,45 +0,0 @@
|
||||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file contains definitions of our old basic integral types
|
||||
// ((u)int{8,16,32,64}) and further includes. I recommend that you use the C99
|
||||
// standard types instead, and include <stdint.h>/<stddef.h>/etc. as needed.
|
||||
// Note that the macros and macro-like constructs that were formerly defined in
|
||||
// this file are now available separately in base/macros.h.
|
||||
|
||||
#ifndef BASE_BASICTYPES_H_
|
||||
#define BASE_BASICTYPES_H_
|
||||
|
||||
#include <limits.h> // So we can set the bounds of our types.
|
||||
#include <stddef.h> // For size_t.
|
||||
#include <stdint.h> // For intptr_t.
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/port.h" // Types that only need exist on certain systems.
|
||||
|
||||
// DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
|
||||
typedef int8_t int8;
|
||||
typedef uint8_t uint8;
|
||||
typedef int16_t int16;
|
||||
typedef uint16_t uint16;
|
||||
typedef int32_t int32;
|
||||
typedef uint32_t uint32;
|
||||
typedef int64_t int64;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
// DEPRECATED: Please use std::numeric_limits (from <limits>) instead.
|
||||
const uint8 kuint8max = 0xFF;
|
||||
const uint16 kuint16max = 0xFFFF;
|
||||
const uint32 kuint32max = 0xFFFFFFFF;
|
||||
const uint64 kuint64max = 0xFFFFFFFFFFFFFFFFULL;
|
||||
const int8 kint8min = -0x7F - 1;
|
||||
const int8 kint8max = 0x7F;
|
||||
const int16 kint16min = -0x7FFF - 1;
|
||||
const int16 kint16max = 0x7FFF;
|
||||
const int32 kint32min = -0x7FFFFFFF - 1;
|
||||
const int32 kint32max = 0x7FFFFFFF;
|
||||
const int64 kint64min = -0x7FFFFFFFFFFFFFFFLL - 1;
|
||||
const int64 kint64max = 0x7FFFFFFFFFFFFFFFLL;
|
||||
|
||||
#endif // BASE_BASICTYPES_H_
|
@ -1,8 +1,3 @@
|
||||
// This file was GENERATED by command:
|
||||
// pump.py bind.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
@ -46,464 +41,59 @@
|
||||
//
|
||||
// TODO(ajwong): We might be able to avoid this now, but need to test.
|
||||
//
|
||||
// It is possible to move most of the COMPILE_ASSERT asserts into BindState<>,
|
||||
// but it feels a little nicer to have the asserts here so people do not
|
||||
// need to crack open bind_internal.h. On the other hand, it makes Bind()
|
||||
// harder to read.
|
||||
// It is possible to move most of the static_assert into BindState<>, but it
|
||||
// feels a little nicer to have the asserts here so people do not need to crack
|
||||
// open bind_internal.h. On the other hand, it makes Bind() harder to read.
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Functor>
|
||||
template <typename Functor, typename... Args>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void()>
|
||||
typename internal::CallbackParamTraits<Args>::StorageType...>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
typedef internal::BindState<RunnableType, RunType, void()> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor)));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
Bind(Functor functor, const Args&... args) {
|
||||
// Type aliases for how to store and run the functor.
|
||||
using RunnableType = typename internal::FunctorTraits<Functor>::RunnableType;
|
||||
using RunType = typename internal::FunctorTraits<Functor>::RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// checks below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
using BoundRunType = typename RunnableType::RunType;
|
||||
|
||||
using BoundArgs =
|
||||
internal::TakeTypeListItem<sizeof...(Args),
|
||||
internal::ExtractArgs<BoundRunType>>;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
static_assert(!internal::HasNonConstReferenceItem<BoundArgs>::value,
|
||||
"do not bind functions with nonconst ref");
|
||||
|
||||
const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType)> BindState;
|
||||
static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value,
|
||||
"first bound argument to method cannot be array");
|
||||
static_assert(
|
||||
!internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value,
|
||||
"a parameter is a refcounted type and needs scoped_refptr");
|
||||
|
||||
using BindState = internal::BindState<
|
||||
RunnableType, RunType,
|
||||
typename internal::CallbackParamTraits<Args>::StorageType...>;
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
|
||||
typename P5>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
|
||||
const P5& p5) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
|
||||
p5_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
|
||||
typename P5, typename P6>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
|
||||
const P5& p5, const P6& p6) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
|
||||
p5_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
|
||||
p6_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
|
||||
typename P5, typename P6, typename P7>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType,
|
||||
typename internal::CallbackParamTraits<P7>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
|
||||
const P5& p5, const P6& p6, const P7& p7) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A7Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
|
||||
p5_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
|
||||
p6_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P7>::value,
|
||||
p7_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType,
|
||||
typename internal::CallbackParamTraits<P7>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6,
|
||||
p7));
|
||||
new BindState(internal::MakeRunnable(functor), args...));
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
@ -111,7 +111,7 @@
|
||||
// scoped_ptr<Foo> f(new Foo());
|
||||
//
|
||||
// // |cb| is given ownership of Foo(). |f| is now NULL.
|
||||
// // You can use f.Pass() in place of &f, but it's more verbose.
|
||||
// // You can use std::move(f) in place of &f, but it's more verbose.
|
||||
// Closure cb = Bind(&TakesOwnership, Passed(&f));
|
||||
//
|
||||
// // Run was never called so |cb| still owns Foo() and deletes
|
||||
@ -129,7 +129,7 @@
|
||||
// Passed() is particularly useful with PostTask() when you are transferring
|
||||
// ownership of an argument into a task, but don't necessarily know if the
|
||||
// task will always be executed. This can happen if the task is cancellable
|
||||
// or if it is posted to a MessageLoopProxy.
|
||||
// or if it is posted to a TaskRunner.
|
||||
//
|
||||
//
|
||||
// SIMPLE FUNCTIONS AND UTILITIES.
|
||||
@ -143,10 +143,15 @@
|
||||
#ifndef BASE_BIND_HELPERS_H_
|
||||
#define BASE_BIND_HELPERS_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/template_util.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
@ -185,7 +190,7 @@ namespace internal {
|
||||
// want to probe for. Then we create a class Base that inherits from both T
|
||||
// (the class we wish to probe) and BaseMixin. Note that the function
|
||||
// signature in BaseMixin does not need to match the signature of the function
|
||||
// we are probing for; thus it's easiest to just use void(void).
|
||||
// we are probing for; thus it's easiest to just use void().
|
||||
//
|
||||
// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
|
||||
// ambiguous resolution between BaseMixin and T. This lets us write the
|
||||
@ -222,8 +227,8 @@ namespace internal {
|
||||
// See http://crbug.com/82038.
|
||||
template <typename T>
|
||||
class SupportsAddRefAndRelease {
|
||||
typedef char Yes[1];
|
||||
typedef char No[2];
|
||||
using Yes = char[1];
|
||||
using No = char[2];
|
||||
|
||||
struct BaseMixin {
|
||||
void AddRef();
|
||||
@ -242,7 +247,7 @@ class SupportsAddRefAndRelease {
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <void(BaseMixin::*)(void)> struct Helper {};
|
||||
template <void(BaseMixin::*)()> struct Helper {};
|
||||
|
||||
template <typename C>
|
||||
static No& Check(Helper<&C::AddRef>*);
|
||||
@ -276,8 +281,8 @@ struct UnsafeBindtoRefCountedArg<T*>
|
||||
|
||||
template <typename T>
|
||||
class HasIsMethodTag {
|
||||
typedef char Yes[1];
|
||||
typedef char No[2];
|
||||
using Yes = char[1];
|
||||
using No = char[2];
|
||||
|
||||
template <typename U>
|
||||
static Yes& Check(typename U::IsMethod*);
|
||||
@ -359,22 +364,24 @@ class OwnedWrapper {
|
||||
// created when we are explicitly trying to do a destructive move.
|
||||
//
|
||||
// Two notes:
|
||||
// 1) PassedWrapper supports any type that has a "Pass()" function.
|
||||
// This is intentional. The whitelisting of which specific types we
|
||||
// support is maintained by CallbackParamTraits<>.
|
||||
// 1) PassedWrapper supports any type that has a move constructor, however
|
||||
// the type will need to be specifically whitelisted in order for it to be
|
||||
// bound to a Callback. We guard this explicitly at the call of Passed()
|
||||
// to make for clear errors. Things not given to Passed() will be forwarded
|
||||
// and stored by value which will not work for general move-only types.
|
||||
// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
|
||||
// scoper to a Callback and allow the Callback to execute once.
|
||||
template <typename T>
|
||||
class PassedWrapper {
|
||||
public:
|
||||
explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
|
||||
explicit PassedWrapper(T&& scoper)
|
||||
: is_valid_(true), scoper_(std::move(scoper)) {}
|
||||
PassedWrapper(const PassedWrapper& other)
|
||||
: is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
|
||||
}
|
||||
: is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
|
||||
T Pass() const {
|
||||
CHECK(is_valid_);
|
||||
is_valid_ = false;
|
||||
return scoper_.Pass();
|
||||
return std::move(scoper_);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -385,13 +392,13 @@ class PassedWrapper {
|
||||
// Unwrap the stored parameters for the wrappers above.
|
||||
template <typename T>
|
||||
struct UnwrapTraits {
|
||||
typedef const T& ForwardType;
|
||||
using ForwardType = const T&;
|
||||
static ForwardType Unwrap(const T& o) { return o; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<UnretainedWrapper<T> > {
|
||||
typedef T* ForwardType;
|
||||
using ForwardType = T*;
|
||||
static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
|
||||
return unretained.get();
|
||||
}
|
||||
@ -399,7 +406,7 @@ struct UnwrapTraits<UnretainedWrapper<T> > {
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<ConstRefWrapper<T> > {
|
||||
typedef const T& ForwardType;
|
||||
using ForwardType = const T&;
|
||||
static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
|
||||
return const_ref.get();
|
||||
}
|
||||
@ -407,19 +414,19 @@ struct UnwrapTraits<ConstRefWrapper<T> > {
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<scoped_refptr<T> > {
|
||||
typedef T* ForwardType;
|
||||
using ForwardType = T*;
|
||||
static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<WeakPtr<T> > {
|
||||
typedef const WeakPtr<T>& ForwardType;
|
||||
using ForwardType = const WeakPtr<T>&;
|
||||
static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<OwnedWrapper<T> > {
|
||||
typedef T* ForwardType;
|
||||
using ForwardType = T*;
|
||||
static ForwardType Unwrap(const OwnedWrapper<T>& o) {
|
||||
return o.get();
|
||||
}
|
||||
@ -427,7 +434,7 @@ struct UnwrapTraits<OwnedWrapper<T> > {
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<PassedWrapper<T> > {
|
||||
typedef T ForwardType;
|
||||
using ForwardType = T;
|
||||
static T Unwrap(PassedWrapper<T>& o) {
|
||||
return o.Pass();
|
||||
}
|
||||
@ -435,45 +442,46 @@ struct UnwrapTraits<PassedWrapper<T> > {
|
||||
|
||||
// Utility for handling different refcounting semantics in the Bind()
|
||||
// function.
|
||||
template <bool is_method, typename T>
|
||||
struct MaybeRefcount;
|
||||
template <bool is_method, typename... T>
|
||||
struct MaybeScopedRefPtr;
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<false, T> {
|
||||
static void AddRef(const T&) {}
|
||||
static void Release(const T&) {}
|
||||
template <bool is_method>
|
||||
struct MaybeScopedRefPtr<is_method> {
|
||||
MaybeScopedRefPtr() {}
|
||||
};
|
||||
|
||||
template <typename T, size_t n>
|
||||
struct MaybeRefcount<false, T[n]> {
|
||||
static void AddRef(const T*) {}
|
||||
static void Release(const T*) {}
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<false, T, Rest...> {
|
||||
MaybeScopedRefPtr(const T&, const Rest&...) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, T> {
|
||||
static void AddRef(const T&) {}
|
||||
static void Release(const T&) {}
|
||||
template <typename T, size_t n, typename... Rest>
|
||||
struct MaybeScopedRefPtr<false, T[n], Rest...> {
|
||||
MaybeScopedRefPtr(const T*, const Rest&...) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, T*> {
|
||||
static void AddRef(T* o) { o->AddRef(); }
|
||||
static void Release(T* o) { o->Release(); }
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<true, T, Rest...> {
|
||||
MaybeScopedRefPtr(const T& o, const Rest&...) {}
|
||||
};
|
||||
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<true, T*, Rest...> {
|
||||
MaybeScopedRefPtr(T* o, const Rest&...) : ref_(o) {}
|
||||
scoped_refptr<T> ref_;
|
||||
};
|
||||
|
||||
// No need to additionally AddRef() and Release() since we are storing a
|
||||
// scoped_refptr<> inside the storage object already.
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, scoped_refptr<T> > {
|
||||
static void AddRef(const scoped_refptr<T>& o) {}
|
||||
static void Release(const scoped_refptr<T>& o) {}
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<true, scoped_refptr<T>, Rest...> {
|
||||
MaybeScopedRefPtr(const scoped_refptr<T>&, const Rest&...) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, const T*> {
|
||||
static void AddRef(const T* o) { o->AddRef(); }
|
||||
static void Release(const T* o) { o->Release(); }
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<true, const T*, Rest...> {
|
||||
MaybeScopedRefPtr(const T* o, const Rest&...) : ref_(o) {}
|
||||
scoped_refptr<const T> ref_;
|
||||
};
|
||||
|
||||
// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
|
||||
@ -481,15 +489,113 @@ struct MaybeRefcount<true, const T*> {
|
||||
// InvokeHelper that will no-op itself in the event the WeakPtr<> for
|
||||
// the target object is invalidated.
|
||||
//
|
||||
// P1 should be the type of the object that will be received of the method.
|
||||
template <bool IsMethod, typename P1>
|
||||
// The first argument should be the type of the object that will be received by
|
||||
// the method.
|
||||
template <bool IsMethod, typename... Args>
|
||||
struct IsWeakMethod : public false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsWeakMethod<true, WeakPtr<T> > : public true_type {};
|
||||
template <typename T, typename... Args>
|
||||
struct IsWeakMethod<true, WeakPtr<T>, Args...> : public true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T> > > : public true_type {};
|
||||
template <typename T, typename... Args>
|
||||
struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T>>, Args...>
|
||||
: public true_type {};
|
||||
|
||||
|
||||
// Packs a list of types to hold them in a single type.
|
||||
template <typename... Types>
|
||||
struct TypeList {};
|
||||
|
||||
// Used for DropTypeListItem implementation.
|
||||
template <size_t n, typename List>
|
||||
struct DropTypeListItemImpl;
|
||||
|
||||
// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
|
||||
template <size_t n, typename T, typename... List>
|
||||
struct DropTypeListItemImpl<n, TypeList<T, List...>>
|
||||
: DropTypeListItemImpl<n - 1, TypeList<List...>> {};
|
||||
|
||||
template <typename T, typename... List>
|
||||
struct DropTypeListItemImpl<0, TypeList<T, List...>> {
|
||||
using Type = TypeList<T, List...>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DropTypeListItemImpl<0, TypeList<>> {
|
||||
using Type = TypeList<>;
|
||||
};
|
||||
|
||||
// A type-level function that drops |n| list item from given TypeList.
|
||||
template <size_t n, typename List>
|
||||
using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
|
||||
|
||||
// Used for TakeTypeListItem implementation.
|
||||
template <size_t n, typename List, typename... Accum>
|
||||
struct TakeTypeListItemImpl;
|
||||
|
||||
// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
|
||||
template <size_t n, typename T, typename... List, typename... Accum>
|
||||
struct TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>
|
||||
: TakeTypeListItemImpl<n - 1, TypeList<List...>, Accum..., T> {};
|
||||
|
||||
template <typename T, typename... List, typename... Accum>
|
||||
struct TakeTypeListItemImpl<0, TypeList<T, List...>, Accum...> {
|
||||
using Type = TypeList<Accum...>;
|
||||
};
|
||||
|
||||
template <typename... Accum>
|
||||
struct TakeTypeListItemImpl<0, TypeList<>, Accum...> {
|
||||
using Type = TypeList<Accum...>;
|
||||
};
|
||||
|
||||
// A type-level function that takes first |n| list item from given TypeList.
|
||||
// E.g. TakeTypeListItem<3, TypeList<A, B, C, D>> is evaluated to
|
||||
// TypeList<A, B, C>.
|
||||
template <size_t n, typename List>
|
||||
using TakeTypeListItem = typename TakeTypeListItemImpl<n, List>::Type;
|
||||
|
||||
// Used for ConcatTypeLists implementation.
|
||||
template <typename List1, typename List2>
|
||||
struct ConcatTypeListsImpl;
|
||||
|
||||
template <typename... Types1, typename... Types2>
|
||||
struct ConcatTypeListsImpl<TypeList<Types1...>, TypeList<Types2...>> {
|
||||
using Type = TypeList<Types1..., Types2...>;
|
||||
};
|
||||
|
||||
// A type-level function that concats two TypeLists.
|
||||
template <typename List1, typename List2>
|
||||
using ConcatTypeLists = typename ConcatTypeListsImpl<List1, List2>::Type;
|
||||
|
||||
// Used for MakeFunctionType implementation.
|
||||
template <typename R, typename ArgList>
|
||||
struct MakeFunctionTypeImpl;
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef R Type(Args...);
|
||||
};
|
||||
|
||||
// A type-level function that constructs a function type that has |R| as its
|
||||
// return type and has TypeLists items as its arguments.
|
||||
template <typename R, typename ArgList>
|
||||
using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
|
||||
|
||||
// Used for ExtractArgs.
|
||||
template <typename Signature>
|
||||
struct ExtractArgsImpl;
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct ExtractArgsImpl<R(Args...)> {
|
||||
using Type = TypeList<Args...>;
|
||||
};
|
||||
|
||||
// A type-level function that extracts function arguments into a TypeList.
|
||||
// E.g. ExtractArgs<R(A, B, C)> is evaluated to TypeList<A, B, C>.
|
||||
template <typename Signature>
|
||||
using ExtractArgs = typename ExtractArgsImpl<Signature>::Type;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
@ -508,17 +614,25 @@ static inline internal::OwnedWrapper<T> Owned(T* o) {
|
||||
return internal::OwnedWrapper<T>(o);
|
||||
}
|
||||
|
||||
// We offer 2 syntaxes for calling Passed(). The first takes a temporary and
|
||||
// is best suited for use with the return value of a function. The second
|
||||
// takes a pointer to the scoper and is just syntactic sugar to avoid having
|
||||
// to write Passed(scoper.Pass()).
|
||||
template <typename T>
|
||||
static inline internal::PassedWrapper<T> Passed(T scoper) {
|
||||
return internal::PassedWrapper<T>(scoper.Pass());
|
||||
// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and
|
||||
// is best suited for use with the return value of a function or other temporary
|
||||
// rvalues. The second takes a pointer to the scoper and is just syntactic sugar
|
||||
// to avoid having to write Passed(std::move(scoper)).
|
||||
//
|
||||
// Both versions of Passed() prevent T from being an lvalue reference. The first
|
||||
// via use of enable_if, and the second takes a T* which will not bind to T&.
|
||||
template <typename T,
|
||||
typename std::enable_if<internal::IsMoveOnlyType<T>::value &&
|
||||
!std::is_lvalue_reference<T>::value>::type* =
|
||||
nullptr>
|
||||
static inline internal::PassedWrapper<T> Passed(T&& scoper) {
|
||||
return internal::PassedWrapper<T>(std::move(scoper));
|
||||
}
|
||||
template <typename T>
|
||||
template <typename T,
|
||||
typename std::enable_if<internal::IsMoveOnlyType<T>::value>::type* =
|
||||
nullptr>
|
||||
static inline internal::PassedWrapper<T> Passed(T* scoper) {
|
||||
return internal::PassedWrapper<T>(scoper->Pass());
|
||||
return internal::PassedWrapper<T>(std::move(*scoper));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,8 @@
|
||||
#ifndef BASE_BIND_INTERNAL_WIN_H_
|
||||
#define BASE_BIND_INTERNAL_WIN_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
|
||||
// the same as __cdecl which would turn the following specializations into
|
||||
// multiple definitions.
|
||||
@ -23,7 +25,9 @@ class RunnableAdapter;
|
||||
template <typename R, typename... Args>
|
||||
class RunnableAdapter<R(__stdcall *)(Args...)> {
|
||||
public:
|
||||
typedef R (RunType)(Args...);
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef R RunType(Args...);
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)(Args...))
|
||||
: function_(function) {
|
||||
@ -41,7 +45,9 @@ class RunnableAdapter<R(__stdcall *)(Args...)> {
|
||||
template <typename R, typename... Args>
|
||||
class RunnableAdapter<R(__fastcall *)(Args...)> {
|
||||
public:
|
||||
typedef R (RunType)(Args...);
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef R RunType(Args...);
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)(Args...))
|
||||
: function_(function) {
|
||||
|
71
security/sandbox/chromium/base/bit_cast.h
Normal file
71
security/sandbox/chromium/base/bit_cast.h
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_BIT_CAST_H_
|
||||
#define BASE_BIT_CAST_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// bit_cast<Dest,Source> is a template function that implements the equivalent
|
||||
// of "*reinterpret_cast<Dest*>(&source)". We need this in very low-level
|
||||
// functions like the protobuf library and fast math support.
|
||||
//
|
||||
// float f = 3.14159265358979;
|
||||
// int i = bit_cast<int32_t>(f);
|
||||
// // i = 0x40490fdb
|
||||
//
|
||||
// The classical address-casting method is:
|
||||
//
|
||||
// // WRONG
|
||||
// float f = 3.14159265358979; // WRONG
|
||||
// int i = * reinterpret_cast<int*>(&f); // WRONG
|
||||
//
|
||||
// The address-casting method actually produces undefined behavior according to
|
||||
// the ISO C++98 specification, section 3.10 ("basic.lval"), paragraph 15.
|
||||
// (This did not substantially change in C++11.) Roughly, this section says: if
|
||||
// an object in memory has one type, and a program accesses it with a different
|
||||
// type, then the result is undefined behavior for most values of "different
|
||||
// type".
|
||||
//
|
||||
// This is true for any cast syntax, either *(int*)&f or
|
||||
// *reinterpret_cast<int*>(&f). And it is particularly true for conversions
|
||||
// between integral lvalues and floating-point lvalues.
|
||||
//
|
||||
// The purpose of this paragraph is to allow optimizing compilers to assume that
|
||||
// expressions with different types refer to different memory. Compilers are
|
||||
// known to take advantage of this. So a non-conforming program quietly
|
||||
// produces wildly incorrect output.
|
||||
//
|
||||
// The problem is not the use of reinterpret_cast. The problem is type punning:
|
||||
// holding an object in memory of one type and reading its bits back using a
|
||||
// different type.
|
||||
//
|
||||
// The C++ standard is more subtle and complex than this, but that is the basic
|
||||
// idea.
|
||||
//
|
||||
// Anyways ...
|
||||
//
|
||||
// bit_cast<> calls memcpy() which is blessed by the standard, especially by the
|
||||
// example in section 3.9 . Also, of course, bit_cast<> wraps up the nasty
|
||||
// logic in one place.
|
||||
//
|
||||
// Fortunately memcpy() is very fast. In optimized mode, compilers replace
|
||||
// calls to memcpy() with inline object code when the size argument is a
|
||||
// compile-time constant. On a 32-bit system, memcpy(d,s,4) compiles to one
|
||||
// load and one store, and memcpy(d,s,8) compiles to two loads and two stores.
|
||||
//
|
||||
// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
|
||||
// is likely to surprise you.
|
||||
|
||||
template <class Dest, class Source>
|
||||
inline Dest bit_cast(const Source& source) {
|
||||
static_assert(sizeof(Dest) == sizeof(Source),
|
||||
"bit_cast requires source and destination to be the same size");
|
||||
|
||||
Dest dest;
|
||||
memcpy(&dest, &source, sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
|
||||
#endif // BASE_BIT_CAST_H_
|
@ -1,8 +1,3 @@
|
||||
// This file was GENERATED by command:
|
||||
// pump.py callback.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
@ -31,7 +26,7 @@
|
||||
// much like lexical closures are used in other languages. For example, it
|
||||
// is used in Chromium code to schedule tasks on different MessageLoops.
|
||||
//
|
||||
// A callback with no unbound input parameters (base::Callback<void(void)>)
|
||||
// A callback with no unbound input parameters (base::Callback<void()>)
|
||||
// is called a base::Closure. Note that this is NOT the same as what other
|
||||
// languages refer to as a closure -- it does not retain a reference to its
|
||||
// enclosing environment.
|
||||
@ -53,7 +48,7 @@
|
||||
// BINDING A BARE FUNCTION
|
||||
//
|
||||
// int Return5() { return 5; }
|
||||
// base::Callback<int(void)> func_cb = base::Bind(&Return5);
|
||||
// base::Callback<int()> func_cb = base::Bind(&Return5);
|
||||
// LOG(INFO) << func_cb.Run(); // Prints 5.
|
||||
//
|
||||
// BINDING A CLASS METHOD
|
||||
@ -67,7 +62,7 @@
|
||||
// void PrintBye() { LOG(INFO) << "bye."; }
|
||||
// };
|
||||
// scoped_refptr<Ref> ref = new Ref();
|
||||
// base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
|
||||
// base::Callback<void()> ref_cb = base::Bind(&Ref::Foo, ref);
|
||||
// LOG(INFO) << ref_cb.Run(); // Prints out 3.
|
||||
//
|
||||
// By default the object must support RefCounted or you will get a compiler
|
||||
@ -109,10 +104,10 @@
|
||||
// calling.
|
||||
//
|
||||
// void MyFunc(int i, const std::string& str) {}
|
||||
// base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
|
||||
// base::Callback<void()> cb = base::Bind(&MyFunc, 23, "hello world");
|
||||
// cb.Run();
|
||||
//
|
||||
// A callback with no unbound input parameters (base::Callback<void(void)>)
|
||||
// A callback with no unbound input parameters (base::Callback<void()>)
|
||||
// is called a base::Closure. So we could have also written:
|
||||
//
|
||||
// base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
|
||||
@ -170,7 +165,7 @@
|
||||
// that doesn't expect a return value.
|
||||
//
|
||||
// int DoSomething(int arg) { cout << arg << endl; }
|
||||
// base::Callback<void<int>) cb =
|
||||
// base::Callback<void(int)> cb =
|
||||
// base::Bind(base::IgnoreResult(&DoSomething));
|
||||
//
|
||||
//
|
||||
@ -180,7 +175,7 @@
|
||||
//
|
||||
// Bound parameters are specified as arguments to Bind() and are passed to the
|
||||
// function. A callback with no parameters or no unbound parameters is called a
|
||||
// Closure (base::Callback<void(void)> and base::Closure are the same thing).
|
||||
// Closure (base::Callback<void()> and base::Closure are the same thing).
|
||||
//
|
||||
// PASSING PARAMETERS OWNED BY THE CALLBACK
|
||||
//
|
||||
@ -359,33 +354,30 @@ namespace base {
|
||||
//
|
||||
// If you are thinking of forward declaring Callback in your own header file,
|
||||
// please include "base/callback_forward.h" instead.
|
||||
template <typename Sig>
|
||||
class Callback;
|
||||
|
||||
namespace internal {
|
||||
template <typename Runnable, typename RunType, typename BoundArgsType>
|
||||
template <typename Runnable, typename RunType, typename... BoundArgsType>
|
||||
struct BindState;
|
||||
} // namespace internal
|
||||
|
||||
template <typename R>
|
||||
class Callback<R(void)> : public internal::CallbackBase {
|
||||
template <typename R, typename... Args>
|
||||
class Callback<R(Args...)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)();
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef R RunType(Args...);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
Callback() : CallbackBase(nullptr) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
template <typename Runnable, typename BindRunType, typename... BoundArgsType>
|
||||
explicit Callback(
|
||||
internal::BindState<Runnable, BindRunType, BoundArgsType...>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType...>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
@ -394,377 +386,20 @@ class Callback<R(void)> : public internal::CallbackBase {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run() const {
|
||||
R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args)
|
||||
const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get());
|
||||
return f(bind_state_.get(), internal::CallbackForward(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*);
|
||||
|
||||
using PolymorphicInvoke =
|
||||
R(*)(internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<Args>::ForwardType...);
|
||||
};
|
||||
|
||||
template <typename R, typename A1>
|
||||
class Callback<R(A1)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2>
|
||||
class Callback<R(A1, A2)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3>
|
||||
class Callback<R(A1, A2, A3)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4>
|
||||
class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5>
|
||||
class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4, A5);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType a5) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4),
|
||||
internal::CallbackForward(a5));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6>
|
||||
class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4, A5, A6);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType a6) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4),
|
||||
internal::CallbackForward(a5),
|
||||
internal::CallbackForward(a6));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6, typename A7>
|
||||
class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4, A5, A6, A7);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType a6,
|
||||
typename internal::CallbackParamTraits<A7>::ForwardType a7) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4),
|
||||
internal::CallbackForward(a5),
|
||||
internal::CallbackForward(a6),
|
||||
internal::CallbackForward(a7));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A7>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Syntactic sugar to make Callback<void(void)> easier to declare since it
|
||||
// will be used in a lot of APIs with delayed execution.
|
||||
typedef Callback<void(void)> Closure;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CALLBACK_H
|
||||
#endif // BASE_CALLBACK_H_
|
||||
|
@ -10,8 +10,10 @@ namespace base {
|
||||
template <typename Sig>
|
||||
class Callback;
|
||||
|
||||
typedef Callback<void(void)> Closure;
|
||||
// Syntactic sugar to make Callback<void()> easier to declare since it
|
||||
// will be used in a lot of APIs with delayed execution.
|
||||
using Closure = Callback<void()>;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CALLBACK_FORWARD_H
|
||||
#endif // BASE_CALLBACK_FORWARD_H_
|
||||
|
@ -9,6 +9,18 @@
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
void BindStateBase::AddRef() {
|
||||
AtomicRefCountInc(&ref_count_);
|
||||
}
|
||||
|
||||
void BindStateBase::Release() {
|
||||
if (!AtomicRefCountDec(&ref_count_))
|
||||
destructor_(this);
|
||||
}
|
||||
|
||||
CallbackBase::CallbackBase(const CallbackBase& c) = default;
|
||||
CallbackBase& CallbackBase::operator=(const CallbackBase& c) = default;
|
||||
|
||||
void CallbackBase::Reset() {
|
||||
polymorphic_invoke_ = NULL;
|
||||
// NULL the bind_state_ last, since it may be holding the last ref to whatever
|
||||
@ -24,7 +36,7 @@ bool CallbackBase::Equals(const CallbackBase& other) const {
|
||||
CallbackBase::CallbackBase(BindStateBase* bind_state)
|
||||
: bind_state_(bind_state),
|
||||
polymorphic_invoke_(NULL) {
|
||||
DCHECK(!bind_state_.get() || bind_state_->HasOneRef());
|
||||
DCHECK(!bind_state_.get() || bind_state_->ref_count_ == 1);
|
||||
}
|
||||
|
||||
CallbackBase::~CallbackBase() {
|
||||
|
@ -9,16 +9,19 @@
|
||||
#define BASE_CALLBACK_INTERNAL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/atomic_ref_count.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
|
||||
template <typename T>
|
||||
class ScopedVector;
|
||||
#include "base/template_util.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
class CallbackBase;
|
||||
|
||||
// BindStateBase is used to provide an opaque handle that the Callback
|
||||
// class can use to represent a function object with bound arguments. It
|
||||
@ -26,16 +29,39 @@ namespace internal {
|
||||
// DoInvoke function to perform the function execution. This allows
|
||||
// us to shield the Callback class from the types of the bound argument via
|
||||
// "type erasure."
|
||||
class BindStateBase : public RefCountedThreadSafe<BindStateBase> {
|
||||
// At the base level, the only task is to add reference counting data. Don't use
|
||||
// RefCountedThreadSafe since it requires the destructor to be a virtual method.
|
||||
// Creating a vtable for every BindState template instantiation results in a lot
|
||||
// of bloat. Its only task is to call the destructor which can be done with a
|
||||
// function pointer.
|
||||
class BindStateBase {
|
||||
protected:
|
||||
friend class RefCountedThreadSafe<BindStateBase>;
|
||||
virtual ~BindStateBase() {}
|
||||
explicit BindStateBase(void (*destructor)(BindStateBase*))
|
||||
: ref_count_(0), destructor_(destructor) {}
|
||||
~BindStateBase() = default;
|
||||
|
||||
private:
|
||||
friend class scoped_refptr<BindStateBase>;
|
||||
friend class CallbackBase;
|
||||
|
||||
void AddRef();
|
||||
void Release();
|
||||
|
||||
AtomicRefCount ref_count_;
|
||||
|
||||
// Pointer to a function that will properly destroy |this|.
|
||||
void (*destructor_)(BindStateBase*);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BindStateBase);
|
||||
};
|
||||
|
||||
// Holds the Callback methods that don't require specialization to reduce
|
||||
// template bloat.
|
||||
class BASE_EXPORT CallbackBase {
|
||||
public:
|
||||
CallbackBase(const CallbackBase& c);
|
||||
CallbackBase& operator=(const CallbackBase& c);
|
||||
|
||||
// Returns true if Callback is null (doesn't refer to anything).
|
||||
bool is_null() const { return bind_state_.get() == NULL; }
|
||||
|
||||
@ -47,7 +73,7 @@ class BASE_EXPORT CallbackBase {
|
||||
// another type. It is not okay to use void*. We create a InvokeFuncStorage
|
||||
// that that can store our function pointer, and then cast it back to
|
||||
// the original type on usage.
|
||||
typedef void(*InvokeFuncStorage)(void);
|
||||
using InvokeFuncStorage = void(*)();
|
||||
|
||||
// Returns true if this callback equals |other|. |other| may be null.
|
||||
bool Equals(const CallbackBase& other) const;
|
||||
@ -68,8 +94,14 @@ class BASE_EXPORT CallbackBase {
|
||||
};
|
||||
|
||||
// A helper template to determine if given type is non-const move-only-type,
|
||||
// i.e. if a value of the given type should be passed via .Pass() in a
|
||||
// destructive way.
|
||||
// i.e. if a value of the given type should be passed via std::move() in a
|
||||
// destructive way. Types are considered to be move-only if they have a
|
||||
// sentinel MoveOnlyTypeForCPP03 member: a class typically gets this from using
|
||||
// the DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND macro.
|
||||
// It would be easy to generalize this trait to all move-only types... but this
|
||||
// confuses template deduction in VS2013 with certain types such as
|
||||
// std::unique_ptr.
|
||||
// TODO(dcheng): Revisit this when Windows switches to VS2015 by default.
|
||||
template <typename T> struct IsMoveOnlyType {
|
||||
template <typename U>
|
||||
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
|
||||
@ -81,6 +113,21 @@ template <typename T> struct IsMoveOnlyType {
|
||||
!is_const<T>::value;
|
||||
};
|
||||
|
||||
// Specialization of IsMoveOnlyType so that std::unique_ptr is still considered
|
||||
// move-only, even without the sentinel member.
|
||||
template <typename T>
|
||||
struct IsMoveOnlyType<std::unique_ptr<T>> : std::true_type {};
|
||||
|
||||
template <typename>
|
||||
struct CallbackParamTraitsForMoveOnlyType;
|
||||
|
||||
template <typename>
|
||||
struct CallbackParamTraitsForNonMoveOnlyType;
|
||||
|
||||
// TODO(tzik): Use a default parameter once MSVS supports variadic templates
|
||||
// with default values.
|
||||
// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates
|
||||
//
|
||||
// This is a typetraits object that's used to take an argument type, and
|
||||
// extract a suitable type for storing and forwarding arguments.
|
||||
//
|
||||
@ -92,10 +139,17 @@ template <typename T> struct IsMoveOnlyType {
|
||||
// parameters by const reference. In this case, we end up passing an actual
|
||||
// array type in the initializer list which C++ does not allow. This will
|
||||
// break passing of C-string literals.
|
||||
template <typename T, bool is_move_only = IsMoveOnlyType<T>::value>
|
||||
struct CallbackParamTraits {
|
||||
typedef const T& ForwardType;
|
||||
typedef T StorageType;
|
||||
template <typename T>
|
||||
struct CallbackParamTraits
|
||||
: std::conditional<IsMoveOnlyType<T>::value,
|
||||
CallbackParamTraitsForMoveOnlyType<T>,
|
||||
CallbackParamTraitsForNonMoveOnlyType<T>>::type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CallbackParamTraitsForNonMoveOnlyType {
|
||||
using ForwardType = const T&;
|
||||
using StorageType = T;
|
||||
};
|
||||
|
||||
// The Storage should almost be impossible to trigger unless someone manually
|
||||
@ -104,9 +158,9 @@ struct CallbackParamTraits {
|
||||
//
|
||||
// The ForwardType should only be used for unbound arguments.
|
||||
template <typename T>
|
||||
struct CallbackParamTraits<T&, false> {
|
||||
typedef T& ForwardType;
|
||||
typedef T StorageType;
|
||||
struct CallbackParamTraitsForNonMoveOnlyType<T&> {
|
||||
using ForwardType = T&;
|
||||
using StorageType = T;
|
||||
};
|
||||
|
||||
// Note that for array types, we implicitly add a const in the conversion. This
|
||||
@ -115,16 +169,16 @@ struct CallbackParamTraits<T&, false> {
|
||||
// T[n]" does not seem to match correctly, so we are stuck with this
|
||||
// restriction.
|
||||
template <typename T, size_t n>
|
||||
struct CallbackParamTraits<T[n], false> {
|
||||
typedef const T* ForwardType;
|
||||
typedef const T* StorageType;
|
||||
struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
|
||||
using ForwardType = const T*;
|
||||
using StorageType = const T*;
|
||||
};
|
||||
|
||||
// See comment for CallbackParamTraits<T[n]>.
|
||||
template <typename T>
|
||||
struct CallbackParamTraits<T[], false> {
|
||||
typedef const T* ForwardType;
|
||||
typedef const T* StorageType;
|
||||
struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
|
||||
using ForwardType = const T*;
|
||||
using StorageType = const T*;
|
||||
};
|
||||
|
||||
// Parameter traits for movable-but-not-copyable scopers.
|
||||
@ -141,9 +195,9 @@ struct CallbackParamTraits<T[], false> {
|
||||
// reference cannot be used with temporaries which means the result of a
|
||||
// function or a cast would not be usable with Callback<> or Bind().
|
||||
template <typename T>
|
||||
struct CallbackParamTraits<T, true> {
|
||||
typedef T ForwardType;
|
||||
typedef T StorageType;
|
||||
struct CallbackParamTraitsForMoveOnlyType {
|
||||
using ForwardType = T;
|
||||
using StorageType = T;
|
||||
};
|
||||
|
||||
// CallbackForward() is a very limited simulation of C++11's std::forward()
|
||||
@ -155,7 +209,7 @@ struct CallbackParamTraits<T, true> {
|
||||
// default template compiles out to be a no-op.
|
||||
//
|
||||
// In C++11, std::forward would replace all uses of this function. However, it
|
||||
// is impossible to implement a general std::forward with C++11 due to a lack
|
||||
// is impossible to implement a general std::forward without C++11 due to a lack
|
||||
// of rvalue references.
|
||||
//
|
||||
// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
|
||||
@ -163,13 +217,15 @@ struct CallbackParamTraits<T, true> {
|
||||
// parameter to another callback. This is to support Callbacks that return
|
||||
// the movable-but-not-copyable types whitelisted above.
|
||||
template <typename T>
|
||||
typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
|
||||
typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(
|
||||
T& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
|
||||
return t.Pass();
|
||||
typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(
|
||||
T& t) {
|
||||
return std::move(t);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -9,6 +9,9 @@
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
|
||||
// For _Printf_format_string_.
|
||||
#include <sal.h>
|
||||
|
||||
// Macros for suppressing and disabling warnings on MSVC.
|
||||
//
|
||||
// Warning numbers are enumerated at:
|
||||
@ -57,6 +60,7 @@
|
||||
|
||||
#else // Not MSVC
|
||||
|
||||
#define _Printf_format_string_
|
||||
#define MSVC_SUPPRESS_WARNING(n)
|
||||
#define MSVC_PUSH_DISABLE_WARNING(n)
|
||||
#define MSVC_PUSH_WARNING_LEVEL(n)
|
||||
@ -68,28 +72,6 @@
|
||||
#endif // COMPILER_MSVC
|
||||
|
||||
|
||||
// The C++ standard requires that static const members have an out-of-class
|
||||
// definition (in a single compilation unit), but MSVC chokes on this (when
|
||||
// language extensions, which are required, are enabled). (You're only likely to
|
||||
// notice the need for a definition if you take the address of the member or,
|
||||
// more commonly, pass it to a function that takes it as a reference argument --
|
||||
// probably an STL function.) This macro makes MSVC do the right thing. See
|
||||
// http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx for more
|
||||
// information. Use like:
|
||||
//
|
||||
// In .h file:
|
||||
// struct Foo {
|
||||
// static const int kBar = 5;
|
||||
// };
|
||||
//
|
||||
// In .cc file:
|
||||
// STATIC_CONST_MEMBER_DEFINITION const int Foo::kBar;
|
||||
#if defined(COMPILER_MSVC)
|
||||
#define STATIC_CONST_MEMBER_DEFINITION __declspec(selectany)
|
||||
#else
|
||||
#define STATIC_CONST_MEMBER_DEFINITION
|
||||
#endif
|
||||
|
||||
// Annotate a variable indicating it's ok if the variable is not used.
|
||||
// (Typically used to silence a compiler warning when the assignment
|
||||
// is important for some other reason.)
|
||||
@ -101,7 +83,7 @@
|
||||
// Annotate a typedef or function indicating it's ok if it's not used.
|
||||
// Use like:
|
||||
// typedef Foo Bar ALLOW_UNUSED_TYPE;
|
||||
#if defined(COMPILER_GCC)
|
||||
#if defined(COMPILER_GCC) || defined(__clang__)
|
||||
#define ALLOW_UNUSED_TYPE __attribute__((unused))
|
||||
#else
|
||||
#define ALLOW_UNUSED_TYPE
|
||||
@ -128,13 +110,11 @@
|
||||
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
|
||||
#endif
|
||||
|
||||
// Return the byte alignment of the given type (available at compile time). Use
|
||||
// sizeof(type) prior to checking __alignof to workaround Visual C++ bug:
|
||||
// http://goo.gl/isH0C
|
||||
// Return the byte alignment of the given type (available at compile time).
|
||||
// Use like:
|
||||
// ALIGNOF(int32) // this would be 4
|
||||
// ALIGNOF(int32_t) // this would be 4
|
||||
#if defined(COMPILER_MSVC)
|
||||
#define ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type))
|
||||
#define ALIGNOF(type) __alignof(type)
|
||||
#elif defined(COMPILER_GCC)
|
||||
#define ALIGNOF(type) __alignof__(type)
|
||||
#endif
|
||||
@ -142,8 +122,9 @@
|
||||
// Annotate a function indicating the caller must examine the return value.
|
||||
// Use like:
|
||||
// int foo() WARN_UNUSED_RESULT;
|
||||
// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
|
||||
#if defined(COMPILER_GCC)
|
||||
// To explicitly ignore a result, see |ignore_result()| in base/macros.h.
|
||||
#undef WARN_UNUSED_RESULT
|
||||
#if defined(COMPILER_GCC) || defined(__clang__)
|
||||
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
#define WARN_UNUSED_RESULT
|
||||
@ -175,9 +156,17 @@
|
||||
// Mark a memory region fully initialized.
|
||||
// Use this to annotate code that deliberately reads uninitialized data, for
|
||||
// example a GC scavenging root set pointers from the stack.
|
||||
#define MSAN_UNPOISON(p, s) __msan_unpoison(p, s)
|
||||
#define MSAN_UNPOISON(p, size) __msan_unpoison(p, size)
|
||||
|
||||
// Check a memory region for initializedness, as if it was being used here.
|
||||
// If any bits are uninitialized, crash with an MSan report.
|
||||
// Use this to sanitize data which MSan won't be able to track, e.g. before
|
||||
// passing data to another process via shared memory.
|
||||
#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) \
|
||||
__msan_check_mem_is_initialized(p, size)
|
||||
#else // MEMORY_SANITIZER
|
||||
#define MSAN_UNPOISON(p, s)
|
||||
#define MSAN_UNPOISON(p, size)
|
||||
#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
|
||||
#endif // MEMORY_SANITIZER
|
||||
|
||||
// Macro useful for writing cross-platform function pointers.
|
||||
|
@ -21,9 +21,11 @@
|
||||
#ifndef BASE_CONTAINERS_HASH_TABLES_H_
|
||||
#define BASE_CONTAINERS_HASH_TABLES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
@ -45,15 +47,9 @@
|
||||
#undef __DEPRECATED
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID) && !defined(MOZ_WIDGET_GONK)
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#define BASE_HASH_IMPL_NAMESPACE std
|
||||
#else
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
#define BASE_HASH_IMPL_NAMESPACE __gnu_cxx
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -84,7 +80,6 @@ struct hash<T*> {
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
// The GNU C++ library provides identity hash functions for many integral types,
|
||||
// but not for |long long|. This hash function will truncate if |size_t| is
|
||||
// narrower than |long long|. This is probably good enough for what we will
|
||||
@ -102,7 +97,6 @@ DEFINE_TRIVIAL_HASH(long long);
|
||||
DEFINE_TRIVIAL_HASH(unsigned long long);
|
||||
|
||||
#undef DEFINE_TRIVIAL_HASH
|
||||
#endif // !defined(OS_ANDROID)
|
||||
|
||||
// Implement string hash functions so that strings of various flavors can
|
||||
// be used as keys in STL maps and sets. The hash algorithm comes from the
|
||||
@ -204,19 +198,19 @@ using hash_set = BASE_HASH_IMPL_NAMESPACE::hash_set<Key, Hash, Pred, Alloc>;
|
||||
// h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
|
||||
//
|
||||
// Contact danakj@chromium.org for any questions.
|
||||
inline std::size_t HashInts32(uint32 value1, uint32 value2) {
|
||||
uint64 value1_64 = value1;
|
||||
uint64 hash64 = (value1_64 << 32) | value2;
|
||||
inline std::size_t HashInts32(uint32_t value1, uint32_t value2) {
|
||||
uint64_t value1_64 = value1;
|
||||
uint64_t hash64 = (value1_64 << 32) | value2;
|
||||
|
||||
if (sizeof(std::size_t) >= sizeof(uint64))
|
||||
if (sizeof(std::size_t) >= sizeof(uint64_t))
|
||||
return static_cast<std::size_t>(hash64);
|
||||
|
||||
uint64 odd_random = 481046412LL << 32 | 1025306955LL;
|
||||
uint32 shift_random = 10121U << 16;
|
||||
uint64_t odd_random = 481046412LL << 32 | 1025306955LL;
|
||||
uint32_t shift_random = 10121U << 16;
|
||||
|
||||
hash64 = hash64 * odd_random + shift_random;
|
||||
std::size_t high_bits = static_cast<std::size_t>(
|
||||
hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
|
||||
hash64 >> (8 * (sizeof(uint64_t) - sizeof(std::size_t))));
|
||||
return high_bits;
|
||||
}
|
||||
|
||||
@ -225,87 +219,46 @@ inline std::size_t HashInts32(uint32 value1, uint32 value2) {
|
||||
// breaking the two 64-bit inputs into 4 32-bit values:
|
||||
// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
|
||||
// Then we reduce our result to 32 bits if required, similar to above.
|
||||
inline std::size_t HashInts64(uint64 value1, uint64 value2) {
|
||||
uint32 short_random1 = 842304669U;
|
||||
uint32 short_random2 = 619063811U;
|
||||
uint32 short_random3 = 937041849U;
|
||||
uint32 short_random4 = 3309708029U;
|
||||
inline std::size_t HashInts64(uint64_t value1, uint64_t value2) {
|
||||
uint32_t short_random1 = 842304669U;
|
||||
uint32_t short_random2 = 619063811U;
|
||||
uint32_t short_random3 = 937041849U;
|
||||
uint32_t short_random4 = 3309708029U;
|
||||
|
||||
uint32 value1a = static_cast<uint32>(value1 & 0xffffffff);
|
||||
uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff);
|
||||
uint32 value2a = static_cast<uint32>(value2 & 0xffffffff);
|
||||
uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff);
|
||||
uint32_t value1a = static_cast<uint32_t>(value1 & 0xffffffff);
|
||||
uint32_t value1b = static_cast<uint32_t>((value1 >> 32) & 0xffffffff);
|
||||
uint32_t value2a = static_cast<uint32_t>(value2 & 0xffffffff);
|
||||
uint32_t value2b = static_cast<uint32_t>((value2 >> 32) & 0xffffffff);
|
||||
|
||||
uint64 product1 = static_cast<uint64>(value1a) * short_random1;
|
||||
uint64 product2 = static_cast<uint64>(value1b) * short_random2;
|
||||
uint64 product3 = static_cast<uint64>(value2a) * short_random3;
|
||||
uint64 product4 = static_cast<uint64>(value2b) * short_random4;
|
||||
uint64_t product1 = static_cast<uint64_t>(value1a) * short_random1;
|
||||
uint64_t product2 = static_cast<uint64_t>(value1b) * short_random2;
|
||||
uint64_t product3 = static_cast<uint64_t>(value2a) * short_random3;
|
||||
uint64_t product4 = static_cast<uint64_t>(value2b) * short_random4;
|
||||
|
||||
uint64 hash64 = product1 + product2 + product3 + product4;
|
||||
uint64_t hash64 = product1 + product2 + product3 + product4;
|
||||
|
||||
if (sizeof(std::size_t) >= sizeof(uint64))
|
||||
if (sizeof(std::size_t) >= sizeof(uint64_t))
|
||||
return static_cast<std::size_t>(hash64);
|
||||
|
||||
uint64 odd_random = 1578233944LL << 32 | 194370989LL;
|
||||
uint32 shift_random = 20591U << 16;
|
||||
uint64_t odd_random = 1578233944LL << 32 | 194370989LL;
|
||||
uint32_t shift_random = 20591U << 16;
|
||||
|
||||
hash64 = hash64 * odd_random + shift_random;
|
||||
std::size_t high_bits = static_cast<std::size_t>(
|
||||
hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
|
||||
hash64 >> (8 * (sizeof(uint64_t) - sizeof(std::size_t))));
|
||||
return high_bits;
|
||||
}
|
||||
|
||||
#define DEFINE_32BIT_PAIR_HASH(Type1, Type2) \
|
||||
inline std::size_t HashPair(Type1 value1, Type2 value2) { \
|
||||
return HashInts32(value1, value2); \
|
||||
template<typename T1, typename T2>
|
||||
inline std::size_t HashPair(T1 value1, T2 value2) {
|
||||
// This condition is expected to be compile-time evaluated and optimised away
|
||||
// in release builds.
|
||||
if (sizeof(T1) > sizeof(uint32_t) || (sizeof(T2) > sizeof(uint32_t)))
|
||||
return HashInts64(value1, value2);
|
||||
|
||||
return HashInts32(value1, value2);
|
||||
}
|
||||
|
||||
DEFINE_32BIT_PAIR_HASH(int16, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(int16, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(int16, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(int16, uint32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, uint32);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, uint32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, uint32);
|
||||
|
||||
#undef DEFINE_32BIT_PAIR_HASH
|
||||
|
||||
#define DEFINE_64BIT_PAIR_HASH(Type1, Type2) \
|
||||
inline std::size_t HashPair(Type1 value1, Type2 value2) { \
|
||||
return HashInts64(value1, value2); \
|
||||
}
|
||||
|
||||
DEFINE_64BIT_PAIR_HASH(int16, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(int16, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint16, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint16, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(int32, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(int32, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint32, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint32, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, int16);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, uint16);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, int32);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, uint32);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, int16);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, uint16);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, int32);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, uint32);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, uint64);
|
||||
|
||||
#undef DEFINE_64BIT_PAIR_HASH
|
||||
} // namespace base
|
||||
|
||||
namespace BASE_HASH_NAMESPACE {
|
||||
@ -320,7 +273,7 @@ struct hash<std::pair<Type1, Type2> > {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace BASE_HASH_NAMESPACE
|
||||
|
||||
#undef DEFINE_PAIR_HASH_FUNCTION_START
|
||||
#undef DEFINE_PAIR_HASH_FUNCTION_END
|
||||
|
@ -4,12 +4,15 @@
|
||||
|
||||
#include "base/cpu.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
@ -43,7 +46,7 @@ CPU::CPU()
|
||||
has_sse41_(false),
|
||||
has_sse42_(false),
|
||||
has_avx_(false),
|
||||
has_avx_hardware_(false),
|
||||
has_avx2_(false),
|
||||
has_aesni_(false),
|
||||
has_non_stop_time_stamp_counter_(false),
|
||||
has_broken_neon_(false),
|
||||
@ -72,7 +75,7 @@ void __cpuid(int cpu_info[4], int info_type) {
|
||||
|
||||
void __cpuid(int cpu_info[4], int info_type) {
|
||||
__asm__ volatile (
|
||||
"cpuid \n\t"
|
||||
"cpuid\n"
|
||||
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
|
||||
: "a"(info_type)
|
||||
);
|
||||
@ -82,11 +85,12 @@ void __cpuid(int cpu_info[4], int info_type) {
|
||||
|
||||
// _xgetbv returns the value of an Intel Extended Control Register (XCR).
|
||||
// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
|
||||
uint64 _xgetbv(uint32 xcr) {
|
||||
uint32 eax, edx;
|
||||
uint64_t _xgetbv(uint32_t xcr) {
|
||||
uint32_t eax, edx;
|
||||
|
||||
__asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr));
|
||||
return (static_cast<uint64>(edx) << 32) | eax;
|
||||
__asm__ volatile (
|
||||
"xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
|
||||
return (static_cast<uint64_t>(edx) << 32) | eax;
|
||||
}
|
||||
|
||||
#endif // !_MSC_VER
|
||||
@ -110,7 +114,7 @@ class LazyCpuInfoValue {
|
||||
revision = 0;
|
||||
const struct {
|
||||
const char key[17];
|
||||
unsigned *result;
|
||||
unsigned int* result;
|
||||
} kUnsignedValues[] = {
|
||||
{"CPU implementer", &implementer},
|
||||
{"CPU architecture", &architecture},
|
||||
@ -156,7 +160,7 @@ class LazyCpuInfoValue {
|
||||
|
||||
// The string may have leading "0x" or not, so we use strtoul to
|
||||
// handle that.
|
||||
char *endptr;
|
||||
char* endptr;
|
||||
std::string value(value_sp.as_string());
|
||||
unsigned long int result = strtoul(value.c_str(), &endptr, 0);
|
||||
if (*endptr == 0 && result <= UINT_MAX) {
|
||||
@ -211,7 +215,11 @@ void CPU::Initialize() {
|
||||
|
||||
// Interpret CPU feature information.
|
||||
if (num_ids > 0) {
|
||||
int cpu_info7[4] = {0};
|
||||
__cpuid(cpu_info, 1);
|
||||
if (num_ids >= 7) {
|
||||
__cpuid(cpu_info7, 7);
|
||||
}
|
||||
signature_ = cpu_info[0];
|
||||
stepping_ = cpu_info[0] & 0xf;
|
||||
model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
|
||||
@ -226,8 +234,6 @@ void CPU::Initialize() {
|
||||
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
|
||||
has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
|
||||
has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
|
||||
has_avx_hardware_ =
|
||||
(cpu_info[2] & 0x10000000) != 0;
|
||||
// AVX instructions will generate an illegal instruction exception unless
|
||||
// a) they are supported by the CPU,
|
||||
// b) XSAVE is supported by the CPU and
|
||||
@ -239,11 +245,12 @@ void CPU::Initialize() {
|
||||
// Because of that, we also test the XSAVE bit because its description in
|
||||
// the CPUID documentation suggests that it signals xgetbv support.
|
||||
has_avx_ =
|
||||
has_avx_hardware_ &&
|
||||
(cpu_info[2] & 0x10000000) != 0 &&
|
||||
(cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
|
||||
(cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
|
||||
(_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
|
||||
has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
|
||||
has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0;
|
||||
}
|
||||
|
||||
// Get the brand string of the cpu.
|
||||
@ -275,6 +282,7 @@ void CPU::Initialize() {
|
||||
}
|
||||
|
||||
CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
|
||||
if (has_avx2()) return AVX2;
|
||||
if (has_avx()) return AVX;
|
||||
if (has_sse42()) return SSE42;
|
||||
if (has_sse41()) return SSE41;
|
||||
|
@ -26,6 +26,7 @@ class BASE_EXPORT CPU {
|
||||
SSE41,
|
||||
SSE42,
|
||||
AVX,
|
||||
AVX2,
|
||||
MAX_INTEL_MICRO_ARCHITECTURE
|
||||
};
|
||||
|
||||
@ -46,12 +47,7 @@ class BASE_EXPORT CPU {
|
||||
bool has_sse41() const { return has_sse41_; }
|
||||
bool has_sse42() const { return has_sse42_; }
|
||||
bool has_avx() const { return has_avx_; }
|
||||
// has_avx_hardware returns true when AVX is present in the CPU. This might
|
||||
// differ from the value of |has_avx()| because |has_avx()| also tests for
|
||||
// operating system support needed to actually call AVX instuctions.
|
||||
// Note: you should never need to call this function. It was added in order
|
||||
// to workaround a bug in NSS but |has_avx()| is what you want.
|
||||
bool has_avx_hardware() const { return has_avx_hardware_; }
|
||||
bool has_avx2() const { return has_avx2_; }
|
||||
bool has_aesni() const { return has_aesni_; }
|
||||
bool has_non_stop_time_stamp_counter() const {
|
||||
return has_non_stop_time_stamp_counter_;
|
||||
@ -83,7 +79,7 @@ class BASE_EXPORT CPU {
|
||||
bool has_sse41_;
|
||||
bool has_sse42_;
|
||||
bool has_avx_;
|
||||
bool has_avx_hardware_;
|
||||
bool has_avx2_;
|
||||
bool has_aesni_;
|
||||
bool has_non_stop_time_stamp_counter_;
|
||||
bool has_broken_neon_;
|
||||
|
@ -6,8 +6,8 @@
|
||||
// debuggers. You should use this to test if you're running under a debugger,
|
||||
// and if you would like to yield (breakpoint) into the debugger.
|
||||
|
||||
#ifndef BASE_DEBUG_DEBUGGER_H
|
||||
#define BASE_DEBUG_DEBUGGER_H
|
||||
#ifndef BASE_DEBUG_DEBUGGER_H_
|
||||
#define BASE_DEBUG_DEBUGGER_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
@ -41,4 +41,4 @@ BASE_EXPORT bool IsDebugUISuppressed();
|
||||
} // namespace debug
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_DEBUG_DEBUGGER_H
|
||||
#endif // BASE_DEBUG_DEBUGGER_H_
|
||||
|
@ -5,7 +5,7 @@
|
||||
#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
|
||||
#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
// This file defines macros which can be used to annotate intentional memory
|
||||
@ -21,15 +21,7 @@
|
||||
|
||||
#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
|
||||
|
||||
// Public LSan API from <sanitizer/lsan_interface.h>.
|
||||
extern "C" {
|
||||
void __lsan_disable();
|
||||
void __lsan_enable();
|
||||
void __lsan_ignore_object(const void *p);
|
||||
|
||||
// Invoke leak detection immediately. If leaks are found, the process will exit.
|
||||
void __lsan_do_leak_check();
|
||||
} // extern "C"
|
||||
#include <sanitizer/lsan_interface.h>
|
||||
|
||||
class ScopedLeakSanitizerDisabler {
|
||||
public:
|
||||
@ -46,7 +38,6 @@ class ScopedLeakSanitizerDisabler {
|
||||
|
||||
#else
|
||||
|
||||
// If neither HeapChecker nor LSan are used, the annotations should be no-ops.
|
||||
#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
|
||||
#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
|
||||
|
||||
|
@ -6,16 +6,18 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/debug/debugging_flags.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/pe_image.h"
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
// TODO(peria): Enable profiling on Windows.
|
||||
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
|
||||
#endif
|
||||
|
||||
@ -23,15 +25,15 @@ namespace base {
|
||||
namespace debug {
|
||||
|
||||
// TODO(peria): Enable profiling on Windows.
|
||||
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
|
||||
static int profile_count = 0;
|
||||
|
||||
void StartProfiling(const std::string& name) {
|
||||
++profile_count;
|
||||
std::string full_name(name);
|
||||
std::string pid = StringPrintf("%d", GetCurrentProcId());
|
||||
std::string count = StringPrintf("%d", profile_count);
|
||||
std::string pid = IntToString(GetCurrentProcId());
|
||||
std::string count = IntToString(profile_count);
|
||||
ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
|
||||
ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
|
||||
ProfilerStart(full_name.c_str());
|
||||
|
@ -2,13 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_DEBUG_PROFILER_H
|
||||
#define BASE_DEBUG_PROFILER_H
|
||||
#ifndef BASE_DEBUG_PROFILER_H_
|
||||
#define BASE_DEBUG_PROFILER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
// The Profiler functions allow usage of the underlying sampling based
|
||||
// profiler. If the application has not been built with the necessary
|
||||
@ -87,4 +88,4 @@ BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc();
|
||||
} // namespace debug
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_DEBUG_DEBUGGER_H
|
||||
#endif // BASE_DEBUG_PROFILER_H_
|
||||
|
@ -14,9 +14,16 @@ namespace base {
|
||||
// We introduct a special structure for file descriptors in order that we are
|
||||
// able to use template specialisation to special-case their handling.
|
||||
//
|
||||
// WARNING: (Chromium only) There are subtleties to consider if serialising
|
||||
// these objects over IPC. See comments in ipc/ipc_message_utils.h
|
||||
// above the template specialisation for this structure.
|
||||
// IMPORTANT: This is primarily intended for use when sending file descriptors
|
||||
// over IPC. Even if |auto_close| is true, base::FileDescriptor does NOT close()
|
||||
// |fd| when going out of scope. Instead, a consumer of a base::FileDescriptor
|
||||
// must invoke close() on |fd| if |auto_close| is true.
|
||||
//
|
||||
// In the case of IPC, the the IPC subsystem knows to close() |fd| after sending
|
||||
// a message that contains a base::FileDescriptor if auto_close == true. On the
|
||||
// other end, the receiver must make sure to close() |fd| after it has finished
|
||||
// processing the IPC message. See the IPC::ParamTraits<> specialization in
|
||||
// ipc/ipc_message_utils.h for all the details.
|
||||
// -----------------------------------------------------------------------------
|
||||
struct FileDescriptor {
|
||||
FileDescriptor() : fd(-1), auto_close(false) {}
|
||||
|
@ -53,7 +53,7 @@
|
||||
// between char[]-based pathnames on POSIX systems and wchar_t[]-based
|
||||
// pathnames on Windows.
|
||||
//
|
||||
// Paths can't contain NULs as a precaution agaist premature truncation.
|
||||
// As a precaution against premature truncation, paths can't contain NULs.
|
||||
//
|
||||
// Because a FilePath object should not be instantiated at the global scope,
|
||||
// instead, use a FilePath::CharType[] and initialize it with
|
||||
@ -83,9 +83,9 @@
|
||||
// in case it ever comes across such a system. FilePath needs this support
|
||||
// for Windows UNC paths, anyway.
|
||||
// References:
|
||||
// The Open Group Base Specifications Issue 7, sections 3.266 ("Pathname")
|
||||
// The Open Group Base Specifications Issue 7, sections 3.267 ("Pathname")
|
||||
// and 4.12 ("Pathname Resolution"), available at:
|
||||
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_266
|
||||
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_267
|
||||
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_12
|
||||
//
|
||||
// - Windows treats c:\\ the same way it treats \\. This was intended to
|
||||
@ -103,13 +103,17 @@
|
||||
#define BASE_FILES_FILE_PATH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/string_piece.h" // For implicit conversions.
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
// Windows-style drive letter support and pathname separator characters can be
|
||||
@ -121,11 +125,20 @@
|
||||
#define FILE_PATH_USES_WIN_SEPARATORS
|
||||
#endif // OS_WIN
|
||||
|
||||
class Pickle;
|
||||
class PickleIterator;
|
||||
// To print path names portably use PRIsFP (based on PRIuS and friends from
|
||||
// C99 and format_macros.h) like this:
|
||||
// base::StringPrintf("Path is %" PRIsFP ".\n", path.value().c_str());
|
||||
#if defined(OS_POSIX)
|
||||
#define PRIsFP "s"
|
||||
#elif defined(OS_WIN)
|
||||
#define PRIsFP "ls"
|
||||
#endif // OS_WIN
|
||||
|
||||
namespace base {
|
||||
|
||||
class Pickle;
|
||||
class PickleIterator;
|
||||
|
||||
// An abstraction to isolate users from the differences between native
|
||||
// pathnames on different platforms.
|
||||
class BASE_EXPORT FilePath {
|
||||
@ -141,6 +154,7 @@ class BASE_EXPORT FilePath {
|
||||
typedef std::wstring StringType;
|
||||
#endif // OS_WIN
|
||||
|
||||
typedef BasicStringPiece<StringType> StringPieceType;
|
||||
typedef StringType::value_type CharType;
|
||||
|
||||
// Null-terminated array of separators used to separate components in
|
||||
@ -163,7 +177,7 @@ class BASE_EXPORT FilePath {
|
||||
|
||||
FilePath();
|
||||
FilePath(const FilePath& that);
|
||||
explicit FilePath(const StringType& path);
|
||||
explicit FilePath(StringPieceType path);
|
||||
~FilePath();
|
||||
FilePath& operator=(const FilePath& that);
|
||||
|
||||
@ -237,7 +251,7 @@ class BASE_EXPORT FilePath {
|
||||
// ASSERT(new_path == path.value());
|
||||
// NOTE: this is different from the original file_util implementation which
|
||||
// returned the extension without a leading "." ("jpg" instead of ".jpg")
|
||||
StringType Extension() const;
|
||||
StringType Extension() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns the path's file extension, as in Extension(), but will
|
||||
// never return a double extension.
|
||||
@ -246,7 +260,7 @@ class BASE_EXPORT FilePath {
|
||||
// we can rename this to Extension() and the other to something like
|
||||
// LongExtension(), defaulting to short extensions and leaving the
|
||||
// long "extensions" to logic like base::GetUniquePathNumber().
|
||||
StringType FinalExtension() const;
|
||||
StringType FinalExtension() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
|
||||
// NOTE: this is slightly different from the similar file_util implementation
|
||||
@ -265,25 +279,23 @@ class BASE_EXPORT FilePath {
|
||||
// path == "C:\pics\jojo" suffix == " (1)", returns "C:\pics\jojo (1)"
|
||||
// path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)"
|
||||
FilePath InsertBeforeExtension(
|
||||
const StringType& suffix) const WARN_UNUSED_RESULT;
|
||||
StringPieceType suffix) const WARN_UNUSED_RESULT;
|
||||
FilePath InsertBeforeExtensionASCII(
|
||||
const base::StringPiece& suffix) const WARN_UNUSED_RESULT;
|
||||
StringPiece suffix) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Adds |extension| to |file_name|. Returns the current FilePath if
|
||||
// |extension| is empty. Returns "" if BaseName() == "." or "..".
|
||||
FilePath AddExtension(
|
||||
const StringType& extension) const WARN_UNUSED_RESULT;
|
||||
FilePath AddExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Replaces the extension of |file_name| with |extension|. If |file_name|
|
||||
// does not have an extension, then |extension| is added. If |extension| is
|
||||
// empty, then the extension is removed from |file_name|.
|
||||
// Returns "" if BaseName() == "." or "..".
|
||||
FilePath ReplaceExtension(
|
||||
const StringType& extension) const WARN_UNUSED_RESULT;
|
||||
FilePath ReplaceExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns true if the file path matches the specified extension. The test is
|
||||
// case insensitive. Don't forget the leading period if appropriate.
|
||||
bool MatchesExtension(const StringType& extension) const;
|
||||
bool MatchesExtension(StringPieceType extension) const;
|
||||
|
||||
// Returns a FilePath by appending a separator and the supplied path
|
||||
// component to this object's path. Append takes care to avoid adding
|
||||
@ -291,7 +303,7 @@ class BASE_EXPORT FilePath {
|
||||
// If this object's path is kCurrentDirectory, a new FilePath corresponding
|
||||
// only to |component| is returned. |component| must be a relative path;
|
||||
// it is an error to pass an absolute path.
|
||||
FilePath Append(const StringType& component) const WARN_UNUSED_RESULT;
|
||||
FilePath Append(StringPieceType component) const WARN_UNUSED_RESULT;
|
||||
FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Although Windows StringType is std::wstring, since the encoding it uses for
|
||||
@ -300,8 +312,7 @@ class BASE_EXPORT FilePath {
|
||||
// On Linux, although it can use any 8-bit encoding for paths, we assume that
|
||||
// ASCII is a valid subset, regardless of the encoding, since many operating
|
||||
// system paths will always be ASCII.
|
||||
FilePath AppendASCII(const base::StringPiece& component)
|
||||
const WARN_UNUSED_RESULT;
|
||||
FilePath AppendASCII(StringPiece component) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns true if this FilePath contains an absolute path. On Windows, an
|
||||
// absolute path begins with either a drive letter specification followed by
|
||||
@ -385,14 +396,14 @@ class BASE_EXPORT FilePath {
|
||||
// on parts of a file path, e.g., just the extension.
|
||||
// CompareIgnoreCase() returns -1, 0 or 1 for less-than, equal-to and
|
||||
// greater-than respectively.
|
||||
static int CompareIgnoreCase(const StringType& string1,
|
||||
const StringType& string2);
|
||||
static bool CompareEqualIgnoreCase(const StringType& string1,
|
||||
const StringType& string2) {
|
||||
static int CompareIgnoreCase(StringPieceType string1,
|
||||
StringPieceType string2);
|
||||
static bool CompareEqualIgnoreCase(StringPieceType string1,
|
||||
StringPieceType string2) {
|
||||
return CompareIgnoreCase(string1, string2) == 0;
|
||||
}
|
||||
static bool CompareLessIgnoreCase(const StringType& string1,
|
||||
const StringType& string2) {
|
||||
static bool CompareLessIgnoreCase(StringPieceType string1,
|
||||
StringPieceType string2) {
|
||||
return CompareIgnoreCase(string1, string2) < 0;
|
||||
}
|
||||
|
||||
@ -402,14 +413,14 @@ class BASE_EXPORT FilePath {
|
||||
// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
|
||||
// for further comments.
|
||||
// Returns the epmty string if the conversion failed.
|
||||
static StringType GetHFSDecomposedForm(const FilePath::StringType& string);
|
||||
static StringType GetHFSDecomposedForm(StringPieceType string);
|
||||
|
||||
// Special UTF-8 version of FastUnicodeCompare. Cf:
|
||||
// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
|
||||
// IMPORTANT: The input strings must be in the special HFS decomposed form!
|
||||
// (cf. above GetHFSDecomposedForm method)
|
||||
static int HFSFastUnicodeCompare(const StringType& string1,
|
||||
const StringType& string2);
|
||||
static int HFSFastUnicodeCompare(StringPieceType string1,
|
||||
StringPieceType string2);
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
@ -432,21 +443,22 @@ class BASE_EXPORT FilePath {
|
||||
StringType path_;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
// This is required by googletest to print a readable output on test failures.
|
||||
BASE_EXPORT extern void PrintTo(const base::FilePath& path, std::ostream* out);
|
||||
// This is declared here for use in gtest-based unit tests but is defined in
|
||||
// the test_support_base target. Depend on that to use this in your unit test.
|
||||
// This should not be used in production code - call ToString() instead.
|
||||
void PrintTo(const FilePath& path, std::ostream* out);
|
||||
|
||||
} // namespace base
|
||||
|
||||
// Macros for string literal initialization of FilePath::CharType[], and for
|
||||
// using a FilePath::CharType[] in a printf-style format string.
|
||||
#if defined(OS_POSIX)
|
||||
#define FILE_PATH_LITERAL(x) x
|
||||
#define PRFilePath "s"
|
||||
#define PRFilePathLiteral "%s"
|
||||
#elif defined(OS_WIN)
|
||||
#define FILE_PATH_LITERAL(x) L ## x
|
||||
#define PRFilePath "ls"
|
||||
#define PRFilePathLiteral L"%ls"
|
||||
#endif // OS_WIN
|
||||
|
||||
// Provide a hash function so that hash_sets and maps can contain FilePath
|
||||
|
@ -1,36 +0,0 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_FLOAT_UTIL_H_
|
||||
#define BASE_FLOAT_UTIL_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Float>
|
||||
inline bool IsFinite(const Float& number) {
|
||||
#if defined(OS_POSIX)
|
||||
return std::isfinite(number) != 0;
|
||||
#elif defined(OS_WIN)
|
||||
return _finite(number) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Float>
|
||||
inline bool IsNaN(const Float& number) {
|
||||
#if defined(OS_POSIX)
|
||||
return std::isnan(number) != 0;
|
||||
#elif defined(OS_WIN)
|
||||
return _isnan(number) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_FLOAT_UTIL_H_
|
@ -5,10 +5,11 @@
|
||||
#ifndef BASE_GUID_H_
|
||||
#define BASE_GUID_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
@ -24,7 +25,7 @@ BASE_EXPORT bool IsValidGUID(const std::string& guid);
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// For unit testing purposes only. Do not use outside of tests.
|
||||
BASE_EXPORT std::string RandomDataToGUIDString(const uint64 bytes[2]);
|
||||
BASE_EXPORT std::string RandomDataToGUIDString(const uint64_t bytes[2]);
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
@ -11,7 +11,7 @@ extern "C" uint32_t SuperFastHash(const char* data, int len);
|
||||
|
||||
namespace base {
|
||||
|
||||
uint32 SuperFastHash(const char* data, int len) {
|
||||
uint32_t SuperFastHash(const char* data, int len) {
|
||||
return ::SuperFastHash(data, len);
|
||||
}
|
||||
|
||||
|
@ -5,21 +5,23 @@
|
||||
#ifndef BASE_HASH_H_
|
||||
#define BASE_HASH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
BASE_EXPORT uint32 SuperFastHash(const char* data, int len);
|
||||
BASE_EXPORT uint32_t SuperFastHash(const char* data, int len);
|
||||
|
||||
// Computes a hash of a memory buffer |data| of a given |length|.
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
inline uint32 Hash(const char* data, size_t length) {
|
||||
inline uint32_t Hash(const char* data, size_t length) {
|
||||
if (length > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
NOTREACHED();
|
||||
return 0;
|
||||
@ -29,7 +31,7 @@ inline uint32 Hash(const char* data, size_t length) {
|
||||
|
||||
// Computes a hash of a string |str|.
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
inline uint32 Hash(const std::string& str) {
|
||||
inline uint32_t Hash(const std::string& str) {
|
||||
return Hash(str.data(), str.size());
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/atomicops.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
|
||||
namespace base {
|
||||
|
@ -39,7 +39,6 @@
|
||||
|
||||
#include "base/atomicops.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/debug/leak_annotations.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/aligned_memory.h"
|
||||
|
@ -31,6 +31,13 @@ Location::Location()
|
||||
program_counter_(NULL) {
|
||||
}
|
||||
|
||||
Location::Location(const Location& other)
|
||||
: function_name_(other.function_name_),
|
||||
file_name_(other.file_name_),
|
||||
line_number_(other.line_number_),
|
||||
program_counter_(other.program_counter_) {
|
||||
}
|
||||
|
||||
std::string Location::ToString() const {
|
||||
return std::string(function_name_) + "@" + file_name_ + ":" +
|
||||
base::IntToString(line_number_);
|
||||
|
@ -5,10 +5,13 @@
|
||||
#ifndef BASE_LOCATION_H_
|
||||
#define BASE_LOCATION_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/containers/hash_tables.h"
|
||||
|
||||
namespace tracked_objects {
|
||||
|
||||
@ -27,18 +30,15 @@ class BASE_EXPORT Location {
|
||||
// Provide a default constructor for easy of debugging.
|
||||
Location();
|
||||
|
||||
// Comparison operator for insertion into a std::map<> hash tables.
|
||||
// All we need is *some* (any) hashing distinction. Strings should already
|
||||
// be unique, so we don't bother with strcmp or such.
|
||||
// Use line number as the primary key (because it is fast, and usually gets us
|
||||
// a difference), and then pointers as secondary keys (just to get some
|
||||
// distinctions).
|
||||
bool operator < (const Location& other) const {
|
||||
if (line_number_ != other.line_number_)
|
||||
return line_number_ < other.line_number_;
|
||||
if (file_name_ != other.file_name_)
|
||||
return file_name_ < other.file_name_;
|
||||
return function_name_ < other.function_name_;
|
||||
// Copy constructor.
|
||||
Location(const Location& other);
|
||||
|
||||
// Comparator for hash map insertion.
|
||||
// No need to use |function_name_| since the other two fields uniquely
|
||||
// identify this location.
|
||||
bool operator==(const Location& other) const {
|
||||
return line_number_ == other.line_number_ &&
|
||||
file_name_ == other.file_name_;
|
||||
}
|
||||
|
||||
const char* function_name() const { return function_name_; }
|
||||
@ -48,6 +48,22 @@ class BASE_EXPORT Location {
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
// Hash operator for hash maps.
|
||||
struct Hash {
|
||||
size_t operator()(const Location& location) const {
|
||||
// Compute the hash value using file name pointer and line number.
|
||||
// No need to use |function_name_| since the other two fields uniquely
|
||||
// identify this location.
|
||||
|
||||
// The file name will always be uniquely identified by its pointer since
|
||||
// it comes from __FILE__, so no need to check the contents of the string.
|
||||
// See the definition of FROM_HERE in location.h, and how it is used
|
||||
// elsewhere.
|
||||
return base::HashPair(reinterpret_cast<uintptr_t>(location.file_name()),
|
||||
location.line_number());
|
||||
}
|
||||
};
|
||||
|
||||
// Translate the some of the state in this instance into a human readable
|
||||
// string with HTML characters in the function names escaped, and append that
|
||||
// string to |output|. Inclusion of the file_name_ and function_name_ are
|
||||
|
@ -5,14 +5,16 @@
|
||||
#ifndef BASE_LOGGING_H_
|
||||
#define BASE_LOGGING_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/debug/debugger.h"
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
//
|
||||
@ -238,6 +240,9 @@ BASE_EXPORT void SetMinLogLevel(int level);
|
||||
// Gets the current log level.
|
||||
BASE_EXPORT int GetMinLogLevel();
|
||||
|
||||
// Used by LOG_IS_ON to lazy-evaluate stream arguments.
|
||||
BASE_EXPORT bool ShouldCreateLogMessage(int severity);
|
||||
|
||||
// Gets the VLOG default verbosity level.
|
||||
BASE_EXPORT int GetVlogVerbosity();
|
||||
|
||||
@ -340,7 +345,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
|
||||
// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
|
||||
// always fire if they fail.
|
||||
#define LOG_IS_ON(severity) \
|
||||
((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel())
|
||||
(::logging::ShouldCreateLogMessage(::logging::LOG_##severity))
|
||||
|
||||
// We can't do any caching tricks with VLOG_IS_ON() like the
|
||||
// google-glog version since it requires GCC extensions. This means
|
||||
@ -350,7 +355,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
|
||||
((verboselevel) <= ::logging::GetVlogLevel(__FILE__))
|
||||
|
||||
// Helper macro which avoids evaluating the arguments to a stream if
|
||||
// the condition doesn't hold.
|
||||
// the condition doesn't hold. Condition is evaluated once and only once.
|
||||
#define LAZY_STREAM(stream, condition) \
|
||||
!(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)
|
||||
|
||||
@ -426,6 +431,21 @@ const LogSeverity LOG_0 = LOG_ERROR;
|
||||
#define EAT_STREAM_PARAMETERS \
|
||||
true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
|
||||
|
||||
// Captures the result of a CHECK_EQ (for example) and facilitates testing as a
|
||||
// boolean.
|
||||
class CheckOpResult {
|
||||
public:
|
||||
// |message| must be null if and only if the check failed.
|
||||
CheckOpResult(std::string* message) : message_(message) {}
|
||||
// Returns true if the check succeeded.
|
||||
operator bool() const { return !message_; }
|
||||
// Returns the message.
|
||||
std::string* message() { return message_; }
|
||||
|
||||
private:
|
||||
std::string* message_;
|
||||
};
|
||||
|
||||
// CHECK dies with a fatal error if condition is not true. It is *not*
|
||||
// controlled by NDEBUG, so the check will be executed regardless of
|
||||
// compilation mode.
|
||||
@ -436,7 +456,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
|
||||
#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID)
|
||||
|
||||
// Make all CHECK functions discard their log strings to reduce code
|
||||
// bloat for official release builds.
|
||||
// bloat for official release builds (except Android).
|
||||
|
||||
// TODO(akalin): This would be more valuable if there were some way to
|
||||
// remove BreakDebugger() from the backtrace, perhaps by turning it
|
||||
@ -470,9 +490,10 @@ const LogSeverity LOG_0 = LOG_ERROR;
|
||||
|
||||
#else // _PREFAST_
|
||||
|
||||
// Do as much work as possible out of line to reduce inline code size.
|
||||
#define CHECK(condition) \
|
||||
LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
|
||||
<< "Check failed: " #condition ". "
|
||||
LAZY_STREAM(logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
|
||||
!(condition))
|
||||
|
||||
#define PCHECK(condition) \
|
||||
LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
|
||||
@ -482,14 +503,18 @@ const LogSeverity LOG_0 = LOG_ERROR;
|
||||
|
||||
// Helper macro for binary operators.
|
||||
// Don't use this macro directly in your code, use CHECK_EQ et al below.
|
||||
//
|
||||
// TODO(akalin): Rewrite this so that constructs like if (...)
|
||||
// CHECK_EQ(...) else { ... } work properly.
|
||||
// The 'switch' is used to prevent the 'else' from being ambiguous when the
|
||||
// macro is used in an 'if' clause such as:
|
||||
// if (a == 1)
|
||||
// CHECK_EQ(2, a);
|
||||
#define CHECK_OP(name, op, val1, val2) \
|
||||
if (std::string* _result = \
|
||||
switch (0) case 0: default: \
|
||||
if (logging::CheckOpResult true_if_passed = \
|
||||
logging::Check##name##Impl((val1), (val2), \
|
||||
#val1 " " #op " " #val2)) \
|
||||
logging::LogMessage(__FILE__, __LINE__, _result).stream()
|
||||
; \
|
||||
else \
|
||||
logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
|
||||
|
||||
#endif
|
||||
|
||||
@ -551,7 +576,6 @@ DEFINE_CHECK_OP_IMPL(GT, > )
|
||||
#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
|
||||
#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
|
||||
#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
|
||||
#define CHECK_IMPLIES(val1, val2) CHECK(!(val1) || (val2))
|
||||
|
||||
#if defined(NDEBUG)
|
||||
#define ENABLE_DLOG 0
|
||||
@ -560,9 +584,9 @@ DEFINE_CHECK_OP_IMPL(GT, > )
|
||||
#endif
|
||||
|
||||
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
|
||||
#define DCHECK_IS_ON 0
|
||||
#define DCHECK_IS_ON() 0
|
||||
#else
|
||||
#define DCHECK_IS_ON 1
|
||||
#define DCHECK_IS_ON() 1
|
||||
#endif
|
||||
|
||||
// Definitions for DLOG et al.
|
||||
@ -616,14 +640,14 @@ enum { DEBUG_MODE = ENABLE_DLOG };
|
||||
|
||||
// Definitions for DCHECK et al.
|
||||
|
||||
#if DCHECK_IS_ON
|
||||
#if DCHECK_IS_ON()
|
||||
|
||||
#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
|
||||
COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__)
|
||||
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL
|
||||
const LogSeverity LOG_DCHECK = LOG_FATAL;
|
||||
|
||||
#else // DCHECK_IS_ON
|
||||
#else // DCHECK_IS_ON()
|
||||
|
||||
// These are just dummy values.
|
||||
#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
|
||||
@ -631,7 +655,7 @@ const LogSeverity LOG_DCHECK = LOG_FATAL;
|
||||
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO
|
||||
const LogSeverity LOG_DCHECK = LOG_INFO;
|
||||
|
||||
#endif // DCHECK_IS_ON
|
||||
#endif // DCHECK_IS_ON()
|
||||
|
||||
// DCHECK et al. make sure to reference |condition| regardless of
|
||||
// whether DCHECKs are enabled; this is so that we don't get unused
|
||||
@ -654,25 +678,31 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
|
||||
#else // _PREFAST_
|
||||
|
||||
#define DCHECK(condition) \
|
||||
LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON ? !(condition) : false) \
|
||||
LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#define DPCHECK(condition) \
|
||||
LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON ? !(condition) : false) \
|
||||
LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#endif // _PREFAST_
|
||||
|
||||
// Helper macro for binary operators.
|
||||
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
|
||||
// The 'switch' is used to prevent the 'else' from being ambiguous when the
|
||||
// macro is used in an 'if' clause such as:
|
||||
// if (a == 1)
|
||||
// DCHECK_EQ(2, a);
|
||||
#define DCHECK_OP(name, op, val1, val2) \
|
||||
if (DCHECK_IS_ON) \
|
||||
if (std::string* _result = \
|
||||
switch (0) case 0: default: \
|
||||
if (logging::CheckOpResult true_if_passed = \
|
||||
DCHECK_IS_ON() ? \
|
||||
logging::Check##name##Impl((val1), (val2), \
|
||||
#val1 " " #op " " #val2)) \
|
||||
logging::LogMessage( \
|
||||
__FILE__, __LINE__, ::logging::LOG_DCHECK, \
|
||||
_result).stream()
|
||||
#val1 " " #op " " #val2) : nullptr) \
|
||||
; \
|
||||
else \
|
||||
logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, \
|
||||
true_if_passed.message()).stream()
|
||||
|
||||
// Equality/Inequality checks - compare two values, and log a
|
||||
// LOG_DCHECK message including the two values when the result is not
|
||||
@ -699,11 +729,14 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
|
||||
#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
|
||||
#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
|
||||
#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
|
||||
#define DCHECK_IMPLIES(val1, val2) DCHECK(!(val1) || (val2))
|
||||
|
||||
#if !DCHECK_IS_ON && defined(OS_CHROMEOS)
|
||||
#define NOTREACHED() LOG(ERROR) << "NOTREACHED() hit in " << \
|
||||
__FUNCTION__ << ". "
|
||||
#if !DCHECK_IS_ON() && defined(OS_CHROMEOS)
|
||||
// Implement logging of NOTREACHED() as a dedicated function to get function
|
||||
// call overhead down to a minimum.
|
||||
void LogErrorNotReached(const char* file, int line);
|
||||
#define NOTREACHED() \
|
||||
true ? ::logging::LogErrorNotReached(__FILE__, __LINE__) \
|
||||
: EAT_STREAM_PARAMETERS
|
||||
#else
|
||||
#define NOTREACHED() DCHECK(false)
|
||||
#endif
|
||||
@ -725,6 +758,9 @@ class BASE_EXPORT LogMessage {
|
||||
// Used for LOG(severity).
|
||||
LogMessage(const char* file, int line, LogSeverity severity);
|
||||
|
||||
// Used for CHECK(). Implied severity = LOG_FATAL.
|
||||
LogMessage(const char* file, int line, const char* condition);
|
||||
|
||||
// Used for CHECK_EQ(), etc. Takes ownership of the given string.
|
||||
// Implied severity = LOG_FATAL.
|
||||
LogMessage(const char* file, int line, std::string* result);
|
||||
@ -773,7 +809,7 @@ class BASE_EXPORT LogMessage {
|
||||
|
||||
// A non-macro interface to the log facility; (useful
|
||||
// when the logging level is not a compile-time constant).
|
||||
inline void LogAtLevel(int const log_level, std::string const &msg) {
|
||||
inline void LogAtLevel(int log_level, const std::string& msg) {
|
||||
LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
|
||||
}
|
||||
|
||||
@ -859,6 +895,9 @@ BASE_EXPORT void RawLog(int level, const char* message);
|
||||
} while (0)
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Returns true if logging to file is enabled.
|
||||
BASE_EXPORT bool IsLoggingToFileEnabled();
|
||||
|
||||
// Returns the default log file path.
|
||||
BASE_EXPORT std::wstring GetLogFileFullPath();
|
||||
#endif
|
||||
@ -918,9 +957,9 @@ inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
|
||||
#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
|
||||
#elif NOTIMPLEMENTED_POLICY == 1
|
||||
// TODO, figure out how to generate a warning
|
||||
#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
|
||||
#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
|
||||
#elif NOTIMPLEMENTED_POLICY == 2
|
||||
#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
|
||||
#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
|
||||
#elif NOTIMPLEMENTED_POLICY == 3
|
||||
#define NOTIMPLEMENTED() NOTREACHED()
|
||||
#elif NOTIMPLEMENTED_POLICY == 4
|
||||
|
@ -11,17 +11,14 @@
|
||||
#define BASE_MACROS_H_
|
||||
|
||||
#include <stddef.h> // For size_t.
|
||||
#include <string.h> // For memcpy.
|
||||
|
||||
#include "base/compiler_specific.h" // For ALLOW_UNUSED.
|
||||
|
||||
// Put this in the private: declarations for a class to be uncopyable.
|
||||
// Put this in the declarations for a class to be uncopyable.
|
||||
#define DISALLOW_COPY(TypeName) \
|
||||
TypeName(const TypeName&)
|
||||
TypeName(const TypeName&) = delete
|
||||
|
||||
// Put this in the private: declarations for a class to be unassignable.
|
||||
// Put this in the declarations for a class to be unassignable.
|
||||
#define DISALLOW_ASSIGN(TypeName) \
|
||||
void operator=(const TypeName&)
|
||||
void operator=(const TypeName&) = delete
|
||||
|
||||
// A macro to disallow the copy constructor and operator= functions
|
||||
// This should be used in the private: declarations for a class
|
||||
@ -29,13 +26,6 @@
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
// An older, deprecated, politically incorrect name for the above.
|
||||
// NOTE: The usage of this macro was banned from our code base, but some
|
||||
// third_party libraries are yet using it.
|
||||
// TODO(tfarina): Figure out how to fix the usage of this macro in the
|
||||
// third_party libraries and get rid of it.
|
||||
#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName)
|
||||
|
||||
// A macro to disallow all the implicit constructors, namely the
|
||||
// default constructor, copy constructor and operator= functions.
|
||||
//
|
||||
@ -43,134 +33,21 @@
|
||||
// that wants to prevent anyone from instantiating it. This is
|
||||
// especially useful for classes containing only static methods.
|
||||
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
||||
TypeName(); \
|
||||
TypeName() = delete; \
|
||||
DISALLOW_COPY_AND_ASSIGN(TypeName)
|
||||
|
||||
// The arraysize(arr) macro returns the # of elements in an array arr.
|
||||
// The expression is a compile-time constant, and therefore can be
|
||||
// used in defining new arrays, for example. If you use arraysize on
|
||||
// a pointer by mistake, you will get a compile-time error.
|
||||
// The arraysize(arr) macro returns the # of elements in an array arr. The
|
||||
// expression is a compile-time constant, and therefore can be used in defining
|
||||
// new arrays, for example. If you use arraysize on a pointer by mistake, you
|
||||
// will get a compile-time error. For the technical details, refer to
|
||||
// http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx.
|
||||
|
||||
// This template function declaration is used in defining arraysize.
|
||||
// Note that the function doesn't need an implementation, as we only
|
||||
// use its type.
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||
|
||||
// That gcc wants both of these prototypes seems mysterious. VC, for
|
||||
// its part, can't decide which to use (another mystery). Matching of
|
||||
// template overloads: the final frontier.
|
||||
#ifndef _MSC_VER
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(const T (&array)[N]))[N];
|
||||
#endif
|
||||
|
||||
template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
|
||||
|
||||
|
||||
// Use implicit_cast as a safe version of static_cast or const_cast
|
||||
// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
|
||||
// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
|
||||
// a const pointer to Foo).
|
||||
// When you use implicit_cast, the compiler checks that the cast is safe.
|
||||
// Such explicit implicit_casts are necessary in surprisingly many
|
||||
// situations where C++ demands an exact type match instead of an
|
||||
// argument type convertible to a target type.
|
||||
//
|
||||
// The From type can be inferred, so the preferred syntax for using
|
||||
// implicit_cast is the same as for static_cast etc.:
|
||||
//
|
||||
// implicit_cast<ToType>(expr)
|
||||
//
|
||||
// implicit_cast would have been part of the C++ standard library,
|
||||
// but the proposal was submitted too late. It will probably make
|
||||
// its way into the language in the future.
|
||||
template<typename To, typename From>
|
||||
inline To implicit_cast(From const &f) {
|
||||
return f;
|
||||
}
|
||||
|
||||
// The COMPILE_ASSERT macro can be used to verify that a compile time
|
||||
// expression is true. For example, you could use it to verify the
|
||||
// size of a static array:
|
||||
//
|
||||
// COMPILE_ASSERT(arraysize(content_type_names) == CONTENT_NUM_TYPES,
|
||||
// content_type_names_incorrect_size);
|
||||
//
|
||||
// or to make sure a struct is smaller than a certain size:
|
||||
//
|
||||
// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
|
||||
//
|
||||
// The second argument to the macro is the name of the variable. If
|
||||
// the expression is false, most compilers will issue a warning/error
|
||||
// containing the name of the variable.
|
||||
|
||||
#undef COMPILE_ASSERT
|
||||
#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
|
||||
|
||||
// bit_cast<Dest,Source> is a template function that implements the
|
||||
// equivalent of "*reinterpret_cast<Dest*>(&source)". We need this in
|
||||
// very low-level functions like the protobuf library and fast math
|
||||
// support.
|
||||
//
|
||||
// float f = 3.14159265358979;
|
||||
// int i = bit_cast<int32>(f);
|
||||
// // i = 0x40490fdb
|
||||
//
|
||||
// The classical address-casting method is:
|
||||
//
|
||||
// // WRONG
|
||||
// float f = 3.14159265358979; // WRONG
|
||||
// int i = * reinterpret_cast<int*>(&f); // WRONG
|
||||
//
|
||||
// The address-casting method actually produces undefined behavior
|
||||
// according to ISO C++ specification section 3.10 -15 -. Roughly, this
|
||||
// section says: if an object in memory has one type, and a program
|
||||
// accesses it with a different type, then the result is undefined
|
||||
// behavior for most values of "different type".
|
||||
//
|
||||
// This is true for any cast syntax, either *(int*)&f or
|
||||
// *reinterpret_cast<int*>(&f). And it is particularly true for
|
||||
// conversions between integral lvalues and floating-point lvalues.
|
||||
//
|
||||
// The purpose of 3.10 -15- is to allow optimizing compilers to assume
|
||||
// that expressions with different types refer to different memory. gcc
|
||||
// 4.0.1 has an optimizer that takes advantage of this. So a
|
||||
// non-conforming program quietly produces wildly incorrect output.
|
||||
//
|
||||
// The problem is not the use of reinterpret_cast. The problem is type
|
||||
// punning: holding an object in memory of one type and reading its bits
|
||||
// back using a different type.
|
||||
//
|
||||
// The C++ standard is more subtle and complex than this, but that
|
||||
// is the basic idea.
|
||||
//
|
||||
// Anyways ...
|
||||
//
|
||||
// bit_cast<> calls memcpy() which is blessed by the standard,
|
||||
// especially by the example in section 3.9 . Also, of course,
|
||||
// bit_cast<> wraps up the nasty logic in one place.
|
||||
//
|
||||
// Fortunately memcpy() is very fast. In optimized mode, with a
|
||||
// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
|
||||
// code with the minimal amount of data movement. On a 32-bit system,
|
||||
// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
|
||||
// compiles to two loads and two stores.
|
||||
//
|
||||
// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
|
||||
//
|
||||
// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
|
||||
// is likely to surprise you.
|
||||
|
||||
template <class Dest, class Source>
|
||||
inline Dest bit_cast(const Source& source) {
|
||||
COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), VerifySizesAreEqual);
|
||||
|
||||
Dest dest;
|
||||
memcpy(&dest, &source, sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Used to explicitly mark the return value of a function as unused. If you are
|
||||
// really sure you don't want to do anything with the return value of a function
|
||||
// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
|
||||
|
@ -34,8 +34,10 @@
|
||||
#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
|
||||
#define BASE_MEMORY_ALIGNED_MEMORY_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
@ -55,17 +57,18 @@ struct AlignedMemory {};
|
||||
template <size_t Size> \
|
||||
class AlignedMemory<Size, byte_alignment> { \
|
||||
public: \
|
||||
ALIGNAS(byte_alignment) uint8 data_[Size]; \
|
||||
ALIGNAS(byte_alignment) uint8_t data_[Size]; \
|
||||
void* void_data() { return static_cast<void*>(data_); } \
|
||||
const void* void_data() const { \
|
||||
return static_cast<const void*>(data_); \
|
||||
const void* void_data() const { return static_cast<const void*>(data_); } \
|
||||
template <typename Type> \
|
||||
Type* data_as() { \
|
||||
return static_cast<Type*>(void_data()); \
|
||||
} \
|
||||
template<typename Type> \
|
||||
Type* data_as() { return static_cast<Type*>(void_data()); } \
|
||||
template<typename Type> \
|
||||
template <typename Type> \
|
||||
const Type* data_as() const { \
|
||||
return static_cast<const Type*>(void_data()); \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
void* operator new(size_t); \
|
||||
void operator delete(void*); \
|
||||
|
@ -47,79 +47,14 @@ struct ParamsUseScopedRefptrCorrectly {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple0> {
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
|
||||
enum { value = 1 };
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple1<A> > {
|
||||
enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple2<A, B> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple3<A, B, C> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple4<A, B, C, D> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple5<A, B, C, D, E> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<E>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E,
|
||||
typename F>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple6<A, B, C, D, E, F> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<E>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<F>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E,
|
||||
typename F, typename G>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple7<A, B, C, D, E, F, G> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<E>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<F>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<G>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E,
|
||||
typename F, typename G, typename H>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple8<A, B, C, D, E, F, G, H> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<E>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<F>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<G>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<H>::value) };
|
||||
template <typename Head, typename... Tail>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple<Head, Tail...>> {
|
||||
enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
|
||||
ParamsUseScopedRefptrCorrectly<Tuple<Tail...>>::value };
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -11,16 +11,12 @@
|
||||
#include "base/atomic_ref_count.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/macros.h"
|
||||
#ifndef NDEBUG
|
||||
#include "base/logging.h"
|
||||
#endif
|
||||
#include "base/threading/thread_collision_warner.h"
|
||||
#include "build/build_config.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_ANDROID)
|
||||
#define DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -122,7 +118,7 @@ class BASE_EXPORT RefCountedThreadSafeBase {
|
||||
// ~MyFoo();
|
||||
// };
|
||||
//
|
||||
// You should always make your destructor private, to avoid any code deleting
|
||||
// You should always make your destructor non-public, to avoid any code deleting
|
||||
// the object accidently while there are references to it.
|
||||
template <class T>
|
||||
class RefCounted : public subtle::RefCountedBase {
|
||||
@ -280,17 +276,29 @@ class scoped_refptr {
|
||||
AddRef(ptr_);
|
||||
}
|
||||
|
||||
// Copy constructor.
|
||||
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
|
||||
if (ptr_)
|
||||
AddRef(ptr_);
|
||||
}
|
||||
|
||||
// Copy conversion constructor.
|
||||
template <typename U>
|
||||
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
|
||||
if (ptr_)
|
||||
AddRef(ptr_);
|
||||
}
|
||||
|
||||
// Move constructor. This is required in addition to the conversion
|
||||
// constructor below in order for clang to warn about pessimizing moves.
|
||||
scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }
|
||||
|
||||
// Move conversion constructor.
|
||||
template <typename U>
|
||||
scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
|
||||
r.ptr_ = nullptr;
|
||||
}
|
||||
|
||||
~scoped_refptr() {
|
||||
if (ptr_)
|
||||
Release(ptr_);
|
||||
@ -298,12 +306,6 @@ class scoped_refptr {
|
||||
|
||||
T* get() const { return ptr_; }
|
||||
|
||||
#if !defined(DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR)
|
||||
// Allow scoped_refptr<C> to be used in boolean expression
|
||||
// and comparison operations.
|
||||
operator T*() const { return ptr_; }
|
||||
#endif
|
||||
|
||||
T& operator*() const {
|
||||
assert(ptr_ != NULL);
|
||||
return *ptr_;
|
||||
@ -334,6 +336,17 @@ class scoped_refptr {
|
||||
return *this = r.get();
|
||||
}
|
||||
|
||||
scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
|
||||
scoped_refptr<T>(std::move(r)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
|
||||
scoped_refptr<T>(std::move(r)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(T** pp) {
|
||||
T* p = ptr_;
|
||||
ptr_ = *pp;
|
||||
@ -344,7 +357,21 @@ class scoped_refptr {
|
||||
swap(&r.ptr_);
|
||||
}
|
||||
|
||||
#if defined(DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR)
|
||||
private:
|
||||
template <typename U> friend class scoped_refptr;
|
||||
|
||||
// Allow scoped_refptr<T> to be used in boolean expressions, but not
|
||||
// implicitly convertible to a real bool (which is dangerous).
|
||||
//
|
||||
// Note that this trick is only safe when the == and != operators
|
||||
// are declared explicitly, as otherwise "refptr1 == refptr2"
|
||||
// will compile but do the wrong thing (i.e., convert to Testable
|
||||
// and then do the comparison).
|
||||
typedef T* scoped_refptr::*Testable;
|
||||
|
||||
public:
|
||||
operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : nullptr; }
|
||||
|
||||
template <typename U>
|
||||
bool operator==(const scoped_refptr<U>& rhs) const {
|
||||
return ptr_ == rhs.get();
|
||||
@ -359,7 +386,6 @@ class scoped_refptr {
|
||||
bool operator<(const scoped_refptr<U>& rhs) const {
|
||||
return ptr_ < rhs.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
T* ptr_;
|
||||
@ -390,8 +416,8 @@ scoped_refptr<T> make_scoped_refptr(T* t) {
|
||||
return scoped_refptr<T>(t);
|
||||
}
|
||||
|
||||
#if defined(DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR)
|
||||
// Temporary operator overloads to facilitate the transition...
|
||||
// Temporary operator overloads to facilitate the transition. See
|
||||
// https://crbug.com/110610.
|
||||
template <typename T, typename U>
|
||||
bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
|
||||
return lhs.get() == rhs;
|
||||
@ -416,6 +442,5 @@ template <typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
|
||||
return out << p.get();
|
||||
}
|
||||
#endif // defined(DISABLE_SCOPED_REFPTR_CONVERSION_OPERATOR)
|
||||
|
||||
#endif // BASE_MEMORY_REF_COUNTED_H_
|
||||
|
@ -37,42 +37,43 @@
|
||||
// in that they are "movable but not copyable." You can use the scopers in
|
||||
// the parameter and return types of functions to signify ownership transfer
|
||||
// in to and out of a function. When calling a function that has a scoper
|
||||
// as the argument type, it must be called with the result of an analogous
|
||||
// scoper's Pass() function or another function that generates a temporary;
|
||||
// passing by copy will NOT work. Here is an example using scoped_ptr:
|
||||
// as the argument type, it must be called with an rvalue of a scoper, which
|
||||
// can be created by using std::move(), or the result of another function that
|
||||
// generates a temporary; passing by copy will NOT work. Here is an example
|
||||
// using scoped_ptr:
|
||||
//
|
||||
// void TakesOwnership(scoped_ptr<Foo> arg) {
|
||||
// // Do something with arg
|
||||
// // Do something with arg.
|
||||
// }
|
||||
// scoped_ptr<Foo> CreateFoo() {
|
||||
// // No need for calling Pass() because we are constructing a temporary
|
||||
// // for the return value.
|
||||
// // No need for calling std::move() for returning a move-only value, or
|
||||
// // when you already have an rvalue as we do here.
|
||||
// return scoped_ptr<Foo>(new Foo("new"));
|
||||
// }
|
||||
// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
|
||||
// return arg.Pass();
|
||||
// return arg;
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
|
||||
// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
|
||||
// TakesOwnership(std::move(ptr)); // ptr no longer owns Foo("yay").
|
||||
// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
|
||||
// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
|
||||
// PassThru(ptr2.Pass()); // ptr2 is correspondingly nullptr.
|
||||
// PassThru(std::move(ptr2)); // ptr2 is correspondingly nullptr.
|
||||
// }
|
||||
//
|
||||
// Notice that if you do not call Pass() when returning from PassThru(), or
|
||||
// Notice that if you do not call std::move() when returning from PassThru(), or
|
||||
// when invoking TakesOwnership(), the code will not compile because scopers
|
||||
// are not copyable; they only implement move semantics which require calling
|
||||
// the Pass() function to signify a destructive transfer of state. CreateFoo()
|
||||
// is different though because we are constructing a temporary on the return
|
||||
// line and thus can avoid needing to call Pass().
|
||||
// the std::move() function to signify a destructive transfer of state.
|
||||
// CreateFoo() is different though because we are constructing a temporary on
|
||||
// the return line and thus can avoid needing to call std::move().
|
||||
//
|
||||
// Pass() properly handles upcast in initialization, i.e. you can use a
|
||||
// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
|
||||
// The conversion move-constructor properly handles upcast in initialization,
|
||||
// i.e. you can use a scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
|
||||
//
|
||||
// scoped_ptr<Foo> foo(new Foo());
|
||||
// scoped_ptr<FooParent> parent(foo.Pass());
|
||||
// scoped_ptr<FooParent> parent(std::move(foo));
|
||||
|
||||
#ifndef BASE_MEMORY_SCOPED_PTR_H_
|
||||
#define BASE_MEMORY_SCOPED_PTR_H_
|
||||
@ -84,10 +85,13 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm> // For std::swap().
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/move.h"
|
||||
#include "base/template_util.h"
|
||||
|
||||
@ -98,61 +102,6 @@ class RefCountedBase;
|
||||
class RefCountedThreadSafeBase;
|
||||
} // namespace subtle
|
||||
|
||||
// Function object which deletes its parameter, which must be a pointer.
|
||||
// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
|
||||
// invokes 'delete'. The default deleter for scoped_ptr<T>.
|
||||
template <class T>
|
||||
struct DefaultDeleter {
|
||||
DefaultDeleter() {}
|
||||
template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
|
||||
// IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
|
||||
// if U* is implicitly convertible to T* and U is not an array type.
|
||||
//
|
||||
// Correct implementation should use SFINAE to disable this
|
||||
// constructor. However, since there are no other 1-argument constructors,
|
||||
// using a COMPILE_ASSERT() based on is_convertible<> and requiring
|
||||
// complete types is simpler and will cause compile failures for equivalent
|
||||
// misuses.
|
||||
//
|
||||
// Note, the is_convertible<U*, T*> check also ensures that U is not an
|
||||
// array. T is guaranteed to be a non-array, so any U* where U is an array
|
||||
// cannot convert to T*.
|
||||
enum { T_must_be_complete = sizeof(T) };
|
||||
enum { U_must_be_complete = sizeof(U) };
|
||||
COMPILE_ASSERT((base::is_convertible<U*, T*>::value),
|
||||
U_ptr_must_implicitly_convert_to_T_ptr);
|
||||
}
|
||||
inline void operator()(T* ptr) const {
|
||||
enum { type_must_be_complete = sizeof(T) };
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of DefaultDeleter for array types.
|
||||
template <class T>
|
||||
struct DefaultDeleter<T[]> {
|
||||
inline void operator()(T* ptr) const {
|
||||
enum { type_must_be_complete = sizeof(T) };
|
||||
delete[] ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// Disable this operator for any U != T because it is undefined to execute
|
||||
// an array delete when the static type of the array mismatches the dynamic
|
||||
// type.
|
||||
//
|
||||
// References:
|
||||
// C++98 [expr.delete]p3
|
||||
// http://cplusplus.github.com/LWG/lwg-defects.html#938
|
||||
template <typename U> void operator()(U* array) const;
|
||||
};
|
||||
|
||||
template <class T, int n>
|
||||
struct DefaultDeleter<T[n]> {
|
||||
// Never allow someone to declare something like scoped_ptr<int[10]>.
|
||||
COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type);
|
||||
};
|
||||
|
||||
// Function object which invokes 'free' on its parameter, which must be
|
||||
// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
|
||||
//
|
||||
@ -174,17 +123,6 @@ template <typename T> struct IsNotRefCounted {
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ShouldAbortOnSelfReset {
|
||||
template <typename U>
|
||||
static NoType Test(const typename U::AllowSelfReset*);
|
||||
|
||||
template <typename U>
|
||||
static YesType Test(...);
|
||||
|
||||
static const bool value = sizeof(Test<T>(0)) == sizeof(YesType);
|
||||
};
|
||||
|
||||
// Minimal implementation of the core logic of scoped_ptr, suitable for
|
||||
// reuse in both scoped_ptr and its specializations.
|
||||
template <class T, class D>
|
||||
@ -215,37 +153,28 @@ class scoped_ptr_impl {
|
||||
}
|
||||
|
||||
~scoped_ptr_impl() {
|
||||
if (data_.ptr != nullptr) {
|
||||
// Not using get_deleter() saves one function call in non-optimized
|
||||
// builds.
|
||||
static_cast<D&>(data_)(data_.ptr);
|
||||
}
|
||||
// Match libc++, which calls reset() in its destructor.
|
||||
// Use nullptr as the new value for three reasons:
|
||||
// 1. libc++ does it.
|
||||
// 2. Avoids infinitely recursing into destructors if two classes are owned
|
||||
// in a reference cycle (see ScopedPtrTest.ReferenceCycle).
|
||||
// 3. If |this| is accessed in the future, in a use-after-free bug, attempts
|
||||
// to dereference |this|'s pointer should cause either a failure or a
|
||||
// segfault closer to the problem. If |this| wasn't reset to nullptr,
|
||||
// the access would cause the deleted memory to be read or written
|
||||
// leading to other more subtle issues.
|
||||
reset(nullptr);
|
||||
}
|
||||
|
||||
void reset(T* p) {
|
||||
// This is a self-reset, which is no longer allowed for default deleters:
|
||||
// https://crbug.com/162971
|
||||
assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr);
|
||||
|
||||
// Note that running data_.ptr = p can lead to undefined behavior if
|
||||
// get_deleter()(get()) deletes this. In order to prevent this, reset()
|
||||
// should update the stored pointer before deleting its old value.
|
||||
//
|
||||
// However, changing reset() to use that behavior may cause current code to
|
||||
// break in unexpected ways. If the destruction of the owned object
|
||||
// dereferences the scoped_ptr when it is destroyed by a call to reset(),
|
||||
// then it will incorrectly dispatch calls to |p| rather than the original
|
||||
// value of |data_.ptr|.
|
||||
//
|
||||
// During the transition period, set the stored pointer to nullptr while
|
||||
// deleting the object. Eventually, this safety check will be removed to
|
||||
// prevent the scenario initially described from occuring and
|
||||
// http://crbug.com/176091 can be closed.
|
||||
// Match C++11's definition of unique_ptr::reset(), which requires changing
|
||||
// the pointer before invoking the deleter on the old pointer. This prevents
|
||||
// |this| from being accessed after the deleter is run, which may destroy
|
||||
// |this|.
|
||||
T* old = data_.ptr;
|
||||
data_.ptr = nullptr;
|
||||
data_.ptr = p;
|
||||
if (old != nullptr)
|
||||
static_cast<D&>(data_)(old);
|
||||
data_.ptr = p;
|
||||
}
|
||||
|
||||
T* get() const { return data_.ptr; }
|
||||
@ -299,25 +228,27 @@ class scoped_ptr_impl {
|
||||
// dereference it, you get the thread safety guarantees of T.
|
||||
//
|
||||
// The size of scoped_ptr is small. On most compilers, when using the
|
||||
// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
|
||||
// increase the size proportional to whatever state they need to have. See
|
||||
// std::default_delete, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters
|
||||
// will increase the size proportional to whatever state they need to have. See
|
||||
// comments inside scoped_ptr_impl<> for details.
|
||||
//
|
||||
// Current implementation targets having a strict subset of C++11's
|
||||
// unique_ptr<> features. Known deficiencies include not supporting move-only
|
||||
// deleteres, function pointers as deleters, and deleters with reference
|
||||
// types.
|
||||
template <class T, class D = base::DefaultDeleter<T> >
|
||||
template <class T, class D = std::default_delete<T>>
|
||||
class scoped_ptr {
|
||||
MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
|
||||
DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
|
||||
|
||||
COMPILE_ASSERT(base::internal::IsNotRefCounted<T>::value,
|
||||
T_is_refcounted_type_and_needs_scoped_refptr);
|
||||
static_assert(!std::is_array<T>::value,
|
||||
"scoped_ptr doesn't support array with size");
|
||||
static_assert(base::internal::IsNotRefCounted<T>::value,
|
||||
"T is a refcounted type and needs a scoped_refptr");
|
||||
|
||||
public:
|
||||
// The element and deleter types.
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
using element_type = T;
|
||||
using deleter_type = D;
|
||||
|
||||
// Constructor. Defaults to initializing with nullptr.
|
||||
scoped_ptr() : impl_(nullptr) {}
|
||||
@ -329,44 +260,87 @@ class scoped_ptr {
|
||||
scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
|
||||
|
||||
// Constructor. Allows construction from a nullptr.
|
||||
scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
|
||||
scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
|
||||
|
||||
// Constructor. Allows construction from a scoped_ptr rvalue for a
|
||||
// Move constructor.
|
||||
//
|
||||
// IMPLEMENTATION NOTE: Clang requires a move constructor to be defined (and
|
||||
// not just the conversion constructor) in order to warn on pessimizing moves.
|
||||
// The requirements for the move constructor are specified in C++11
|
||||
// 20.7.1.2.1.15-17, which has some subtleties around reference deleters. As
|
||||
// we don't support reference (or move-only) deleters, the post conditions are
|
||||
// trivially true: we always copy construct the deleter from other's deleter.
|
||||
scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
|
||||
|
||||
// Conversion constructor. Allows construction from a scoped_ptr rvalue for a
|
||||
// convertible type and deleter.
|
||||
//
|
||||
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
|
||||
// from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
|
||||
// has different post-conditions if D is a reference type. Since this
|
||||
// implementation does not support deleters with reference type,
|
||||
// we do not need a separate move constructor allowing us to avoid one
|
||||
// use of SFINAE. You only need to care about this if you modify the
|
||||
// implementation of scoped_ptr.
|
||||
template <typename U, typename V>
|
||||
scoped_ptr(scoped_ptr<U, V>&& other)
|
||||
: impl_(&other.impl_) {
|
||||
COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
|
||||
// IMPLEMENTATION NOTE: C++ 20.7.1.2.1.19 requires this constructor to only
|
||||
// participate in overload resolution if all the following are true:
|
||||
// - U is implicitly convertible to T: this is important for 2 reasons:
|
||||
// 1. So type traits don't incorrectly return true, e.g.
|
||||
// std::is_convertible<scoped_ptr<Base>, scoped_ptr<Derived>>::value
|
||||
// should be false.
|
||||
// 2. To make sure code like this compiles:
|
||||
// void F(scoped_ptr<int>);
|
||||
// void F(scoped_ptr<Base>);
|
||||
// // Ambiguous since both conversion constructors match.
|
||||
// F(scoped_ptr<Derived>());
|
||||
// - U is not an array type: to prevent conversions from scoped_ptr<T[]> to
|
||||
// scoped_ptr<T>.
|
||||
// - D is a reference type and E is the same type, or D is not a reference
|
||||
// type and E is implicitly convertible to D: again, we don't support
|
||||
// reference deleters, so we only worry about the latter requirement.
|
||||
template <typename U,
|
||||
typename E,
|
||||
typename std::enable_if<!std::is_array<U>::value &&
|
||||
std::is_convertible<U*, T*>::value &&
|
||||
std::is_convertible<E, D>::value>::type* =
|
||||
nullptr>
|
||||
scoped_ptr(scoped_ptr<U, E>&& other)
|
||||
: impl_(&other.impl_) {}
|
||||
|
||||
// operator=.
|
||||
//
|
||||
// IMPLEMENTATION NOTE: Unlike the move constructor, Clang does not appear to
|
||||
// require a move assignment operator to trigger the pessimizing move warning:
|
||||
// in this case, the warning triggers when moving a temporary. For consistency
|
||||
// with the move constructor, we define it anyway. C++11 20.7.1.2.3.1-3
|
||||
// defines several requirements around this: like the move constructor, the
|
||||
// requirements are simplified by the fact that we don't support move-only or
|
||||
// reference deleters.
|
||||
scoped_ptr& operator=(scoped_ptr&& rhs) {
|
||||
impl_.TakeState(&rhs.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator=. Allows assignment from a scoped_ptr rvalue for a convertible
|
||||
// type and deleter.
|
||||
//
|
||||
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
|
||||
// the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
|
||||
// form has different requirements on for move-only Deleters. Since this
|
||||
// implementation does not support move-only Deleters, we do not need a
|
||||
// separate move assignment operator allowing us to avoid one use of SFINAE.
|
||||
// You only need to care about this if you modify the implementation of
|
||||
// scoped_ptr.
|
||||
template <typename U, typename V>
|
||||
scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) {
|
||||
COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
|
||||
// the normal move assignment operator. C++11 20.7.1.2.3.4-7 contains the
|
||||
// requirement for this operator, but like the conversion constructor, the
|
||||
// requirements are greatly simplified by not supporting move-only or
|
||||
// reference deleters.
|
||||
template <typename U,
|
||||
typename E,
|
||||
typename std::enable_if<!std::is_array<U>::value &&
|
||||
std::is_convertible<U*, T*>::value &&
|
||||
// Note that this really should be
|
||||
// std::is_assignable, but <type_traits>
|
||||
// appears to be missing this on some
|
||||
// platforms. This is close enough (though
|
||||
// it's not the same).
|
||||
std::is_convertible<D, E>::value>::type* =
|
||||
nullptr>
|
||||
scoped_ptr& operator=(scoped_ptr<U, E>&& rhs) {
|
||||
impl_.TakeState(&rhs.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator=. Allows assignment from a nullptr. Deletes the currently owned
|
||||
// object, if any.
|
||||
scoped_ptr& operator=(decltype(nullptr)) {
|
||||
scoped_ptr& operator=(std::nullptr_t) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
@ -407,12 +381,6 @@ class scoped_ptr {
|
||||
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
|
||||
}
|
||||
|
||||
// Comparison operators.
|
||||
// These return whether two scoped_ptr refer to the same object, not just to
|
||||
// two different but equal objects.
|
||||
bool operator==(const element_type* p) const { return impl_.get() == p; }
|
||||
bool operator!=(const element_type* p) const { return impl_.get() != p; }
|
||||
|
||||
// Swap two scoped pointers.
|
||||
void swap(scoped_ptr& p2) {
|
||||
impl_.swap(p2.impl_);
|
||||
@ -433,23 +401,16 @@ class scoped_ptr {
|
||||
|
||||
// Forbidden for API compatibility with std::unique_ptr.
|
||||
explicit scoped_ptr(int disallow_construction_from_null);
|
||||
|
||||
// Forbid comparison of scoped_ptr types. If U != T, it totally
|
||||
// doesn't make sense, and if U == T, it still doesn't make sense
|
||||
// because you should never have the same object owned by two different
|
||||
// scoped_ptrs.
|
||||
template <class U> bool operator==(scoped_ptr<U> const& p2) const;
|
||||
template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
|
||||
};
|
||||
|
||||
template <class T, class D>
|
||||
class scoped_ptr<T[], D> {
|
||||
MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
|
||||
DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
|
||||
|
||||
public:
|
||||
// The element and deleter types.
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
using element_type = T;
|
||||
using deleter_type = D;
|
||||
|
||||
// Constructor. Defaults to initializing with nullptr.
|
||||
scoped_ptr() : impl_(nullptr) {}
|
||||
@ -464,13 +425,11 @@ class scoped_ptr<T[], D> {
|
||||
// (C++98 [expr.delete]p3). If you're doing this, fix your code.
|
||||
// - it cannot be const-qualified differently from T per unique_ptr spec
|
||||
// (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
|
||||
// to work around this may use implicit_cast<const T*>().
|
||||
// However, because of the first bullet in this comment, users MUST
|
||||
// NOT use implicit_cast<Base*>() to upcast the static type of the array.
|
||||
// to work around this may use const_cast<const T*>().
|
||||
explicit scoped_ptr(element_type* array) : impl_(array) {}
|
||||
|
||||
// Constructor. Allows construction from a nullptr.
|
||||
scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
|
||||
scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
|
||||
|
||||
// Constructor. Allows construction from a scoped_ptr rvalue.
|
||||
scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
|
||||
@ -483,7 +442,7 @@ class scoped_ptr<T[], D> {
|
||||
|
||||
// operator=. Allows assignment from a nullptr. Deletes the currently owned
|
||||
// array, if any.
|
||||
scoped_ptr& operator=(decltype(nullptr)) {
|
||||
scoped_ptr& operator=(std::nullptr_t) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
@ -514,12 +473,6 @@ class scoped_ptr<T[], D> {
|
||||
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
|
||||
}
|
||||
|
||||
// Comparison operators.
|
||||
// These return whether two scoped_ptr refer to the same object, not just to
|
||||
// two different but equal objects.
|
||||
bool operator==(element_type* array) const { return impl_.get() == array; }
|
||||
bool operator!=(element_type* array) const { return impl_.get() != array; }
|
||||
|
||||
// Swap two scoped pointers.
|
||||
void swap(scoped_ptr& p2) {
|
||||
impl_.swap(p2.impl_);
|
||||
@ -552,13 +505,6 @@ class scoped_ptr<T[], D> {
|
||||
// reasons as the constructor above.
|
||||
template <typename U> void reset(U* array);
|
||||
void reset(int disallow_reset_from_null);
|
||||
|
||||
// Forbid comparison of scoped_ptr types. If U != T, it totally
|
||||
// doesn't make sense, and if U == T, it still doesn't make sense
|
||||
// because you should never have the same object owned by two different
|
||||
// scoped_ptrs.
|
||||
template <class U> bool operator==(scoped_ptr<U> const& p2) const;
|
||||
template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
|
||||
};
|
||||
|
||||
// Free functions
|
||||
@ -567,14 +513,82 @@ void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) {
|
||||
p1.swap(p2);
|
||||
}
|
||||
|
||||
template <class T1, class D1, class T2, class D2>
|
||||
bool operator==(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
|
||||
return p1.get() == p2.get();
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator==(T* p1, const scoped_ptr<T, D>& p2) {
|
||||
return p1 == p2.get();
|
||||
bool operator==(const scoped_ptr<T, D>& p, std::nullptr_t) {
|
||||
return p.get() == nullptr;
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator==(std::nullptr_t, const scoped_ptr<T, D>& p) {
|
||||
return p.get() == nullptr;
|
||||
}
|
||||
|
||||
template <class T1, class D1, class T2, class D2>
|
||||
bool operator!=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
|
||||
return !(p1 == p2);
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator!=(T* p1, const scoped_ptr<T, D>& p2) {
|
||||
return p1 != p2.get();
|
||||
bool operator!=(const scoped_ptr<T, D>& p, std::nullptr_t) {
|
||||
return !(p == nullptr);
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator!=(std::nullptr_t, const scoped_ptr<T, D>& p) {
|
||||
return !(p == nullptr);
|
||||
}
|
||||
|
||||
template <class T1, class D1, class T2, class D2>
|
||||
bool operator<(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
|
||||
return p1.get() < p2.get();
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator<(const scoped_ptr<T, D>& p, std::nullptr_t) {
|
||||
return p.get() < nullptr;
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator<(std::nullptr_t, const scoped_ptr<T, D>& p) {
|
||||
return nullptr < p.get();
|
||||
}
|
||||
|
||||
template <class T1, class D1, class T2, class D2>
|
||||
bool operator>(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
|
||||
return p2 < p1;
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator>(const scoped_ptr<T, D>& p, std::nullptr_t) {
|
||||
return nullptr < p;
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator>(std::nullptr_t, const scoped_ptr<T, D>& p) {
|
||||
return p < nullptr;
|
||||
}
|
||||
|
||||
template <class T1, class D1, class T2, class D2>
|
||||
bool operator<=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
|
||||
return !(p1 > p2);
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator<=(const scoped_ptr<T, D>& p, std::nullptr_t) {
|
||||
return !(p > nullptr);
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator<=(std::nullptr_t, const scoped_ptr<T, D>& p) {
|
||||
return !(nullptr > p);
|
||||
}
|
||||
|
||||
template <class T1, class D1, class T2, class D2>
|
||||
bool operator>=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
|
||||
return !(p1 < p2);
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator>=(const scoped_ptr<T, D>& p, std::nullptr_t) {
|
||||
return !(p < nullptr);
|
||||
}
|
||||
template <class T, class D>
|
||||
bool operator>=(std::nullptr_t, const scoped_ptr<T, D>& p) {
|
||||
return !(nullptr < p);
|
||||
}
|
||||
|
||||
// A function to convert T* into scoped_ptr<T>
|
||||
@ -585,4 +599,9 @@ scoped_ptr<T> make_scoped_ptr(T* ptr) {
|
||||
return scoped_ptr<T>(ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const scoped_ptr<T>& p) {
|
||||
return out << p.get();
|
||||
}
|
||||
|
||||
#endif // BASE_MEMORY_SCOPED_PTR_H_
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include "base/at_exit.h"
|
||||
#include "base/atomicops.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/aligned_memory.h"
|
||||
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
|
||||
namespace base {
|
||||
@ -37,10 +37,10 @@ static const subtle::AtomicWord kBeingCreatedMarker = 1;
|
||||
// we can implement the more complicated pieces out of line in the .cc file.
|
||||
BASE_EXPORT subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
class DeleteTraceLogForTesting;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// TODO(joth): Move more of this file into namespace base
|
||||
|
||||
// Default traits for Singleton<Type>. Calls operator new and operator delete on
|
||||
// the object. Registers automatic deletion at process exit.
|
||||
@ -111,7 +111,7 @@ struct StaticMemorySingletonTraits {
|
||||
// this is traits for returning NULL.
|
||||
static Type* New() {
|
||||
// Only constructs once and returns pointer; otherwise returns NULL.
|
||||
if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1))
|
||||
if (subtle::NoBarrier_AtomicExchange(&dead_, 1))
|
||||
return NULL;
|
||||
|
||||
return new(buffer_.void_data()) Type();
|
||||
@ -126,20 +126,19 @@ struct StaticMemorySingletonTraits {
|
||||
static const bool kAllowedToAccessOnNonjoinableThread = true;
|
||||
|
||||
// Exposed for unittesting.
|
||||
static void Resurrect() {
|
||||
base::subtle::NoBarrier_Store(&dead_, 0);
|
||||
}
|
||||
static void Resurrect() { subtle::NoBarrier_Store(&dead_, 0); }
|
||||
|
||||
private:
|
||||
static base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
|
||||
static AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
|
||||
// Signal the object was already deleted, so it is not revived.
|
||||
static base::subtle::Atomic32 dead_;
|
||||
static subtle::Atomic32 dead_;
|
||||
};
|
||||
|
||||
template <typename Type> base::AlignedMemory<sizeof(Type), ALIGNOF(Type)>
|
||||
template <typename Type>
|
||||
AlignedMemory<sizeof(Type), ALIGNOF(Type)>
|
||||
StaticMemorySingletonTraits<Type>::buffer_;
|
||||
template <typename Type> base::subtle::Atomic32
|
||||
StaticMemorySingletonTraits<Type>::dead_ = 0;
|
||||
template <typename Type>
|
||||
subtle::Atomic32 StaticMemorySingletonTraits<Type>::dead_ = 0;
|
||||
|
||||
// The Singleton<Type, Traits, DifferentiatingType> class manages a single
|
||||
// instance of Type which will be created on first use and will be destroyed at
|
||||
@ -191,7 +190,7 @@ template <typename Type> base::subtle::Atomic32
|
||||
// RAE = kRegisterAtExit
|
||||
//
|
||||
// On every platform, if Traits::RAE is true, the singleton will be destroyed at
|
||||
// process exit. More precisely it uses base::AtExitManager which requires an
|
||||
// process exit. More precisely it uses AtExitManager which requires an
|
||||
// object of this type to be instantiated. AtExitManager mimics the semantics
|
||||
// of atexit() such as LIFO order but under Windows is safer to call. For more
|
||||
// information see at_exit.h.
|
||||
@ -210,6 +209,7 @@ template <typename Type> base::subtle::Atomic32
|
||||
// (b) Your factory function must never throw an exception. This class is not
|
||||
// exception-safe.
|
||||
//
|
||||
|
||||
template <typename Type,
|
||||
typename Traits = DefaultSingletonTraits<Type>,
|
||||
typename DifferentiatingType = Type>
|
||||
@ -220,7 +220,7 @@ class Singleton {
|
||||
friend Type* Type::GetInstance();
|
||||
|
||||
// Allow TraceLog tests to test tracing after OnExit.
|
||||
friend class DeleteTraceLogForTesting;
|
||||
friend class internal::DeleteTraceLogForTesting;
|
||||
|
||||
// This class is safe to be constructed and copy-constructed since it has no
|
||||
// member.
|
||||
@ -230,45 +230,37 @@ class Singleton {
|
||||
#ifndef NDEBUG
|
||||
// Avoid making TLS lookup on release builds.
|
||||
if (!Traits::kAllowedToAccessOnNonjoinableThread)
|
||||
base::ThreadRestrictions::AssertSingletonAllowed();
|
||||
ThreadRestrictions::AssertSingletonAllowed();
|
||||
#endif
|
||||
|
||||
// The load has acquire memory ordering as the thread which reads the
|
||||
// instance_ pointer must acquire visibility over the singleton data.
|
||||
base::subtle::AtomicWord value = base::subtle::Acquire_Load(&instance_);
|
||||
if (value != 0 && value != base::internal::kBeingCreatedMarker) {
|
||||
// See the corresponding HAPPENS_BEFORE below.
|
||||
ANNOTATE_HAPPENS_AFTER(&instance_);
|
||||
subtle::AtomicWord value = subtle::Acquire_Load(&instance_);
|
||||
if (value != 0 && value != internal::kBeingCreatedMarker) {
|
||||
return reinterpret_cast<Type*>(value);
|
||||
}
|
||||
|
||||
// Object isn't created yet, maybe we will get to create it, let's try...
|
||||
if (base::subtle::Acquire_CompareAndSwap(
|
||||
&instance_, 0, base::internal::kBeingCreatedMarker) == 0) {
|
||||
if (subtle::Acquire_CompareAndSwap(&instance_, 0,
|
||||
internal::kBeingCreatedMarker) == 0) {
|
||||
// instance_ was NULL and is now kBeingCreatedMarker. Only one thread
|
||||
// will ever get here. Threads might be spinning on us, and they will
|
||||
// stop right after we do this store.
|
||||
Type* newval = Traits::New();
|
||||
|
||||
// This annotation helps race detectors recognize correct lock-less
|
||||
// synchronization between different threads calling get().
|
||||
// See the corresponding HAPPENS_AFTER below and above.
|
||||
ANNOTATE_HAPPENS_BEFORE(&instance_);
|
||||
// Releases the visibility over instance_ to the readers.
|
||||
base::subtle::Release_Store(
|
||||
&instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
|
||||
subtle::Release_Store(&instance_,
|
||||
reinterpret_cast<subtle::AtomicWord>(newval));
|
||||
|
||||
if (newval != NULL && Traits::kRegisterAtExit)
|
||||
base::AtExitManager::RegisterCallback(OnExit, NULL);
|
||||
AtExitManager::RegisterCallback(OnExit, NULL);
|
||||
|
||||
return newval;
|
||||
}
|
||||
|
||||
// We hit a race. Wait for the other thread to complete it.
|
||||
value = base::internal::WaitForInstance(&instance_);
|
||||
value = internal::WaitForInstance(&instance_);
|
||||
|
||||
// See the corresponding HAPPENS_BEFORE above.
|
||||
ANNOTATE_HAPPENS_AFTER(&instance_);
|
||||
return reinterpret_cast<Type*>(value);
|
||||
}
|
||||
|
||||
@ -278,15 +270,15 @@ class Singleton {
|
||||
static void OnExit(void* /*unused*/) {
|
||||
// AtExit should only ever be register after the singleton instance was
|
||||
// created. We should only ever get here with a valid instance_ pointer.
|
||||
Traits::Delete(
|
||||
reinterpret_cast<Type*>(base::subtle::NoBarrier_Load(&instance_)));
|
||||
Traits::Delete(reinterpret_cast<Type*>(subtle::NoBarrier_Load(&instance_)));
|
||||
instance_ = 0;
|
||||
}
|
||||
static base::subtle::AtomicWord instance_;
|
||||
static subtle::AtomicWord instance_;
|
||||
};
|
||||
|
||||
template <typename Type, typename Traits, typename DifferentiatingType>
|
||||
base::subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::
|
||||
instance_ = 0;
|
||||
subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::instance_ = 0;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_SINGLETON_H_
|
||||
|
@ -16,6 +16,7 @@
|
||||
//
|
||||
// class Controller {
|
||||
// public:
|
||||
// Controller() : weak_factory_(this) {}
|
||||
// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
|
||||
// void WorkComplete(const Result& result) { ... }
|
||||
// private:
|
||||
@ -58,15 +59,20 @@
|
||||
// off to other task runners, e.g. to use to post tasks back to object on the
|
||||
// bound sequence.
|
||||
//
|
||||
// Invalidating the factory's WeakPtrs un-binds it from the sequence, allowing
|
||||
// it to be passed for a different sequence to use or delete it.
|
||||
// If all WeakPtr objects are destroyed or invalidated then the factory is
|
||||
// unbound from the SequencedTaskRunner/Thread. The WeakPtrFactory may then be
|
||||
// destroyed, or new WeakPtr objects may be used, from a different sequence.
|
||||
//
|
||||
// Thus, at least one WeakPtr object must exist and have been dereferenced on
|
||||
// the correct thread to enforce that other WeakPtr objects will enforce they
|
||||
// are used on the desired thread.
|
||||
|
||||
#ifndef BASE_MEMORY_WEAK_PTR_H_
|
||||
#define BASE_MEMORY_WEAK_PTR_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "base/template_util.h"
|
||||
@ -155,8 +161,8 @@ class SupportsWeakPtrBase {
|
||||
static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
|
||||
typedef
|
||||
is_convertible<Derived, internal::SupportsWeakPtrBase&> convertible;
|
||||
COMPILE_ASSERT(convertible::value,
|
||||
AsWeakPtr_argument_inherits_from_SupportsWeakPtr);
|
||||
static_assert(convertible::value,
|
||||
"AsWeakPtr argument must inherit from SupportsWeakPtr");
|
||||
return AsWeakPtrImpl<Derived>(t, *t);
|
||||
}
|
||||
|
||||
|
@ -2,228 +2,56 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
|
||||
#ifndef BASE_MOVE_H_
|
||||
#define BASE_MOVE_H_
|
||||
|
||||
// Macro with the boilerplate that makes a type move-only in C++03.
|
||||
#include <utility>
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
// TODO(crbug.com/566182): DEPRECATED!
|
||||
// Use DISALLOW_COPY_AND_ASSIGN instead, or if your type will be used in
|
||||
// Callbacks, use DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND instead.
|
||||
#define MOVE_ONLY_TYPE_FOR_CPP_03(type) \
|
||||
DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type)
|
||||
|
||||
// A macro to disallow the copy constructor and copy assignment functions.
|
||||
// This should be used in the private: declarations for a class.
|
||||
//
|
||||
// USAGE
|
||||
// Use this macro instead of DISALLOW_COPY_AND_ASSIGN if you want to pass
|
||||
// ownership of the type through a base::Callback without heap-allocating it
|
||||
// into a scoped_ptr. The class must define a move constructor and move
|
||||
// assignment operator to make this work.
|
||||
//
|
||||
// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create
|
||||
// a "move-only" type. Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be
|
||||
// the first line in a class declaration.
|
||||
//
|
||||
// A class using this macro must call .Pass() (or somehow be an r-value already)
|
||||
// before it can be:
|
||||
//
|
||||
// * Passed as a function argument
|
||||
// * Used as the right-hand side of an assignment
|
||||
// * Returned from a function
|
||||
//
|
||||
// Each class will still need to define their own "move constructor" and "move
|
||||
// operator=" to make this useful. Here's an example of the macro, the move
|
||||
// constructor, and the move operator= from the scoped_ptr class:
|
||||
//
|
||||
// template <typename T>
|
||||
// class scoped_ptr {
|
||||
// MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
|
||||
// public:
|
||||
// scoped_ptr(RValue& other) : ptr_(other.release()) { }
|
||||
// scoped_ptr& operator=(RValue& other) {
|
||||
// swap(other);
|
||||
// return *this;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// Note that the constructor must NOT be marked explicit.
|
||||
//
|
||||
// For consistency, the second parameter to the macro should always be RValue
|
||||
// unless you have a strong reason to do otherwise. It is only exposed as a
|
||||
// macro parameter so that the move constructor and move operator= don't look
|
||||
// like they're using a phantom type.
|
||||
//
|
||||
//
|
||||
// HOW THIS WORKS
|
||||
//
|
||||
// For a thorough explanation of this technique, see:
|
||||
//
|
||||
// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
|
||||
//
|
||||
// The summary is that we take advantage of 2 properties:
|
||||
//
|
||||
// 1) non-const references will not bind to r-values.
|
||||
// 2) C++ can apply one user-defined conversion when initializing a
|
||||
// variable.
|
||||
//
|
||||
// The first lets us disable the copy constructor and assignment operator
|
||||
// by declaring private version of them with a non-const reference parameter.
|
||||
//
|
||||
// For l-values, direct initialization still fails like in
|
||||
// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment
|
||||
// operators are private.
|
||||
//
|
||||
// For r-values, the situation is different. The copy constructor and
|
||||
// assignment operator are not viable due to (1), so we are trying to call
|
||||
// a non-existent constructor and non-existing operator= rather than a private
|
||||
// one. Since we have not committed an error quite yet, we can provide an
|
||||
// alternate conversion sequence and a constructor. We add
|
||||
//
|
||||
// * a private struct named "RValue"
|
||||
// * a user-defined conversion "operator RValue()"
|
||||
// * a "move constructor" and "move operator=" that take the RValue& as
|
||||
// their sole parameter.
|
||||
//
|
||||
// Only r-values will trigger this sequence and execute our "move constructor"
|
||||
// or "move operator=." L-values will match the private copy constructor and
|
||||
// operator= first giving a "private in this context" error. This combination
|
||||
// gives us a move-only type.
|
||||
//
|
||||
// For signaling a destructive transfer of data from an l-value, we provide a
|
||||
// method named Pass() which creates an r-value for the current instance
|
||||
// triggering the move constructor or move operator=.
|
||||
//
|
||||
// Other ways to get r-values is to use the result of an expression like a
|
||||
// function call.
|
||||
//
|
||||
// Here's an example with comments explaining what gets triggered where:
|
||||
//
|
||||
// class Foo {
|
||||
// MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue);
|
||||
//
|
||||
// public:
|
||||
// ... API ...
|
||||
// Foo(RValue other); // Move constructor.
|
||||
// Foo& operator=(RValue rhs); // Move operator=
|
||||
// };
|
||||
//
|
||||
// Foo MakeFoo(); // Function that returns a Foo.
|
||||
//
|
||||
// Foo f;
|
||||
// Foo f_copy(f); // ERROR: Foo(Foo&) is private in this context.
|
||||
// Foo f_assign;
|
||||
// f_assign = f; // ERROR: operator=(Foo&) is private in this context.
|
||||
//
|
||||
//
|
||||
// Foo f(MakeFoo()); // R-value so alternate conversion executed.
|
||||
// Foo f_copy(f.Pass()); // R-value so alternate conversion executed.
|
||||
// f = f_copy.Pass(); // R-value so alternate conversion executed.
|
||||
//
|
||||
//
|
||||
// IMPLEMENTATION SUBTLETIES WITH RValue
|
||||
//
|
||||
// The RValue struct is just a container for a pointer back to the original
|
||||
// object. It should only ever be created as a temporary, and no external
|
||||
// class should ever declare it or use it in a parameter.
|
||||
//
|
||||
// It is tempting to want to use the RValue type in function parameters, but
|
||||
// excluding the limited usage here for the move constructor and move
|
||||
// operator=, doing so would mean that the function could take both r-values
|
||||
// and l-values equially which is unexpected. See COMPARED To Boost.Move for
|
||||
// more details.
|
||||
//
|
||||
// An alternate, and incorrect, implementation of the RValue class used by
|
||||
// Boost.Move makes RValue a fieldless child of the move-only type. RValue&
|
||||
// is then used in place of RValue in the various operators. The RValue& is
|
||||
// "created" by doing *reinterpret_cast<RValue*>(this). This has the appeal
|
||||
// of never creating a temporary RValue struct even with optimizations
|
||||
// disabled. Also, by virtue of inheritance you can treat the RValue
|
||||
// reference as if it were the move-only type itself. Unfortunately,
|
||||
// using the result of this reinterpret_cast<> is actually undefined behavior
|
||||
// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer
|
||||
// will generate non-working code.
|
||||
//
|
||||
// In optimized builds, both implementations generate the same assembly so we
|
||||
// choose the one that adheres to the standard.
|
||||
//
|
||||
//
|
||||
// WHY HAVE typedef void MoveOnlyTypeForCPP03
|
||||
//
|
||||
// Callback<>/Bind() needs to understand movable-but-not-copyable semantics
|
||||
// to call .Pass() appropriately when it is expected to transfer the value.
|
||||
// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check
|
||||
// easy and automatic in helper templates for Callback<>/Bind().
|
||||
// This version of the macro adds a Pass() function and a cryptic
|
||||
// MoveOnlyTypeForCPP03 typedef for the base::Callback implementation to use.
|
||||
// See IsMoveOnlyType template and its usage in base/callback_internal.h
|
||||
// for more details.
|
||||
//
|
||||
//
|
||||
// COMPARED TO C++11
|
||||
//
|
||||
// In C++11, you would implement this functionality using an r-value reference
|
||||
// and our .Pass() method would be replaced with a call to std::move().
|
||||
//
|
||||
// This emulation also has a deficiency where it uses up the single
|
||||
// user-defined conversion allowed by C++ during initialization. This can
|
||||
// cause problems in some API edge cases. For instance, in scoped_ptr, it is
|
||||
// impossible to make a function "void Foo(scoped_ptr<Parent> p)" accept a
|
||||
// value of type scoped_ptr<Child> even if you add a constructor to
|
||||
// scoped_ptr<> that would make it look like it should work. C++11 does not
|
||||
// have this deficiency.
|
||||
//
|
||||
//
|
||||
// COMPARED TO Boost.Move
|
||||
//
|
||||
// Our implementation similar to Boost.Move, but we keep the RValue struct
|
||||
// private to the move-only type, and we don't use the reinterpret_cast<> hack.
|
||||
//
|
||||
// In Boost.Move, RValue is the boost::rv<> template. This type can be used
|
||||
// when writing APIs like:
|
||||
//
|
||||
// void MyFunc(boost::rv<Foo>& f)
|
||||
//
|
||||
// that can take advantage of rv<> to avoid extra copies of a type. However you
|
||||
// would still be able to call this version of MyFunc with an l-value:
|
||||
//
|
||||
// Foo f;
|
||||
// MyFunc(f); // Uh oh, we probably just destroyed |f| w/o calling Pass().
|
||||
//
|
||||
// unless someone is very careful to also declare a parallel override like:
|
||||
//
|
||||
// void MyFunc(const Foo& f)
|
||||
//
|
||||
// that would catch the l-values first. This was declared unsafe in C++11 and
|
||||
// a C++11 compiler will explicitly fail MyFunc(f). Unfortunately, we cannot
|
||||
// ensure this in C++03.
|
||||
//
|
||||
// Since we have no need for writing such APIs yet, our implementation keeps
|
||||
// RValue private and uses a .Pass() method to do the conversion instead of
|
||||
// trying to write a version of "std::move()." Writing an API like std::move()
|
||||
// would require the RValue struct to be public.
|
||||
//
|
||||
//
|
||||
// CAVEATS
|
||||
//
|
||||
// If you include a move-only type as a field inside a class that does not
|
||||
// explicitly declare a copy constructor, the containing class's implicit
|
||||
// copy constructor will change from Containing(const Containing&) to
|
||||
// Containing(Containing&). This can cause some unexpected errors.
|
||||
//
|
||||
// http://llvm.org/bugs/show_bug.cgi?id=11528
|
||||
//
|
||||
// The workaround is to explicitly declare your copy constructor.
|
||||
//
|
||||
#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
|
||||
// TODO(crbug.com/566182): Remove this macro and use DISALLOW_COPY_AND_ASSIGN
|
||||
// everywhere instead.
|
||||
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_MACOSX)
|
||||
#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
|
||||
private: \
|
||||
struct rvalue_type { \
|
||||
explicit rvalue_type(type* object) : object(object) {} \
|
||||
type* object; \
|
||||
}; \
|
||||
type(type&); \
|
||||
void operator=(type&); \
|
||||
type(const type&) = delete; \
|
||||
void operator=(const type&) = delete; \
|
||||
\
|
||||
public: \
|
||||
operator rvalue_type() { return rvalue_type(this); } \
|
||||
type Pass() WARN_UNUSED_RESULT { return type(rvalue_type(this)); } \
|
||||
typedef void MoveOnlyTypeForCPP03; \
|
||||
\
|
||||
private:
|
||||
|
||||
#define MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
|
||||
#else
|
||||
#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
|
||||
private: \
|
||||
type(type&); \
|
||||
void operator=(type&); \
|
||||
type(const type&) = delete; \
|
||||
void operator=(const type&) = delete; \
|
||||
\
|
||||
public: \
|
||||
type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
|
||||
type&& Pass() WARN_UNUSED_RESULT { return std::move(*this); } \
|
||||
typedef void MoveOnlyTypeForCPP03; \
|
||||
\
|
||||
private:
|
||||
#endif
|
||||
|
||||
#endif // BASE_MOVE_H_
|
||||
|
@ -2,10 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_SAFE_CONVERSIONS_H_
|
||||
#define BASE_SAFE_CONVERSIONS_H_
|
||||
#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_
|
||||
#define BASE_NUMERICS_SAFE_CONVERSIONS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/safe_conversions_impl.h"
|
||||
@ -20,6 +23,24 @@ inline bool IsValueInRangeForNumericType(Src value) {
|
||||
internal::RANGE_VALID;
|
||||
}
|
||||
|
||||
// Convenience function for determining if a numeric value is negative without
|
||||
// throwing compiler warnings on: unsigned(value) < 0.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
|
||||
IsValueNegative(T value) {
|
||||
static_assert(std::numeric_limits<T>::is_specialized,
|
||||
"Argument must be numeric.");
|
||||
return value < 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
|
||||
IsValueNegative(T) {
|
||||
static_assert(std::numeric_limits<T>::is_specialized,
|
||||
"Argument must be numeric.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// checked_cast<> is analogous to static_cast<> for numeric types,
|
||||
// except that it CHECKs that the specified numeric conversion will not
|
||||
// overflow or underflow. NaN source will always trigger a CHECK.
|
||||
@ -29,10 +50,30 @@ inline Dst checked_cast(Src value) {
|
||||
return static_cast<Dst>(value);
|
||||
}
|
||||
|
||||
// HandleNaN will cause this class to CHECK(false).
|
||||
struct SaturatedCastNaNBehaviorCheck {
|
||||
template <typename T>
|
||||
static T HandleNaN() {
|
||||
CHECK(false);
|
||||
return T();
|
||||
}
|
||||
};
|
||||
|
||||
// HandleNaN will return 0 in this case.
|
||||
struct SaturatedCastNaNBehaviorReturnZero {
|
||||
template <typename T>
|
||||
static T HandleNaN() {
|
||||
return T();
|
||||
}
|
||||
};
|
||||
|
||||
// saturated_cast<> is analogous to static_cast<> for numeric types, except
|
||||
// that the specified numeric conversion will saturate rather than overflow or
|
||||
// underflow. NaN assignment to an integral will trigger a CHECK condition.
|
||||
template <typename Dst, typename Src>
|
||||
// underflow. NaN assignment to an integral will defer the behavior to a
|
||||
// specified class. By default, it will return 0.
|
||||
template <typename Dst,
|
||||
class NaNHandler = SaturatedCastNaNBehaviorReturnZero,
|
||||
typename Src>
|
||||
inline Dst saturated_cast(Src value) {
|
||||
// Optimization for floating point values, which already saturate.
|
||||
if (std::numeric_limits<Dst>::is_iec559)
|
||||
@ -50,15 +91,75 @@ inline Dst saturated_cast(Src value) {
|
||||
|
||||
// Should fail only on attempting to assign NaN to a saturated integer.
|
||||
case internal::RANGE_INVALID:
|
||||
CHECK(false);
|
||||
return std::numeric_limits<Dst>::max();
|
||||
return NaNHandler::template HandleNaN<Dst>();
|
||||
}
|
||||
|
||||
NOTREACHED();
|
||||
return static_cast<Dst>(value);
|
||||
}
|
||||
|
||||
// strict_cast<> is analogous to static_cast<> for numeric types, except that
|
||||
// it will cause a compile failure if the destination type is not large enough
|
||||
// to contain any value in the source type. It performs no runtime checking.
|
||||
template <typename Dst, typename Src>
|
||||
inline Dst strict_cast(Src value) {
|
||||
static_assert(std::numeric_limits<Src>::is_specialized,
|
||||
"Argument must be numeric.");
|
||||
static_assert(std::numeric_limits<Dst>::is_specialized,
|
||||
"Result must be numeric.");
|
||||
static_assert((internal::StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
|
||||
internal::NUMERIC_RANGE_CONTAINED),
|
||||
"The numeric conversion is out of range for this type. You "
|
||||
"should probably use one of the following conversion "
|
||||
"mechanisms on the value you want to pass:\n"
|
||||
"- base::checked_cast\n"
|
||||
"- base::saturated_cast\n"
|
||||
"- base::CheckedNumeric");
|
||||
|
||||
return static_cast<Dst>(value);
|
||||
}
|
||||
|
||||
// StrictNumeric implements compile time range checking between numeric types by
|
||||
// wrapping assignment operations in a strict_cast. This class is intended to be
|
||||
// used for function arguments and return types, to ensure the destination type
|
||||
// can always contain the source type. This is essentially the same as enforcing
|
||||
// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied
|
||||
// incrementally at API boundaries, making it easier to convert code so that it
|
||||
// compiles cleanly with truncation warnings enabled.
|
||||
// This template should introduce no runtime overhead, but it also provides no
|
||||
// runtime checking of any of the associated mathematical operations. Use
|
||||
// CheckedNumeric for runtime range checks of tha actual value being assigned.
|
||||
template <typename T>
|
||||
class StrictNumeric {
|
||||
public:
|
||||
typedef T type;
|
||||
|
||||
StrictNumeric() : value_(0) {}
|
||||
|
||||
// Copy constructor.
|
||||
template <typename Src>
|
||||
StrictNumeric(const StrictNumeric<Src>& rhs)
|
||||
: value_(strict_cast<T>(rhs.value_)) {}
|
||||
|
||||
// This is not an explicit constructor because we implicitly upgrade regular
|
||||
// numerics to StrictNumerics to make them easier to use.
|
||||
template <typename Src>
|
||||
StrictNumeric(Src value)
|
||||
: value_(strict_cast<T>(value)) {}
|
||||
|
||||
// The numeric cast operator basically handles all the magic.
|
||||
template <typename Dst>
|
||||
operator Dst() const {
|
||||
return strict_cast<Dst>(value_);
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
// Explicitly make a shorter size_t typedef for convenience.
|
||||
typedef StrictNumeric<size_t> SizeT;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SAFE_CONVERSIONS_H_
|
||||
|
||||
#endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_
|
||||
|
@ -2,8 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_SAFE_CONVERSIONS_IMPL_H_
|
||||
#define BASE_SAFE_CONVERSIONS_IMPL_H_
|
||||
#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
|
||||
#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
@ -108,6 +111,55 @@ inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound,
|
||||
(is_in_lower_bound ? 0 : RANGE_UNDERFLOW));
|
||||
}
|
||||
|
||||
// The following helper template addresses a corner case in range checks for
|
||||
// conversion from a floating-point type to an integral type of smaller range
|
||||
// but larger precision (e.g. float -> unsigned). The problem is as follows:
|
||||
// 1. Integral maximum is always one less than a power of two, so it must be
|
||||
// truncated to fit the mantissa of the floating point. The direction of
|
||||
// rounding is implementation defined, but by default it's always IEEE
|
||||
// floats, which round to nearest and thus result in a value of larger
|
||||
// magnitude than the integral value.
|
||||
// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
|
||||
// // is 4294967295u.
|
||||
// 2. If the floating point value is equal to the promoted integral maximum
|
||||
// value, a range check will erroneously pass.
|
||||
// Example: (4294967296f <= 4294967295u) // This is true due to a precision
|
||||
// // loss in rounding up to float.
|
||||
// 3. When the floating point value is then converted to an integral, the
|
||||
// resulting value is out of range for the target integral type and
|
||||
// thus is implementation defined.
|
||||
// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
|
||||
// To fix this bug we manually truncate the maximum value when the destination
|
||||
// type is an integral of larger precision than the source floating-point type,
|
||||
// such that the resulting maximum is represented exactly as a floating point.
|
||||
template <typename Dst, typename Src>
|
||||
struct NarrowingRange {
|
||||
typedef typename std::numeric_limits<Src> SrcLimits;
|
||||
typedef typename std::numeric_limits<Dst> DstLimits;
|
||||
|
||||
static Dst max() {
|
||||
// The following logic avoids warnings where the max function is
|
||||
// instantiated with invalid values for a bit shift (even though
|
||||
// such a function can never be called).
|
||||
static const int shift =
|
||||
(MaxExponent<Src>::value > MaxExponent<Dst>::value &&
|
||||
SrcLimits::digits < DstLimits::digits && SrcLimits::is_iec559 &&
|
||||
DstLimits::is_integer)
|
||||
? (DstLimits::digits - SrcLimits::digits)
|
||||
: 0;
|
||||
|
||||
// We use UINTMAX_C below to avoid compiler warnings about shifting floating
|
||||
// points. Since it's a compile time calculation, it shouldn't have any
|
||||
// performance impact.
|
||||
return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1);
|
||||
}
|
||||
|
||||
static Dst min() {
|
||||
return std::numeric_limits<Dst>::is_iec559 ? -DstLimits::max()
|
||||
: DstLimits::min();
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
typename Dst,
|
||||
typename Src,
|
||||
@ -147,11 +199,8 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
|
||||
INTEGER_REPRESENTATION_SIGNED,
|
||||
NUMERIC_RANGE_NOT_CONTAINED> {
|
||||
static RangeConstraint Check(Src value) {
|
||||
return std::numeric_limits<Dst>::is_iec559
|
||||
? GetRangeConstraint(value <= std::numeric_limits<Dst>::max(),
|
||||
value >= -std::numeric_limits<Dst>::max())
|
||||
: GetRangeConstraint(value <= std::numeric_limits<Dst>::max(),
|
||||
value >= std::numeric_limits<Dst>::min());
|
||||
return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()),
|
||||
(value >= NarrowingRange<Dst, Src>::min()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -163,7 +212,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
|
||||
INTEGER_REPRESENTATION_UNSIGNED,
|
||||
NUMERIC_RANGE_NOT_CONTAINED> {
|
||||
static RangeConstraint Check(Src value) {
|
||||
return GetRangeConstraint(value <= std::numeric_limits<Dst>::max(), true);
|
||||
return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::max(), true);
|
||||
}
|
||||
};
|
||||
|
||||
@ -178,7 +227,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
|
||||
return sizeof(Dst) > sizeof(Src)
|
||||
? RANGE_VALID
|
||||
: GetRangeConstraint(
|
||||
value <= static_cast<Src>(std::numeric_limits<Dst>::max()),
|
||||
value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
|
||||
true);
|
||||
}
|
||||
};
|
||||
@ -195,7 +244,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
|
||||
return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
|
||||
? GetRangeConstraint(true, value >= static_cast<Src>(0))
|
||||
: GetRangeConstraint(
|
||||
value <= static_cast<Src>(std::numeric_limits<Dst>::max()),
|
||||
value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
|
||||
value >= static_cast<Src>(0));
|
||||
}
|
||||
};
|
||||
@ -212,5 +261,4 @@ inline RangeConstraint DstRangeRelationToSrcRange(Src value) {
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SAFE_CONVERSIONS_IMPL_H_
|
||||
|
||||
#endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
|
||||
|
299
security/sandbox/chromium/base/numerics/safe_math.h
Normal file
299
security/sandbox/chromium/base/numerics/safe_math.h
Normal file
@ -0,0 +1,299 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_NUMERICS_SAFE_MATH_H_
|
||||
#define BASE_NUMERICS_SAFE_MATH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "base/numerics/safe_math_impl.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// CheckedNumeric implements all the logic and operators for detecting integer
|
||||
// boundary conditions such as overflow, underflow, and invalid conversions.
|
||||
// The CheckedNumeric type implicitly converts from floating point and integer
|
||||
// data types, and contains overloads for basic arithmetic operations (i.e.: +,
|
||||
// -, *, /, %).
|
||||
//
|
||||
// The following methods convert from CheckedNumeric to standard numeric values:
|
||||
// IsValid() - Returns true if the underlying numeric value is valid (i.e. has
|
||||
// has not wrapped and is not the result of an invalid conversion).
|
||||
// ValueOrDie() - Returns the underlying value. If the state is not valid this
|
||||
// call will crash on a CHECK.
|
||||
// ValueOrDefault() - Returns the current value, or the supplied default if the
|
||||
// state is not valid.
|
||||
// ValueFloating() - Returns the underlying floating point value (valid only
|
||||
// only for floating point CheckedNumeric types).
|
||||
//
|
||||
// Bitwise operations are explicitly not supported, because correct
|
||||
// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison
|
||||
// operations are explicitly not supported because they could result in a crash
|
||||
// on a CHECK condition. You should use patterns like the following for these
|
||||
// operations:
|
||||
// Bitwise operation:
|
||||
// CheckedNumeric<int> checked_int = untrusted_input_value;
|
||||
// int x = checked_int.ValueOrDefault(0) | kFlagValues;
|
||||
// Comparison:
|
||||
// CheckedNumeric<size_t> checked_size = untrusted_input_value;
|
||||
// checked_size += HEADER LENGTH;
|
||||
// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
|
||||
// Do stuff...
|
||||
template <typename T>
|
||||
class CheckedNumeric {
|
||||
public:
|
||||
typedef T type;
|
||||
|
||||
CheckedNumeric() {}
|
||||
|
||||
// Copy constructor.
|
||||
template <typename Src>
|
||||
CheckedNumeric(const CheckedNumeric<Src>& rhs)
|
||||
: state_(rhs.ValueUnsafe(), rhs.validity()) {}
|
||||
|
||||
template <typename Src>
|
||||
CheckedNumeric(Src value, RangeConstraint validity)
|
||||
: state_(value, validity) {}
|
||||
|
||||
// This is not an explicit constructor because we implicitly upgrade regular
|
||||
// numerics to CheckedNumerics to make them easier to use.
|
||||
template <typename Src>
|
||||
CheckedNumeric(Src value)
|
||||
: state_(value) {
|
||||
static_assert(std::numeric_limits<Src>::is_specialized,
|
||||
"Argument must be numeric.");
|
||||
}
|
||||
|
||||
// This is not an explicit constructor because we want a seamless conversion
|
||||
// from StrictNumeric types.
|
||||
template <typename Src>
|
||||
CheckedNumeric(StrictNumeric<Src> value)
|
||||
: state_(static_cast<Src>(value)) {
|
||||
}
|
||||
|
||||
// IsValid() is the public API to test if a CheckedNumeric is currently valid.
|
||||
bool IsValid() const { return validity() == RANGE_VALID; }
|
||||
|
||||
// ValueOrDie() The primary accessor for the underlying value. If the current
|
||||
// state is not valid it will CHECK and crash.
|
||||
T ValueOrDie() const {
|
||||
CHECK(IsValid());
|
||||
return state_.value();
|
||||
}
|
||||
|
||||
// ValueOrDefault(T default_value) A convenience method that returns the
|
||||
// current value if the state is valid, and the supplied default_value for
|
||||
// any other state.
|
||||
T ValueOrDefault(T default_value) const {
|
||||
return IsValid() ? state_.value() : default_value;
|
||||
}
|
||||
|
||||
// ValueFloating() - Since floating point values include their validity state,
|
||||
// we provide an easy method for extracting them directly, without a risk of
|
||||
// crashing on a CHECK.
|
||||
T ValueFloating() const {
|
||||
static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float.");
|
||||
return CheckedNumeric<T>::cast(*this).ValueUnsafe();
|
||||
}
|
||||
|
||||
// validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for
|
||||
// tests and to avoid a big matrix of friend operator overloads. But the
|
||||
// values it returns are likely to change in the future.
|
||||
// Returns: current validity state (i.e. valid, overflow, underflow, nan).
|
||||
// TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
|
||||
// saturation/wrapping so we can expose this state consistently and implement
|
||||
// saturated arithmetic.
|
||||
RangeConstraint validity() const { return state_.validity(); }
|
||||
|
||||
// ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now
|
||||
// for tests and to avoid a big matrix of friend operator overloads. But the
|
||||
// values it returns are likely to change in the future.
|
||||
// Returns: the raw numeric value, regardless of the current state.
|
||||
// TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
|
||||
// saturation/wrapping so we can expose this state consistently and implement
|
||||
// saturated arithmetic.
|
||||
T ValueUnsafe() const { return state_.value(); }
|
||||
|
||||
// Prototypes for the supported arithmetic operator overloads.
|
||||
template <typename Src> CheckedNumeric& operator+=(Src rhs);
|
||||
template <typename Src> CheckedNumeric& operator-=(Src rhs);
|
||||
template <typename Src> CheckedNumeric& operator*=(Src rhs);
|
||||
template <typename Src> CheckedNumeric& operator/=(Src rhs);
|
||||
template <typename Src> CheckedNumeric& operator%=(Src rhs);
|
||||
|
||||
CheckedNumeric operator-() const {
|
||||
RangeConstraint validity;
|
||||
T value = CheckedNeg(state_.value(), &validity);
|
||||
// Negation is always valid for floating point.
|
||||
if (std::numeric_limits<T>::is_iec559)
|
||||
return CheckedNumeric<T>(value);
|
||||
|
||||
validity = GetRangeConstraint(state_.validity() | validity);
|
||||
return CheckedNumeric<T>(value, validity);
|
||||
}
|
||||
|
||||
CheckedNumeric Abs() const {
|
||||
RangeConstraint validity;
|
||||
T value = CheckedAbs(state_.value(), &validity);
|
||||
// Absolute value is always valid for floating point.
|
||||
if (std::numeric_limits<T>::is_iec559)
|
||||
return CheckedNumeric<T>(value);
|
||||
|
||||
validity = GetRangeConstraint(state_.validity() | validity);
|
||||
return CheckedNumeric<T>(value, validity);
|
||||
}
|
||||
|
||||
// This function is available only for integral types. It returns an unsigned
|
||||
// integer of the same width as the source type, containing the absolute value
|
||||
// of the source, and properly handling signed min.
|
||||
CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const {
|
||||
return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>(
|
||||
CheckedUnsignedAbs(state_.value()), state_.validity());
|
||||
}
|
||||
|
||||
CheckedNumeric& operator++() {
|
||||
*this += 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CheckedNumeric operator++(int) {
|
||||
CheckedNumeric value = *this;
|
||||
*this += 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
CheckedNumeric& operator--() {
|
||||
*this -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CheckedNumeric operator--(int) {
|
||||
CheckedNumeric value = *this;
|
||||
*this -= 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
// These static methods behave like a convenience cast operator targeting
|
||||
// the desired CheckedNumeric type. As an optimization, a reference is
|
||||
// returned when Src is the same type as T.
|
||||
template <typename Src>
|
||||
static CheckedNumeric<T> cast(
|
||||
Src u,
|
||||
typename std::enable_if<std::numeric_limits<Src>::is_specialized,
|
||||
int>::type = 0) {
|
||||
return u;
|
||||
}
|
||||
|
||||
template <typename Src>
|
||||
static CheckedNumeric<T> cast(
|
||||
const CheckedNumeric<Src>& u,
|
||||
typename std::enable_if<!is_same<Src, T>::value, int>::type = 0) {
|
||||
return u;
|
||||
}
|
||||
|
||||
static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
|
||||
|
||||
private:
|
||||
template <typename NumericType>
|
||||
struct UnderlyingType {
|
||||
using type = NumericType;
|
||||
};
|
||||
|
||||
template <typename NumericType>
|
||||
struct UnderlyingType<CheckedNumeric<NumericType>> {
|
||||
using type = NumericType;
|
||||
};
|
||||
|
||||
CheckedNumericState<T> state_;
|
||||
};
|
||||
|
||||
// This is the boilerplate for the standard arithmetic operator overloads. A
|
||||
// macro isn't the prettiest solution, but it beats rewriting these five times.
|
||||
// Some details worth noting are:
|
||||
// * We apply the standard arithmetic promotions.
|
||||
// * We skip range checks for floating points.
|
||||
// * We skip range checks for destination integers with sufficient range.
|
||||
// TODO(jschuh): extract these out into templates.
|
||||
#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \
|
||||
/* Binary arithmetic operator for CheckedNumerics of the same type. */ \
|
||||
template <typename T> \
|
||||
CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \
|
||||
const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) { \
|
||||
typedef typename ArithmeticPromotion<T>::type Promotion; \
|
||||
/* Floating point always takes the fast path */ \
|
||||
if (std::numeric_limits<T>::is_iec559) \
|
||||
return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \
|
||||
if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \
|
||||
return CheckedNumeric<Promotion>( \
|
||||
lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
|
||||
GetRangeConstraint(rhs.validity() | lhs.validity())); \
|
||||
RangeConstraint validity = RANGE_VALID; \
|
||||
T result = static_cast<T>(Checked##NAME( \
|
||||
static_cast<Promotion>(lhs.ValueUnsafe()), \
|
||||
static_cast<Promotion>(rhs.ValueUnsafe()), \
|
||||
&validity)); \
|
||||
return CheckedNumeric<Promotion>( \
|
||||
result, \
|
||||
GetRangeConstraint(validity | lhs.validity() | rhs.validity())); \
|
||||
} \
|
||||
/* Assignment arithmetic operator implementation from CheckedNumeric. */ \
|
||||
template <typename T> \
|
||||
template <typename Src> \
|
||||
CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \
|
||||
*this = CheckedNumeric<T>::cast(*this) \
|
||||
OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \
|
||||
return *this; \
|
||||
} \
|
||||
/* Binary arithmetic operator for CheckedNumeric of different type. */ \
|
||||
template <typename T, typename Src> \
|
||||
CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \
|
||||
const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) { \
|
||||
typedef typename ArithmeticPromotion<T, Src>::type Promotion; \
|
||||
if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
|
||||
return CheckedNumeric<Promotion>( \
|
||||
lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
|
||||
GetRangeConstraint(rhs.validity() | lhs.validity())); \
|
||||
return CheckedNumeric<Promotion>::cast(lhs) \
|
||||
OP CheckedNumeric<Promotion>::cast(rhs); \
|
||||
} \
|
||||
/* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
|
||||
template <typename T, typename Src> \
|
||||
CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \
|
||||
const CheckedNumeric<T>& lhs, Src rhs) { \
|
||||
typedef typename ArithmeticPromotion<T, Src>::type Promotion; \
|
||||
if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
|
||||
return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs, \
|
||||
lhs.validity()); \
|
||||
return CheckedNumeric<Promotion>::cast(lhs) \
|
||||
OP CheckedNumeric<Promotion>::cast(rhs); \
|
||||
} \
|
||||
/* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \
|
||||
template <typename T, typename Src> \
|
||||
CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \
|
||||
Src lhs, const CheckedNumeric<T>& rhs) { \
|
||||
typedef typename ArithmeticPromotion<T, Src>::type Promotion; \
|
||||
if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
|
||||
return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \
|
||||
rhs.validity()); \
|
||||
return CheckedNumeric<Promotion>::cast(lhs) \
|
||||
OP CheckedNumeric<Promotion>::cast(rhs); \
|
||||
}
|
||||
|
||||
BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += )
|
||||
BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= )
|
||||
BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= )
|
||||
BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= )
|
||||
BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= )
|
||||
|
||||
#undef BASE_NUMERIC_ARITHMETIC_OPERATORS
|
||||
|
||||
} // namespace internal
|
||||
|
||||
using internal::CheckedNumeric;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_NUMERICS_SAFE_MATH_H_
|
545
security/sandbox/chromium/base/numerics/safe_math_impl.h
Normal file
545
security/sandbox/chromium/base/numerics/safe_math_impl.h
Normal file
@ -0,0 +1,545 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_
|
||||
#define BASE_NUMERICS_SAFE_MATH_IMPL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "base/template_util.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
// Everything from here up to the floating point operations is portable C++,
|
||||
// but it may not be fast. This code could be split based on
|
||||
// platform/architecture and replaced with potentially faster implementations.
|
||||
|
||||
// Integer promotion templates used by the portable checked integer arithmetic.
|
||||
template <size_t Size, bool IsSigned>
|
||||
struct IntegerForSizeAndSign;
|
||||
template <>
|
||||
struct IntegerForSizeAndSign<1, true> {
|
||||
typedef int8_t type;
|
||||
};
|
||||
template <>
|
||||
struct IntegerForSizeAndSign<1, false> {
|
||||
typedef uint8_t type;
|
||||
};
|
||||
template <>
|
||||
struct IntegerForSizeAndSign<2, true> {
|
||||
typedef int16_t type;
|
||||
};
|
||||
template <>
|
||||
struct IntegerForSizeAndSign<2, false> {
|
||||
typedef uint16_t type;
|
||||
};
|
||||
template <>
|
||||
struct IntegerForSizeAndSign<4, true> {
|
||||
typedef int32_t type;
|
||||
};
|
||||
template <>
|
||||
struct IntegerForSizeAndSign<4, false> {
|
||||
typedef uint32_t type;
|
||||
};
|
||||
template <>
|
||||
struct IntegerForSizeAndSign<8, true> {
|
||||
typedef int64_t type;
|
||||
};
|
||||
template <>
|
||||
struct IntegerForSizeAndSign<8, false> {
|
||||
typedef uint64_t type;
|
||||
};
|
||||
|
||||
// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
|
||||
// support 128-bit math, then the ArithmeticPromotion template below will need
|
||||
// to be updated (or more likely replaced with a decltype expression).
|
||||
|
||||
template <typename Integer>
|
||||
struct UnsignedIntegerForSize {
|
||||
typedef typename std::enable_if<
|
||||
std::numeric_limits<Integer>::is_integer,
|
||||
typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
|
||||
};
|
||||
|
||||
template <typename Integer>
|
||||
struct SignedIntegerForSize {
|
||||
typedef typename std::enable_if<
|
||||
std::numeric_limits<Integer>::is_integer,
|
||||
typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
|
||||
};
|
||||
|
||||
template <typename Integer>
|
||||
struct TwiceWiderInteger {
|
||||
typedef typename std::enable_if<
|
||||
std::numeric_limits<Integer>::is_integer,
|
||||
typename IntegerForSizeAndSign<
|
||||
sizeof(Integer) * 2,
|
||||
std::numeric_limits<Integer>::is_signed>::type>::type type;
|
||||
};
|
||||
|
||||
template <typename Integer>
|
||||
struct PositionOfSignBit {
|
||||
static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
|
||||
size_t>::type value =
|
||||
8 * sizeof(Integer) - 1;
|
||||
};
|
||||
|
||||
// This is used for UnsignedAbs, where we need to support floating-point
|
||||
// template instantiations even though we don't actually support the operations.
|
||||
// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs,
|
||||
// so the float versions will not compile.
|
||||
template <typename Numeric,
|
||||
bool IsInteger = std::numeric_limits<Numeric>::is_integer,
|
||||
bool IsFloat = std::numeric_limits<Numeric>::is_iec559>
|
||||
struct UnsignedOrFloatForSize;
|
||||
|
||||
template <typename Numeric>
|
||||
struct UnsignedOrFloatForSize<Numeric, true, false> {
|
||||
typedef typename UnsignedIntegerForSize<Numeric>::type type;
|
||||
};
|
||||
|
||||
template <typename Numeric>
|
||||
struct UnsignedOrFloatForSize<Numeric, false, true> {
|
||||
typedef Numeric type;
|
||||
};
|
||||
|
||||
// Helper templates for integer manipulations.
|
||||
|
||||
template <typename T>
|
||||
bool HasSignBit(T x) {
|
||||
// Cast to unsigned since right shift on signed is undefined.
|
||||
return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
|
||||
PositionOfSignBit<T>::value);
|
||||
}
|
||||
|
||||
// This wrapper undoes the standard integer promotions.
|
||||
template <typename T>
|
||||
T BinaryComplement(T x) {
|
||||
return ~x;
|
||||
}
|
||||
|
||||
// Here are the actual portable checked integer math implementations.
|
||||
// TODO(jschuh): Break this code out from the enable_if pattern and find a clean
|
||||
// way to coalesce things into the CheckedNumericState specializations below.
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
|
||||
CheckedAdd(T x, T y, RangeConstraint* validity) {
|
||||
// Since the value of x+y is undefined if we have a signed type, we compute
|
||||
// it using the unsigned type of the same size.
|
||||
typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
|
||||
UnsignedDst ux = static_cast<UnsignedDst>(x);
|
||||
UnsignedDst uy = static_cast<UnsignedDst>(y);
|
||||
UnsignedDst uresult = ux + uy;
|
||||
// Addition is valid if the sign of (x + y) is equal to either that of x or
|
||||
// that of y.
|
||||
if (std::numeric_limits<T>::is_signed) {
|
||||
if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
|
||||
*validity = RANGE_VALID;
|
||||
else // Direction of wrap is inverse of result sign.
|
||||
*validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
|
||||
|
||||
} else { // Unsigned is either valid or overflow.
|
||||
*validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW;
|
||||
}
|
||||
return static_cast<T>(uresult);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
|
||||
CheckedSub(T x, T y, RangeConstraint* validity) {
|
||||
// Since the value of x+y is undefined if we have a signed type, we compute
|
||||
// it using the unsigned type of the same size.
|
||||
typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
|
||||
UnsignedDst ux = static_cast<UnsignedDst>(x);
|
||||
UnsignedDst uy = static_cast<UnsignedDst>(y);
|
||||
UnsignedDst uresult = ux - uy;
|
||||
// Subtraction is valid if either x and y have same sign, or (x-y) and x have
|
||||
// the same sign.
|
||||
if (std::numeric_limits<T>::is_signed) {
|
||||
if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
|
||||
*validity = RANGE_VALID;
|
||||
else // Direction of wrap is inverse of result sign.
|
||||
*validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
|
||||
|
||||
} else { // Unsigned is either valid or underflow.
|
||||
*validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW;
|
||||
}
|
||||
return static_cast<T>(uresult);
|
||||
}
|
||||
|
||||
// Integer multiplication is a bit complicated. In the fast case we just
|
||||
// we just promote to a twice wider type, and range check the result. In the
|
||||
// slow case we need to manually check that the result won't be truncated by
|
||||
// checking with division against the appropriate bound.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
sizeof(T) * 2 <= sizeof(uintmax_t),
|
||||
T>::type
|
||||
CheckedMul(T x, T y, RangeConstraint* validity) {
|
||||
typedef typename TwiceWiderInteger<T>::type IntermediateType;
|
||||
IntermediateType tmp =
|
||||
static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
|
||||
*validity = DstRangeRelationToSrcRange<T>(tmp);
|
||||
return static_cast<T>(tmp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
std::numeric_limits<T>::is_signed &&
|
||||
(sizeof(T) * 2 > sizeof(uintmax_t)),
|
||||
T>::type
|
||||
CheckedMul(T x, T y, RangeConstraint* validity) {
|
||||
// If either side is zero then the result will be zero.
|
||||
if (!x || !y) {
|
||||
return RANGE_VALID;
|
||||
|
||||
} else if (x > 0) {
|
||||
if (y > 0)
|
||||
*validity =
|
||||
x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
|
||||
else
|
||||
*validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
|
||||
: RANGE_UNDERFLOW;
|
||||
|
||||
} else {
|
||||
if (y > 0)
|
||||
*validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
|
||||
: RANGE_UNDERFLOW;
|
||||
else
|
||||
*validity =
|
||||
y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
|
||||
}
|
||||
|
||||
return x * y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed &&
|
||||
(sizeof(T) * 2 > sizeof(uintmax_t)),
|
||||
T>::type
|
||||
CheckedMul(T x, T y, RangeConstraint* validity) {
|
||||
*validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
|
||||
? RANGE_VALID
|
||||
: RANGE_OVERFLOW;
|
||||
return x * y;
|
||||
}
|
||||
|
||||
// Division just requires a check for an invalid negation on signed min/-1.
|
||||
template <typename T>
|
||||
T CheckedDiv(T x,
|
||||
T y,
|
||||
RangeConstraint* validity,
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer,
|
||||
int>::type = 0) {
|
||||
if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
|
||||
y == static_cast<T>(-1)) {
|
||||
*validity = RANGE_OVERFLOW;
|
||||
return std::numeric_limits<T>::min();
|
||||
}
|
||||
|
||||
*validity = RANGE_VALID;
|
||||
return x / y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
std::numeric_limits<T>::is_signed,
|
||||
T>::type
|
||||
CheckedMod(T x, T y, RangeConstraint* validity) {
|
||||
*validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
|
||||
return x % y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
T>::type
|
||||
CheckedMod(T x, T y, RangeConstraint* validity) {
|
||||
*validity = RANGE_VALID;
|
||||
return x % y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
std::numeric_limits<T>::is_signed,
|
||||
T>::type
|
||||
CheckedNeg(T value, RangeConstraint* validity) {
|
||||
*validity =
|
||||
value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
|
||||
// The negation of signed min is min, so catch that one.
|
||||
return -value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
T>::type
|
||||
CheckedNeg(T value, RangeConstraint* validity) {
|
||||
// The only legal unsigned negation is zero.
|
||||
*validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
|
||||
return static_cast<T>(
|
||||
-static_cast<typename SignedIntegerForSize<T>::type>(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
std::numeric_limits<T>::is_signed,
|
||||
T>::type
|
||||
CheckedAbs(T value, RangeConstraint* validity) {
|
||||
*validity =
|
||||
value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
|
||||
return static_cast<T>(std::abs(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
T>::type
|
||||
CheckedAbs(T value, RangeConstraint* validity) {
|
||||
// T is unsigned, so |value| must already be positive.
|
||||
*validity = RANGE_VALID;
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
std::numeric_limits<T>::is_signed,
|
||||
typename UnsignedIntegerForSize<T>::type>::type
|
||||
CheckedUnsignedAbs(T value) {
|
||||
typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
|
||||
return value == std::numeric_limits<T>::min()
|
||||
? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
|
||||
: static_cast<UnsignedT>(std::abs(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_integer &&
|
||||
!std::numeric_limits<T>::is_signed,
|
||||
T>::type
|
||||
CheckedUnsignedAbs(T value) {
|
||||
// T is unsigned, so |value| must already be positive.
|
||||
return value;
|
||||
}
|
||||
|
||||
// These are the floating point stubs that the compiler needs to see. Only the
|
||||
// negation operation is ever called.
|
||||
#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
|
||||
template <typename T> \
|
||||
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
|
||||
Checked##NAME(T, T, RangeConstraint*) { \
|
||||
NOTREACHED(); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
BASE_FLOAT_ARITHMETIC_STUBS(Add)
|
||||
BASE_FLOAT_ARITHMETIC_STUBS(Sub)
|
||||
BASE_FLOAT_ARITHMETIC_STUBS(Mul)
|
||||
BASE_FLOAT_ARITHMETIC_STUBS(Div)
|
||||
BASE_FLOAT_ARITHMETIC_STUBS(Mod)
|
||||
|
||||
#undef BASE_FLOAT_ARITHMETIC_STUBS
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
|
||||
T value,
|
||||
RangeConstraint*) {
|
||||
return -value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
|
||||
T value,
|
||||
RangeConstraint*) {
|
||||
return std::abs(value);
|
||||
}
|
||||
|
||||
// Floats carry around their validity state with them, but integers do not. So,
|
||||
// we wrap the underlying value in a specialization in order to hide that detail
|
||||
// and expose an interface via accessors.
|
||||
enum NumericRepresentation {
|
||||
NUMERIC_INTEGER,
|
||||
NUMERIC_FLOATING,
|
||||
NUMERIC_UNKNOWN
|
||||
};
|
||||
|
||||
template <typename NumericType>
|
||||
struct GetNumericRepresentation {
|
||||
static const NumericRepresentation value =
|
||||
std::numeric_limits<NumericType>::is_integer
|
||||
? NUMERIC_INTEGER
|
||||
: (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING
|
||||
: NUMERIC_UNKNOWN);
|
||||
};
|
||||
|
||||
template <typename T, NumericRepresentation type =
|
||||
GetNumericRepresentation<T>::value>
|
||||
class CheckedNumericState {};
|
||||
|
||||
// Integrals require quite a bit of additional housekeeping to manage state.
|
||||
template <typename T>
|
||||
class CheckedNumericState<T, NUMERIC_INTEGER> {
|
||||
private:
|
||||
T value_;
|
||||
RangeConstraint validity_;
|
||||
|
||||
public:
|
||||
template <typename Src, NumericRepresentation type>
|
||||
friend class CheckedNumericState;
|
||||
|
||||
CheckedNumericState() : value_(0), validity_(RANGE_VALID) {}
|
||||
|
||||
template <typename Src>
|
||||
CheckedNumericState(Src value, RangeConstraint validity)
|
||||
: value_(static_cast<T>(value)),
|
||||
validity_(GetRangeConstraint(validity |
|
||||
DstRangeRelationToSrcRange<T>(value))) {
|
||||
static_assert(std::numeric_limits<Src>::is_specialized,
|
||||
"Argument must be numeric.");
|
||||
}
|
||||
|
||||
// Copy constructor.
|
||||
template <typename Src>
|
||||
CheckedNumericState(const CheckedNumericState<Src>& rhs)
|
||||
: value_(static_cast<T>(rhs.value())),
|
||||
validity_(GetRangeConstraint(
|
||||
rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {}
|
||||
|
||||
template <typename Src>
|
||||
explicit CheckedNumericState(
|
||||
Src value,
|
||||
typename std::enable_if<std::numeric_limits<Src>::is_specialized,
|
||||
int>::type = 0)
|
||||
: value_(static_cast<T>(value)),
|
||||
validity_(DstRangeRelationToSrcRange<T>(value)) {}
|
||||
|
||||
RangeConstraint validity() const { return validity_; }
|
||||
T value() const { return value_; }
|
||||
};
|
||||
|
||||
// Floating points maintain their own validity, but need translation wrappers.
|
||||
template <typename T>
|
||||
class CheckedNumericState<T, NUMERIC_FLOATING> {
|
||||
private:
|
||||
T value_;
|
||||
|
||||
public:
|
||||
template <typename Src, NumericRepresentation type>
|
||||
friend class CheckedNumericState;
|
||||
|
||||
CheckedNumericState() : value_(0.0) {}
|
||||
|
||||
template <typename Src>
|
||||
CheckedNumericState(
|
||||
Src value,
|
||||
RangeConstraint validity,
|
||||
typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type =
|
||||
0) {
|
||||
switch (DstRangeRelationToSrcRange<T>(value)) {
|
||||
case RANGE_VALID:
|
||||
value_ = static_cast<T>(value);
|
||||
break;
|
||||
|
||||
case RANGE_UNDERFLOW:
|
||||
value_ = -std::numeric_limits<T>::infinity();
|
||||
break;
|
||||
|
||||
case RANGE_OVERFLOW:
|
||||
value_ = std::numeric_limits<T>::infinity();
|
||||
break;
|
||||
|
||||
case RANGE_INVALID:
|
||||
value_ = std::numeric_limits<T>::quiet_NaN();
|
||||
break;
|
||||
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Src>
|
||||
explicit CheckedNumericState(
|
||||
Src value,
|
||||
typename std::enable_if<std::numeric_limits<Src>::is_specialized,
|
||||
int>::type = 0)
|
||||
: value_(static_cast<T>(value)) {}
|
||||
|
||||
// Copy constructor.
|
||||
template <typename Src>
|
||||
CheckedNumericState(const CheckedNumericState<Src>& rhs)
|
||||
: value_(static_cast<T>(rhs.value())) {}
|
||||
|
||||
RangeConstraint validity() const {
|
||||
return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(),
|
||||
value_ >= -std::numeric_limits<T>::max());
|
||||
}
|
||||
T value() const { return value_; }
|
||||
};
|
||||
|
||||
// For integers less than 128-bit and floats 32-bit or larger, we can distil
|
||||
// C/C++ arithmetic promotions down to two simple rules:
|
||||
// 1. The type with the larger maximum exponent always takes precedence.
|
||||
// 2. The resulting type must be promoted to at least an int.
|
||||
// The following template specializations implement that promotion logic.
|
||||
enum ArithmeticPromotionCategory {
|
||||
LEFT_PROMOTION,
|
||||
RIGHT_PROMOTION,
|
||||
DEFAULT_PROMOTION
|
||||
};
|
||||
|
||||
template <typename Lhs,
|
||||
typename Rhs = Lhs,
|
||||
ArithmeticPromotionCategory Promotion =
|
||||
(MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
|
||||
? (MaxExponent<Lhs>::value > MaxExponent<int>::value
|
||||
? LEFT_PROMOTION
|
||||
: DEFAULT_PROMOTION)
|
||||
: (MaxExponent<Rhs>::value > MaxExponent<int>::value
|
||||
? RIGHT_PROMOTION
|
||||
: DEFAULT_PROMOTION) >
|
||||
struct ArithmeticPromotion;
|
||||
|
||||
template <typename Lhs, typename Rhs>
|
||||
struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
|
||||
typedef Lhs type;
|
||||
};
|
||||
|
||||
template <typename Lhs, typename Rhs>
|
||||
struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
|
||||
typedef Rhs type;
|
||||
};
|
||||
|
||||
template <typename Lhs, typename Rhs>
|
||||
struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> {
|
||||
typedef int type;
|
||||
};
|
||||
|
||||
// We can statically check if operations on the provided types can wrap, so we
|
||||
// can skip the checked operations if they're not needed. So, for an integer we
|
||||
// care if the destination type preserves the sign and is twice the width of
|
||||
// the source.
|
||||
template <typename T, typename Lhs, typename Rhs>
|
||||
struct IsIntegerArithmeticSafe {
|
||||
static const bool value = !std::numeric_limits<T>::is_iec559 &&
|
||||
StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
|
||||
NUMERIC_RANGE_CONTAINED &&
|
||||
sizeof(T) >= (2 * sizeof(Lhs)) &&
|
||||
StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
|
||||
NUMERIC_RANGE_CONTAINED &&
|
||||
sizeof(T) >= (2 * sizeof(Rhs));
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_
|
@ -13,9 +13,9 @@
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class FilePath;
|
||||
class ScopedPathOverride;
|
||||
} // namespace
|
||||
|
||||
// The path service is a global table mapping keys to file system paths. It is
|
||||
// OK to use this service from multiple threads.
|
||||
@ -29,7 +29,7 @@ class BASE_EXPORT PathService {
|
||||
//
|
||||
// Returns true if the directory or file was successfully retrieved. On
|
||||
// failure, 'path' will not be changed.
|
||||
static bool Get(int key, base::FilePath* path);
|
||||
static bool Get(int key, FilePath* path);
|
||||
|
||||
// Overrides the path to a special directory or file. This cannot be used to
|
||||
// change the value of DIR_CURRENT, but that should be obvious. Also, if the
|
||||
@ -44,7 +44,7 @@ class BASE_EXPORT PathService {
|
||||
//
|
||||
// Unit tests generally should use ScopedPathOverride instead. Overrides from
|
||||
// one test should not carry over to another.
|
||||
static bool Override(int key, const base::FilePath& path);
|
||||
static bool Override(int key, const FilePath& path);
|
||||
|
||||
// This function does the same as PathService::Override but it takes extra
|
||||
// parameters:
|
||||
@ -56,7 +56,7 @@ class BASE_EXPORT PathService {
|
||||
// - |create| guides whether the directory to be overriden must
|
||||
// be created in case it doesn't exist already.
|
||||
static bool OverrideAndCreateIfNeeded(int key,
|
||||
const base::FilePath& path,
|
||||
const FilePath& path,
|
||||
bool is_absolute,
|
||||
bool create);
|
||||
|
||||
@ -68,7 +68,7 @@ class BASE_EXPORT PathService {
|
||||
// WARNING: This function could be called on any thread from which the
|
||||
// PathService is used, so a the ProviderFunc MUST BE THREADSAFE.
|
||||
//
|
||||
typedef bool (*ProviderFunc)(int, base::FilePath*);
|
||||
typedef bool (*ProviderFunc)(int, FilePath*);
|
||||
|
||||
// Call to register a path provider. You must specify the range "[key_start,
|
||||
// key_end)" of supported path keys.
|
||||
@ -80,7 +80,7 @@ class BASE_EXPORT PathService {
|
||||
static void DisableCache();
|
||||
|
||||
private:
|
||||
friend class base::ScopedPathOverride;
|
||||
friend class ScopedPathOverride;
|
||||
FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride);
|
||||
|
||||
// Removes an override for a special directory or file. Returns true if there
|
||||
@ -89,4 +89,9 @@ class BASE_EXPORT PathService {
|
||||
static bool RemoveOverride(int key);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
// TODO(brettw) Convert all callers to using the base namespace and remove this.
|
||||
using base::PathService;
|
||||
|
||||
#endif // BASE_PATH_SERVICE_H_
|
||||
|
@ -1,48 +0,0 @@
|
||||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_PORT_H_
|
||||
#define BASE_PORT_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "build/build_config.h"
|
||||
|
||||
// DEPRECATED: Use ...LL and ...ULL suffixes.
|
||||
// TODO(viettrungluu): Delete these. These are only here until |GG_(U)INT64_C|
|
||||
// are deleted (some other header files (re)define |GG_(U)INT64_C|, so our
|
||||
// definitions of them must exactly match theirs).
|
||||
#ifdef COMPILER_MSVC
|
||||
#define GG_LONGLONG(x) x##I64
|
||||
#define GG_ULONGLONG(x) x##UI64
|
||||
#else
|
||||
#define GG_LONGLONG(x) x##LL
|
||||
#define GG_ULONGLONG(x) x##ULL
|
||||
#endif
|
||||
|
||||
// DEPRECATED: In Chromium, we force-define __STDC_CONSTANT_MACROS, so you can
|
||||
// just use the regular (U)INTn_C macros from <stdint.h>.
|
||||
// TODO(viettrungluu): Remove the remaining GG_(U)INTn_C macros.
|
||||
#define GG_INT64_C(x) GG_LONGLONG(x)
|
||||
#define GG_UINT64_C(x) GG_ULONGLONG(x)
|
||||
|
||||
// It's possible for functions that use a va_list, such as StringPrintf, to
|
||||
// invalidate the data in it upon use. The fix is to make a copy of the
|
||||
// structure before using it and use that copy instead. va_copy is provided
|
||||
// for this purpose. MSVC does not provide va_copy, so define an
|
||||
// implementation here. It is not guaranteed that assignment is a copy, so the
|
||||
// StringUtil.VariableArgsFunc unit test tests this capability.
|
||||
#if defined(COMPILER_GCC)
|
||||
#define GG_VA_COPY(a, b) (va_copy(a, b))
|
||||
#elif defined(COMPILER_MSVC)
|
||||
#define GG_VA_COPY(a, b) (a = b)
|
||||
#endif
|
||||
|
||||
// Define an OS-neutral wrapper for shared library entry points
|
||||
#if defined(OS_WIN)
|
||||
#define API_CALL __stdcall
|
||||
#else
|
||||
#define API_CALL
|
||||
#endif
|
||||
|
||||
#endif // BASE_PORT_H_
|
@ -5,12 +5,13 @@
|
||||
#ifndef BASE_PROCESS_PROCESS_HANDLE_H_
|
||||
#define BASE_PROCESS_PROCESS_HANDLE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
@ -35,58 +36,44 @@ const ProcessId kNullProcessId = 0;
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
// Returns the id of the current process.
|
||||
// Note that on some platforms, this is not guaranteed to be unique across
|
||||
// processes (use GetUniqueIdForProcess if uniqueness is required).
|
||||
BASE_EXPORT ProcessId GetCurrentProcId();
|
||||
|
||||
// Returns a unique ID for the current process. The ID will be unique across all
|
||||
// currently running processes within the chrome session, but IDs of terminated
|
||||
// processes may be reused. This returns an opaque value that is different from
|
||||
// a process's PID.
|
||||
BASE_EXPORT uint32_t GetUniqueIdForProcess();
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// When a process is started in a different PID namespace from the browser
|
||||
// process, this function must be called with the process's PID in the browser's
|
||||
// PID namespace in order to initialize its unique ID. Not thread safe.
|
||||
// WARNING: To avoid inconsistent results from GetUniqueIdForProcess, this
|
||||
// should only be called very early after process startup - ideally as soon
|
||||
// after process creation as possible.
|
||||
BASE_EXPORT void InitUniqueIdForProcessInPidNamespace(
|
||||
ProcessId pid_outside_of_namespace);
|
||||
#endif
|
||||
|
||||
// Returns the ProcessHandle of the current process.
|
||||
BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
|
||||
|
||||
// Converts a PID to a process handle. This handle must be closed by
|
||||
// CloseProcessHandle when you are done with it. Returns true on success.
|
||||
BASE_EXPORT bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
|
||||
|
||||
// Converts a PID to a process handle. On Windows the handle is opened
|
||||
// with more access rights and must only be used by trusted code.
|
||||
// You have to close returned handle using CloseProcessHandle. Returns true
|
||||
// on success.
|
||||
// TODO(sanjeevr): Replace all calls to OpenPrivilegedProcessHandle with the
|
||||
// more specific OpenProcessHandleWithAccess method and delete this.
|
||||
BASE_EXPORT bool OpenPrivilegedProcessHandle(ProcessId pid,
|
||||
ProcessHandle* handle);
|
||||
|
||||
// Converts a PID to a process handle using the desired access flags. Use a
|
||||
// combination of the kProcessAccess* flags defined above for |access_flags|.
|
||||
BASE_EXPORT bool OpenProcessHandleWithAccess(ProcessId pid,
|
||||
uint32 access_flags,
|
||||
ProcessHandle* handle);
|
||||
|
||||
// Closes the process handle opened by OpenProcessHandle.
|
||||
BASE_EXPORT void CloseProcessHandle(ProcessHandle process);
|
||||
|
||||
// Returns the unique ID for the specified process. This is functionally the
|
||||
// same as Windows' GetProcessId(), but works on versions of Windows before
|
||||
// Win XP SP1 as well.
|
||||
// Returns the process ID for the specified process. This is functionally the
|
||||
// same as Windows' GetProcessId(), but works on versions of Windows before Win
|
||||
// XP SP1 as well.
|
||||
// DEPRECATED. New code should be using Process::Pid() instead.
|
||||
// Note that on some platforms, this is not guaranteed to be unique across
|
||||
// processes.
|
||||
BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
enum IntegrityLevel {
|
||||
INTEGRITY_UNKNOWN,
|
||||
LOW_INTEGRITY,
|
||||
MEDIUM_INTEGRITY,
|
||||
HIGH_INTEGRITY,
|
||||
};
|
||||
// Determine the integrity level of the specified process. Returns false
|
||||
// if the system does not support integrity levels (pre-Vista) or in the case
|
||||
// of an underlying system failure.
|
||||
BASE_EXPORT bool GetProcessIntegrityLevel(ProcessHandle process,
|
||||
IntegrityLevel* level);
|
||||
#endif
|
||||
// Returns the ID for the parent of the given process.
|
||||
BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// Returns the path to the executable of the given process.
|
||||
BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
|
||||
|
||||
// Returns the ID for the parent of the given process.
|
||||
BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
@ -5,15 +5,18 @@
|
||||
#ifndef BASE_RAND_UTIL_H_
|
||||
#define BASE_RAND_UTIL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Returns a random number in range [0, kuint64max]. Thread-safe.
|
||||
BASE_EXPORT uint64 RandUint64();
|
||||
// Returns a random number in range [0, UINT64_MAX]. Thread-safe.
|
||||
BASE_EXPORT uint64_t RandUint64();
|
||||
|
||||
// Returns a random number between min and max (inclusive). Thread-safe.
|
||||
BASE_EXPORT int RandInt(int min, int max);
|
||||
@ -23,14 +26,14 @@ BASE_EXPORT int RandInt(int min, int max);
|
||||
// Note that this can be used as an adapter for std::random_shuffle():
|
||||
// Given a pre-populated |std::vector<int> myvector|, shuffle it as
|
||||
// std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator);
|
||||
BASE_EXPORT uint64 RandGenerator(uint64 range);
|
||||
BASE_EXPORT uint64_t RandGenerator(uint64_t range);
|
||||
|
||||
// Returns a random double in range [0, 1). Thread-safe.
|
||||
BASE_EXPORT double RandDouble();
|
||||
|
||||
// Given input |bits|, convert with maximum precision to a double in
|
||||
// the range [0, 1). Thread-safe.
|
||||
BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64 bits);
|
||||
BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64_t bits);
|
||||
|
||||
// Fills |output_length| bytes of |output| with random data.
|
||||
//
|
||||
|
@ -1,119 +0,0 @@
|
||||
// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// Post-L versions of bionic define the GNU-specific strerror_r if _GNU_SOURCE
|
||||
// is defined, but the symbol is renamed to __gnu_strerror_r which only exists
|
||||
// on those later versions. To preserve ABI compatibility with older versions,
|
||||
// undefine _GNU_SOURCE and use the POSIX version.
|
||||
#undef _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "base/safe_strerror_posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL))
|
||||
|
||||
#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
|
||||
// GCC will complain about the unused second wrap function unless we tell it
|
||||
// that we meant for them to be potentially unused, which is exactly what this
|
||||
// attribute is for.
|
||||
#define POSSIBLY_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define POSSIBLY_UNUSED
|
||||
#endif
|
||||
|
||||
#if USE_HISTORICAL_STRERRO_R
|
||||
// glibc has two strerror_r functions: a historical GNU-specific one that
|
||||
// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4
|
||||
// that returns int. This wraps the GNU-specific one.
|
||||
static void POSSIBLY_UNUSED wrap_posix_strerror_r(
|
||||
char *(*strerror_r_ptr)(int, char *, size_t),
|
||||
int err,
|
||||
char *buf,
|
||||
size_t len) {
|
||||
// GNU version.
|
||||
char *rc = (*strerror_r_ptr)(err, buf, len);
|
||||
if (rc != buf) {
|
||||
// glibc did not use buf and returned a static string instead. Copy it
|
||||
// into buf.
|
||||
buf[0] = '\0';
|
||||
strncat(buf, rc, len - 1);
|
||||
}
|
||||
// The GNU version never fails. Unknown errors get an "unknown error" message.
|
||||
// The result is always null terminated.
|
||||
}
|
||||
#endif // USE_HISTORICAL_STRERRO_R
|
||||
|
||||
// Wrapper for strerror_r functions that implement the POSIX interface. POSIX
|
||||
// does not define the behaviour for some of the edge cases, so we wrap it to
|
||||
// guarantee that they are handled. This is compiled on all POSIX platforms, but
|
||||
// it will only be used on Linux if the POSIX strerror_r implementation is
|
||||
// being used (see below).
|
||||
static void POSSIBLY_UNUSED wrap_posix_strerror_r(
|
||||
int (*strerror_r_ptr)(int, char *, size_t),
|
||||
int err,
|
||||
char *buf,
|
||||
size_t len) {
|
||||
int old_errno = errno;
|
||||
// Have to cast since otherwise we get an error if this is the GNU version
|
||||
// (but in such a scenario this function is never called). Sadly we can't use
|
||||
// C++-style casts because the appropriate one is reinterpret_cast but it's
|
||||
// considered illegal to reinterpret_cast a type to itself, so we get an
|
||||
// error in the opposite case.
|
||||
int result = (*strerror_r_ptr)(err, buf, len);
|
||||
if (result == 0) {
|
||||
// POSIX is vague about whether the string will be terminated, although
|
||||
// it indirectly implies that typically ERANGE will be returned, instead
|
||||
// of truncating the string. We play it safe by always terminating the
|
||||
// string explicitly.
|
||||
buf[len - 1] = '\0';
|
||||
} else {
|
||||
// Error. POSIX is vague about whether the return value is itself a system
|
||||
// error code or something else. On Linux currently it is -1 and errno is
|
||||
// set. On BSD-derived systems it is a system error and errno is unchanged.
|
||||
// We try and detect which case it is so as to put as much useful info as
|
||||
// we can into our message.
|
||||
int strerror_error; // The error encountered in strerror
|
||||
int new_errno = errno;
|
||||
if (new_errno != old_errno) {
|
||||
// errno was changed, so probably the return value is just -1 or something
|
||||
// else that doesn't provide any info, and errno is the error.
|
||||
strerror_error = new_errno;
|
||||
} else {
|
||||
// Either the error from strerror_r was the same as the previous value, or
|
||||
// errno wasn't used. Assume the latter.
|
||||
strerror_error = result;
|
||||
}
|
||||
// snprintf truncates and always null-terminates.
|
||||
snprintf(buf,
|
||||
len,
|
||||
"Error %d while retrieving error %d",
|
||||
strerror_error,
|
||||
err);
|
||||
}
|
||||
errno = old_errno;
|
||||
}
|
||||
|
||||
void safe_strerror_r(int err, char *buf, size_t len) {
|
||||
if (buf == NULL || len <= 0) {
|
||||
return;
|
||||
}
|
||||
// If using glibc (i.e., Linux), the compiler will automatically select the
|
||||
// appropriate overloaded function based on the function type of strerror_r.
|
||||
// The other one will be elided from the translation unit since both are
|
||||
// static.
|
||||
wrap_posix_strerror_r(&strerror_r, err, buf, len);
|
||||
}
|
||||
|
||||
std::string safe_strerror(int err) {
|
||||
const int buffer_size = 256;
|
||||
char buf[buffer_size];
|
||||
safe_strerror_r(err, buf, sizeof(buf));
|
||||
return std::string(buf);
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_SAFE_STRERROR_POSIX_H_
|
||||
#define BASE_SAFE_STRERROR_POSIX_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
// BEFORE using anything from this file, first look at PLOG and friends in
|
||||
// logging.h and use them instead if applicable.
|
||||
//
|
||||
// This file declares safe, portable alternatives to the POSIX strerror()
|
||||
// function. strerror() is inherently unsafe in multi-threaded apps and should
|
||||
// never be used. Doing so can cause crashes. Additionally, the thread-safe
|
||||
// alternative strerror_r varies in semantics across platforms. Use these
|
||||
// functions instead.
|
||||
|
||||
// Thread-safe strerror function with dependable semantics that never fails.
|
||||
// It will write the string form of error "err" to buffer buf of length len.
|
||||
// If there is an error calling the OS's strerror_r() function then a message to
|
||||
// that effect will be printed into buf, truncating if necessary. The final
|
||||
// result is always null-terminated. The value of errno is never changed.
|
||||
//
|
||||
// Use this instead of strerror_r().
|
||||
BASE_EXPORT void safe_strerror_r(int err, char *buf, size_t len);
|
||||
|
||||
// Calls safe_strerror_r with a buffer of suitable size and returns the result
|
||||
// in a C++ string.
|
||||
//
|
||||
// Use this instead of strerror(). Note though that safe_strerror_r will be
|
||||
// more robust in the case of heap corruption errors, since it doesn't need to
|
||||
// allocate a string.
|
||||
BASE_EXPORT std::string safe_strerror(int err);
|
||||
|
||||
#endif // BASE_SAFE_STRERROR_POSIX_H_
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/macros.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#define BASE_SEQUENCE_CHECKER_IMPL_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "base/threading/thread_checker_impl.h"
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_SEQUENCED_TASKRUNNER_H_
|
||||
#define BASE_SEQUENCED_TASKRUNNER_H_
|
||||
#ifndef BASE_SEQUENCED_TASK_RUNNER_H_
|
||||
#define BASE_SEQUENCED_TASK_RUNNER_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/sequenced_task_runner_helpers.h"
|
||||
@ -156,4 +156,4 @@ class BASE_EXPORT SequencedTaskRunner : public TaskRunner {
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SEQUENCED_TASKRUNNER_H_
|
||||
#endif // BASE_SEQUENCED_TASK_RUNNER_H_
|
||||
|
@ -5,8 +5,8 @@
|
||||
#ifndef BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
|
||||
#define BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/debug/alias.h"
|
||||
#include "base/macros.h"
|
||||
|
||||
// TODO(akalin): Investigate whether it's possible to just have
|
||||
// SequencedTaskRunner use these helpers (instead of MessageLoop).
|
||||
|
@ -16,7 +16,8 @@ namespace base {
|
||||
// there is a specific need to run tasks on only a single thread.
|
||||
//
|
||||
// SingleThreadTaskRunner implementations might:
|
||||
// - Post tasks to an existing thread's MessageLoop (see MessageLoopProxy).
|
||||
// - Post tasks to an existing thread's MessageLoop (see
|
||||
// MessageLoop::task_runner()).
|
||||
// - Create their own worker thread and MessageLoop to post tasks to.
|
||||
// - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to
|
||||
// be processed. This allows TaskRunner-oriented code run on threads
|
||||
|
@ -90,17 +90,12 @@ void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
|
||||
}
|
||||
}
|
||||
|
||||
// To treat a possibly-empty vector as an array, use these functions.
|
||||
// If you know the array will never be empty, you can use &*v.begin()
|
||||
// directly, but that is undefined behaviour if |v| is empty.
|
||||
template<typename T>
|
||||
inline T* vector_as_array(std::vector<T>* v) {
|
||||
return v->empty() ? NULL : &*v->begin();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T* vector_as_array(const std::vector<T>* v) {
|
||||
return v->empty() ? NULL : &*v->begin();
|
||||
// Counts the number of instances of val in a container.
|
||||
template <typename Container, typename T>
|
||||
typename std::iterator_traits<
|
||||
typename Container::const_iterator>::difference_type
|
||||
STLCount(const Container& container, const T& val) {
|
||||
return std::count(container.begin(), container.end(), val);
|
||||
}
|
||||
|
||||
// Return a mutable char* pointing to a string's internal buffer,
|
||||
@ -148,8 +143,7 @@ template <class T>
|
||||
void STLDeleteValues(T* container) {
|
||||
if (!container)
|
||||
return;
|
||||
for (typename T::iterator i(container->begin()); i != container->end(); ++i)
|
||||
delete i->second;
|
||||
STLDeleteContainerPairSecondPointers(container->begin(), container->end());
|
||||
container->clear();
|
||||
}
|
||||
|
||||
@ -196,6 +190,14 @@ bool ContainsKey(const Collection& collection, const Key& key) {
|
||||
return collection.find(key) != collection.end();
|
||||
}
|
||||
|
||||
// Test to see if a collection like a vector contains a particular value.
|
||||
// Returns true if the value is in the collection.
|
||||
template <typename Collection, typename Value>
|
||||
bool ContainsValue(const Collection& collection, const Value& value) {
|
||||
return std::find(collection.begin(), collection.end(), value) !=
|
||||
collection.end();
|
||||
}
|
||||
|
||||
namespace base {
|
||||
|
||||
// Returns true if the container is sorted.
|
||||
|
@ -41,6 +41,6 @@ inline bool operator!=(const NullableString16& a, const NullableString16& b) {
|
||||
BASE_EXPORT std::ostream& operator<<(std::ostream& out,
|
||||
const NullableString16& value);
|
||||
|
||||
} // namespace
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STRINGS_NULLABLE_STRING16_H_
|
||||
|
@ -4,8 +4,14 @@
|
||||
|
||||
#include "base/strings/safe_sprintf.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
// In debug builds, we use RAW_CHECK() to print useful error messages, if
|
||||
// SafeSPrintf() is called with broken arguments.
|
||||
@ -69,7 +75,7 @@ const char kDownCaseHexDigits[] = "0123456789abcdef";
|
||||
#if defined(NDEBUG)
|
||||
// We would like to define kSSizeMax as std::numeric_limits<ssize_t>::max(),
|
||||
// but C++ doesn't allow us to do that for constants. Instead, we have to
|
||||
// use careful casting and shifting. We later use a COMPILE_ASSERT to
|
||||
// use careful casting and shifting. We later use a static_assert to
|
||||
// verify that this worked correctly.
|
||||
namespace {
|
||||
const size_t kSSizeMax = kSSizeMaxConst;
|
||||
@ -107,18 +113,13 @@ class Buffer {
|
||||
: buffer_(buffer),
|
||||
size_(size - 1), // Account for trailing NUL byte
|
||||
count_(0) {
|
||||
// The following assertion does not build on Mac and Android. This is because
|
||||
// static_assert only works with compile-time constants, but mac uses
|
||||
// libstdc++4.2 and android uses stlport, which both don't mark
|
||||
// numeric_limits::max() as constexp. Likewise, MSVS2013's standard library
|
||||
// also doesn't mark max() as constexpr yet. cl.exe supports static_cast but
|
||||
// doesn't really implement constexpr yet so it doesn't complain, but clang
|
||||
// does.
|
||||
#if __cplusplus >= 201103 && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \
|
||||
!defined(OS_IOS) && !(defined(__clang__) && defined(OS_WIN))
|
||||
COMPILE_ASSERT(kSSizeMaxConst == \
|
||||
// MSVS2013's standard library doesn't mark max() as constexpr yet. cl.exe
|
||||
// supports static_cast but doesn't really implement constexpr yet so it doesn't
|
||||
// complain, but clang does.
|
||||
#if __cplusplus >= 201103 && !(defined(__clang__) && defined(OS_WIN))
|
||||
static_assert(kSSizeMaxConst ==
|
||||
static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
|
||||
kSSizeMax_is_the_max_value_of_an_ssize_t);
|
||||
"kSSizeMaxConst should be the max value of an ssize_t");
|
||||
#endif
|
||||
DEBUG_CHECK(size > 0);
|
||||
DEBUG_CHECK(size <= kSSizeMax);
|
||||
@ -510,11 +511,11 @@ ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt, const Arg* args,
|
||||
buffer.Pad(' ', padding, 1);
|
||||
|
||||
// Convert the argument to an ASCII character and output it.
|
||||
char ch = static_cast<char>(arg.integer.i);
|
||||
if (!ch) {
|
||||
char as_char = static_cast<char>(arg.integer.i);
|
||||
if (!as_char) {
|
||||
goto end_of_output_buffer;
|
||||
}
|
||||
buffer.Out(ch);
|
||||
buffer.Out(as_char);
|
||||
break; }
|
||||
case 'd': // Output a possibly signed decimal value.
|
||||
case 'o': // Output an unsigned octal value.
|
||||
|
@ -17,7 +17,6 @@
|
||||
#endif
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
namespace strings {
|
||||
|
@ -4,13 +4,17 @@
|
||||
|
||||
#include "base/strings/safe_sprintf.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "build/build_config.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
// Death tests on Android are currently very flaky. No need to add more flaky
|
||||
@ -61,7 +65,7 @@ TEST(SafeSPrintfTest, NoArguments) {
|
||||
// always add a trailing NUL; it always deduplicates '%' characters).
|
||||
static const char text[] = "hello world";
|
||||
char ref[20], buf[20];
|
||||
memset(ref, 'X', sizeof(char) * arraysize(buf));
|
||||
memset(ref, 'X', sizeof(ref));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// A negative buffer size should always result in an error.
|
||||
|
@ -26,11 +26,13 @@
|
||||
// libc functions with custom, 2-byte-char compatible routines. It is capable
|
||||
// of carrying UTF-16-encoded data.
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(WCHAR_T_IS_UTF16)
|
||||
|
||||
@ -46,7 +48,7 @@ typedef std::char_traits<wchar_t> string16_char_traits;
|
||||
|
||||
namespace base {
|
||||
|
||||
typedef uint16 char16;
|
||||
typedef uint16_t char16;
|
||||
|
||||
// char16 versions of the functions required by string16_char_traits; these
|
||||
// are based on the wide character functions of similar names ("w" or "wcs"
|
||||
@ -64,7 +66,8 @@ struct string16_char_traits {
|
||||
|
||||
// int_type needs to be able to hold each possible value of char_type, and in
|
||||
// addition, the distinct value of eof().
|
||||
COMPILE_ASSERT(sizeof(int_type) > sizeof(char_type), unexpected_type_width);
|
||||
static_assert(sizeof(int_type) > sizeof(char_type),
|
||||
"int must be larger than 16 bits wide");
|
||||
|
||||
typedef std::streamoff off_type;
|
||||
typedef mbstate_t state_type;
|
||||
@ -94,7 +97,7 @@ struct string16_char_traits {
|
||||
return c16memchr(s, a, n);
|
||||
}
|
||||
|
||||
static char_type* move(char_type* s1, const char_type* s2, int_type n) {
|
||||
static char_type* move(char_type* s1, const char_type* s2, size_t n) {
|
||||
return c16memmove(s1, s2, n);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <limits>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "base/numerics/safe_math.h"
|
||||
#include "base/scoped_clear_errno.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/third_party/dmg_fp/dmg_fp.h"
|
||||
@ -20,77 +22,37 @@ namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename STR, typename INT, typename UINT, bool NEG>
|
||||
template <typename STR, typename INT>
|
||||
struct IntToStringT {
|
||||
// This is to avoid a compiler warning about unary minus on unsigned type.
|
||||
// For example, say you had the following code:
|
||||
// template <typename INT>
|
||||
// INT abs(INT value) { return value < 0 ? -value : value; }
|
||||
// Even though if INT is unsigned, it's impossible for value < 0, so the
|
||||
// unary minus will never be taken, the compiler will still generate a
|
||||
// warning. We do a little specialization dance...
|
||||
template <typename INT2, typename UINT2, bool NEG2>
|
||||
struct ToUnsignedT {};
|
||||
|
||||
template <typename INT2, typename UINT2>
|
||||
struct ToUnsignedT<INT2, UINT2, false> {
|
||||
static UINT2 ToUnsigned(INT2 value) {
|
||||
return static_cast<UINT2>(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename INT2, typename UINT2>
|
||||
struct ToUnsignedT<INT2, UINT2, true> {
|
||||
static UINT2 ToUnsigned(INT2 value) {
|
||||
return static_cast<UINT2>(value < 0 ? -value : value);
|
||||
}
|
||||
};
|
||||
|
||||
// This set of templates is very similar to the above templates, but
|
||||
// for testing whether an integer is negative.
|
||||
template <typename INT2, bool NEG2>
|
||||
struct TestNegT {};
|
||||
template <typename INT2>
|
||||
struct TestNegT<INT2, false> {
|
||||
static bool TestNeg(INT2 value) {
|
||||
// value is unsigned, and can never be negative.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
template <typename INT2>
|
||||
struct TestNegT<INT2, true> {
|
||||
static bool TestNeg(INT2 value) {
|
||||
return value < 0;
|
||||
}
|
||||
};
|
||||
|
||||
static STR IntToString(INT value) {
|
||||
// log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
|
||||
// So round up to allocate 3 output characters per byte, plus 1 for '-'.
|
||||
const int kOutputBufSize = 3 * sizeof(INT) + 1;
|
||||
const size_t kOutputBufSize =
|
||||
3 * sizeof(INT) + std::numeric_limits<INT>::is_signed;
|
||||
|
||||
// Allocate the whole string right away, we will right back to front, and
|
||||
// Create the string in a temporary buffer, write it back to front, and
|
||||
// then return the substr of what we ended up using.
|
||||
STR outbuf(kOutputBufSize, 0);
|
||||
using CHR = typename STR::value_type;
|
||||
CHR outbuf[kOutputBufSize];
|
||||
|
||||
bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
|
||||
// Even though is_neg will never be true when INT is parameterized as
|
||||
// unsigned, even the presence of the unary operation causes a warning.
|
||||
UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
|
||||
// The ValueOrDie call below can never fail, because UnsignedAbs is valid
|
||||
// for all valid inputs.
|
||||
auto res = CheckedNumeric<INT>(value).UnsignedAbs().ValueOrDie();
|
||||
|
||||
typename STR::iterator it(outbuf.end());
|
||||
CHR* end = outbuf + kOutputBufSize;
|
||||
CHR* i = end;
|
||||
do {
|
||||
--it;
|
||||
DCHECK(it != outbuf.begin());
|
||||
*it = static_cast<typename STR::value_type>((res % 10) + '0');
|
||||
--i;
|
||||
DCHECK(i != outbuf);
|
||||
*i = static_cast<CHR>((res % 10) + '0');
|
||||
res /= 10;
|
||||
} while (res != 0);
|
||||
if (is_neg) {
|
||||
--it;
|
||||
DCHECK(it != outbuf.begin());
|
||||
*it = static_cast<typename STR::value_type>('-');
|
||||
if (IsValueNegative(value)) {
|
||||
--i;
|
||||
DCHECK(i != outbuf);
|
||||
*i = static_cast<CHR>('-');
|
||||
}
|
||||
return STR(it, outbuf.end());
|
||||
return STR(i, end);
|
||||
}
|
||||
};
|
||||
|
||||
@ -101,9 +63,9 @@ template<typename CHAR, int BASE, bool BASE_LTE_10> class BaseCharToDigit {
|
||||
// Faster specialization for bases <= 10
|
||||
template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
|
||||
public:
|
||||
static bool Convert(CHAR c, uint8* digit) {
|
||||
static bool Convert(CHAR c, uint8_t* digit) {
|
||||
if (c >= '0' && c < '0' + BASE) {
|
||||
*digit = static_cast<uint8>(c - '0');
|
||||
*digit = static_cast<uint8_t>(c - '0');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -113,7 +75,7 @@ template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
|
||||
// Specialization for bases where 10 < base <= 36
|
||||
template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
|
||||
public:
|
||||
static bool Convert(CHAR c, uint8* digit) {
|
||||
static bool Convert(CHAR c, uint8_t* digit) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
*digit = c - '0';
|
||||
} else if (c >= 'a' && c < 'a' + BASE - 10) {
|
||||
@ -127,14 +89,15 @@ template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
|
||||
}
|
||||
};
|
||||
|
||||
template<int BASE, typename CHAR> bool CharToDigit(CHAR c, uint8* digit) {
|
||||
template <int BASE, typename CHAR>
|
||||
bool CharToDigit(CHAR c, uint8_t* digit) {
|
||||
return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
|
||||
}
|
||||
|
||||
// There is an IsWhitespace for wchars defined in string_util.h, but it is
|
||||
// locale independent, whereas the functions we are replacing were
|
||||
// locale-dependent. TBD what is desired, but for the moment let's not introduce
|
||||
// a change in behaviour.
|
||||
// There is an IsUnicodeWhitespace for wchars defined in string_util.h, but it
|
||||
// is locale independent, whereas the functions we are replacing were
|
||||
// locale-dependent. TBD what is desired, but for the moment let's not
|
||||
// introduce a change in behaviour.
|
||||
template<typename CHAR> class WhitespaceHelper {
|
||||
};
|
||||
|
||||
@ -224,7 +187,7 @@ class IteratorRangeToNumber {
|
||||
}
|
||||
|
||||
for (const_iterator current = begin; current != end; ++current) {
|
||||
uint8 new_digit = 0;
|
||||
uint8_t new_digit = 0;
|
||||
|
||||
if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
|
||||
return false;
|
||||
@ -245,7 +208,7 @@ class IteratorRangeToNumber {
|
||||
|
||||
class Positive : public Base<Positive> {
|
||||
public:
|
||||
static bool CheckBounds(value_type* output, uint8 new_digit) {
|
||||
static bool CheckBounds(value_type* output, uint8_t new_digit) {
|
||||
if (*output > static_cast<value_type>(traits::max() / traits::kBase) ||
|
||||
(*output == static_cast<value_type>(traits::max() / traits::kBase) &&
|
||||
new_digit > traits::max() % traits::kBase)) {
|
||||
@ -254,14 +217,14 @@ class IteratorRangeToNumber {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static void Increment(uint8 increment, value_type* output) {
|
||||
static void Increment(uint8_t increment, value_type* output) {
|
||||
*output += increment;
|
||||
}
|
||||
};
|
||||
|
||||
class Negative : public Base<Negative> {
|
||||
public:
|
||||
static bool CheckBounds(value_type* output, uint8 new_digit) {
|
||||
static bool CheckBounds(value_type* output, uint8_t new_digit) {
|
||||
if (*output < traits::min() / traits::kBase ||
|
||||
(*output == traits::min() / traits::kBase &&
|
||||
new_digit > 0 - traits::min() % traits::kBase)) {
|
||||
@ -270,7 +233,7 @@ class IteratorRangeToNumber {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static void Increment(uint8 increment, value_type* output) {
|
||||
static void Increment(uint8_t increment, value_type* output) {
|
||||
*output -= increment;
|
||||
}
|
||||
};
|
||||
@ -295,20 +258,17 @@ class BaseHexIteratorRangeToIntTraits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
|
||||
};
|
||||
|
||||
template<typename ITERATOR>
|
||||
template <typename ITERATOR>
|
||||
class BaseHexIteratorRangeToUIntTraits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, uint32, 16> {
|
||||
};
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, uint32_t, 16> {};
|
||||
|
||||
template<typename ITERATOR>
|
||||
template <typename ITERATOR>
|
||||
class BaseHexIteratorRangeToInt64Traits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> {
|
||||
};
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, int64_t, 16> {};
|
||||
|
||||
template<typename ITERATOR>
|
||||
template <typename ITERATOR>
|
||||
class BaseHexIteratorRangeToUInt64Traits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, uint64, 16> {
|
||||
};
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, uint64_t, 16> {};
|
||||
|
||||
typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
|
||||
HexIteratorRangeToIntTraits;
|
||||
@ -322,15 +282,15 @@ typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
|
||||
typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator>
|
||||
HexIteratorRangeToUInt64Traits;
|
||||
|
||||
template<typename STR>
|
||||
bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
|
||||
template <typename STR>
|
||||
bool HexStringToBytesT(const STR& input, std::vector<uint8_t>* output) {
|
||||
DCHECK_EQ(output->size(), 0u);
|
||||
size_t count = input.size();
|
||||
if (count == 0 || (count % 2) != 0)
|
||||
return false;
|
||||
for (uintptr_t i = 0; i < count / 2; ++i) {
|
||||
uint8 msb = 0; // most significant 4 bits
|
||||
uint8 lsb = 0; // least significant 4 bits
|
||||
uint8_t msb = 0; // most significant 4 bits
|
||||
uint8_t lsb = 0; // least significant 4 bits
|
||||
if (!CharToDigit<16>(input[i * 2], &msb) ||
|
||||
!CharToDigit<16>(input[i * 2 + 1], &lsb))
|
||||
return false;
|
||||
@ -368,47 +328,43 @@ bool String16ToIntImpl(const StringPiece16& input, VALUE* output) {
|
||||
} // namespace
|
||||
|
||||
std::string IntToString(int value) {
|
||||
return IntToStringT<std::string, int, unsigned int, true>::
|
||||
IntToString(value);
|
||||
return IntToStringT<std::string, int>::IntToString(value);
|
||||
}
|
||||
|
||||
string16 IntToString16(int value) {
|
||||
return IntToStringT<string16, int, unsigned int, true>::
|
||||
IntToString(value);
|
||||
return IntToStringT<string16, int>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string UintToString(unsigned int value) {
|
||||
return IntToStringT<std::string, unsigned int, unsigned int, false>::
|
||||
IntToString(value);
|
||||
return IntToStringT<std::string, unsigned int>::IntToString(value);
|
||||
}
|
||||
|
||||
string16 UintToString16(unsigned int value) {
|
||||
return IntToStringT<string16, unsigned int, unsigned int, false>::
|
||||
IntToString(value);
|
||||
return IntToStringT<string16, unsigned int>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string Int64ToString(int64 value) {
|
||||
return IntToStringT<std::string, int64, uint64, true>::IntToString(value);
|
||||
std::string Int64ToString(int64_t value) {
|
||||
return IntToStringT<std::string, int64_t>::IntToString(value);
|
||||
}
|
||||
|
||||
string16 Int64ToString16(int64 value) {
|
||||
return IntToStringT<string16, int64, uint64, true>::IntToString(value);
|
||||
string16 Int64ToString16(int64_t value) {
|
||||
return IntToStringT<string16, int64_t>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string Uint64ToString(uint64 value) {
|
||||
return IntToStringT<std::string, uint64, uint64, false>::IntToString(value);
|
||||
std::string Uint64ToString(uint64_t value) {
|
||||
return IntToStringT<std::string, uint64_t>::IntToString(value);
|
||||
}
|
||||
|
||||
string16 Uint64ToString16(uint64 value) {
|
||||
return IntToStringT<string16, uint64, uint64, false>::IntToString(value);
|
||||
string16 Uint64ToString16(uint64_t value) {
|
||||
return IntToStringT<string16, uint64_t>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string SizeTToString(size_t value) {
|
||||
return IntToStringT<std::string, size_t, size_t, false>::IntToString(value);
|
||||
return IntToStringT<std::string, size_t>::IntToString(value);
|
||||
}
|
||||
|
||||
string16 SizeTToString16(size_t value) {
|
||||
return IntToStringT<string16, size_t, size_t, false>::IntToString(value);
|
||||
return IntToStringT<string16, size_t>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string DoubleToString(double value) {
|
||||
@ -434,19 +390,19 @@ bool StringToUint(const StringPiece16& input, unsigned* output) {
|
||||
return String16ToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToInt64(const StringPiece& input, int64* output) {
|
||||
bool StringToInt64(const StringPiece& input, int64_t* output) {
|
||||
return StringToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToInt64(const StringPiece16& input, int64* output) {
|
||||
bool StringToInt64(const StringPiece16& input, int64_t* output) {
|
||||
return String16ToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToUint64(const StringPiece& input, uint64* output) {
|
||||
bool StringToUint64(const StringPiece& input, uint64_t* output) {
|
||||
return StringToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToUint64(const StringPiece16& input, uint64* output) {
|
||||
bool StringToUint64(const StringPiece16& input, uint64_t* output) {
|
||||
return String16ToIntImpl(input, output);
|
||||
}
|
||||
|
||||
@ -507,22 +463,22 @@ bool HexStringToInt(const StringPiece& input, int* output) {
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
bool HexStringToUInt(const StringPiece& input, uint32* output) {
|
||||
bool HexStringToUInt(const StringPiece& input, uint32_t* output) {
|
||||
return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
bool HexStringToInt64(const StringPiece& input, int64* output) {
|
||||
bool HexStringToInt64(const StringPiece& input, int64_t* output) {
|
||||
return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
bool HexStringToUInt64(const StringPiece& input, uint64* output) {
|
||||
bool HexStringToUInt64(const StringPiece& input, uint64_t* output) {
|
||||
return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke(
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
|
||||
bool HexStringToBytes(const std::string& input, std::vector<uint8_t>* output) {
|
||||
return HexStringToBytesT(input, output);
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,13 @@
|
||||
#ifndef BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
|
||||
#define BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
@ -35,11 +37,11 @@ BASE_EXPORT string16 IntToString16(int value);
|
||||
BASE_EXPORT std::string UintToString(unsigned value);
|
||||
BASE_EXPORT string16 UintToString16(unsigned value);
|
||||
|
||||
BASE_EXPORT std::string Int64ToString(int64 value);
|
||||
BASE_EXPORT string16 Int64ToString16(int64 value);
|
||||
BASE_EXPORT std::string Int64ToString(int64_t value);
|
||||
BASE_EXPORT string16 Int64ToString16(int64_t value);
|
||||
|
||||
BASE_EXPORT std::string Uint64ToString(uint64 value);
|
||||
BASE_EXPORT string16 Uint64ToString16(uint64 value);
|
||||
BASE_EXPORT std::string Uint64ToString(uint64_t value);
|
||||
BASE_EXPORT string16 Uint64ToString16(uint64_t value);
|
||||
|
||||
BASE_EXPORT std::string SizeTToString(size_t value);
|
||||
BASE_EXPORT string16 SizeTToString16(size_t value);
|
||||
@ -64,27 +66,31 @@ BASE_EXPORT std::string DoubleToString(double value);
|
||||
// - No characters parseable as a number at the beginning of the string.
|
||||
// |*output| will be set to 0.
|
||||
// - Empty string. |*output| will be set to 0.
|
||||
// WARNING: Will write to |output| even when returning false.
|
||||
// Read the comments above carefully.
|
||||
BASE_EXPORT bool StringToInt(const StringPiece& input, int* output);
|
||||
BASE_EXPORT bool StringToInt(const StringPiece16& input, int* output);
|
||||
|
||||
BASE_EXPORT bool StringToUint(const StringPiece& input, unsigned* output);
|
||||
BASE_EXPORT bool StringToUint(const StringPiece16& input, unsigned* output);
|
||||
|
||||
BASE_EXPORT bool StringToInt64(const StringPiece& input, int64* output);
|
||||
BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64* output);
|
||||
BASE_EXPORT bool StringToInt64(const StringPiece& input, int64_t* output);
|
||||
BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64_t* output);
|
||||
|
||||
BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64* output);
|
||||
BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64* output);
|
||||
BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64_t* output);
|
||||
BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64_t* output);
|
||||
|
||||
BASE_EXPORT bool StringToSizeT(const StringPiece& input, size_t* output);
|
||||
BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output);
|
||||
|
||||
// For floating-point conversions, only conversions of input strings in decimal
|
||||
// form are defined to work. Behavior with strings representing floating-point
|
||||
// numbers in hexadecimal, and strings representing non-fininte values (such as
|
||||
// numbers in hexadecimal, and strings representing non-finite values (such as
|
||||
// NaN and inf) is undefined. Otherwise, these behave the same as the integral
|
||||
// variants. This expects the input string to NOT be specific to the locale.
|
||||
// If your input is locale specific, use ICU to read the number.
|
||||
// WARNING: Will write to |output| even when returning false.
|
||||
// Read the comments here and above StringToInt() carefully.
|
||||
BASE_EXPORT bool StringToDouble(const std::string& input, double* output);
|
||||
|
||||
// Hex encoding ----------------------------------------------------------------
|
||||
@ -106,25 +112,25 @@ BASE_EXPORT bool HexStringToInt(const StringPiece& input, int* output);
|
||||
// Will only successful parse hex values that will fit into |output|, i.e.
|
||||
// 0x00000000 < |input| < 0xFFFFFFFF.
|
||||
// The string is not required to start with 0x.
|
||||
BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32* output);
|
||||
BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32_t* output);
|
||||
|
||||
// Best effort conversion, see StringToInt above for restrictions.
|
||||
// Will only successful parse hex values that will fit into |output|, i.e.
|
||||
// -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF.
|
||||
BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64* output);
|
||||
BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64_t* output);
|
||||
|
||||
// Best effort conversion, see StringToInt above for restrictions.
|
||||
// Will only successful parse hex values that will fit into |output|, i.e.
|
||||
// 0x0000000000000000 < |input| < 0xFFFFFFFFFFFFFFFF.
|
||||
// The string is not required to start with 0x.
|
||||
BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64* output);
|
||||
BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64_t* output);
|
||||
|
||||
// Similar to the previous functions, except that output is a vector of bytes.
|
||||
// |*output| will contain as many bytes as were successfully parsed prior to the
|
||||
// error. There is no overflow, but input.size() must be evenly divisible by 2.
|
||||
// Leading 0x or +/- are not allowed.
|
||||
BASE_EXPORT bool HexStringToBytes(const std::string& input,
|
||||
std::vector<uint8>* output);
|
||||
std::vector<uint8_t>* output);
|
||||
|
||||
} // namespace base
|
||||
|
||||
|
@ -5,9 +5,13 @@
|
||||
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
namespace {
|
||||
|
||||
@ -433,5 +437,16 @@ StringPiece16 substr(const StringPiece16& self,
|
||||
return substrT(self, pos, n);
|
||||
}
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
void AssertIteratorsInOrder(std::string::const_iterator begin,
|
||||
std::string::const_iterator end) {
|
||||
DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
|
||||
}
|
||||
void AssertIteratorsInOrder(string16::const_iterator begin,
|
||||
string16::const_iterator end) {
|
||||
DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
@ -18,12 +18,6 @@
|
||||
// Both of these have the same lifetime semantics. Passing by value
|
||||
// generates slightly smaller code. For more discussion, Googlers can see
|
||||
// the thread go/stringpiecebyvalue on c-users.
|
||||
//
|
||||
// StringPiece16 is similar to StringPiece but for base::string16 instead of
|
||||
// std::string. We do not define as large of a subset of the STL functions
|
||||
// from basic_string as in StringPiece, but this can be changed if these
|
||||
// functions (find, find_first_of, etc.) are found to be useful in this context.
|
||||
//
|
||||
|
||||
#ifndef BASE_STRINGS_STRING_PIECE_H_
|
||||
#define BASE_STRINGS_STRING_PIECE_H_
|
||||
@ -34,10 +28,9 @@
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -150,6 +143,14 @@ BASE_EXPORT StringPiece16 substr(const StringPiece16& self,
|
||||
size_t pos,
|
||||
size_t n);
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
// Asserts that begin <= end to catch some errors with iterator usage.
|
||||
BASE_EXPORT void AssertIteratorsInOrder(std::string::const_iterator begin,
|
||||
std::string::const_iterator end);
|
||||
BASE_EXPORT void AssertIteratorsInOrder(string16::const_iterator begin,
|
||||
string16::const_iterator end);
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// BasicStringPiece ------------------------------------------------------------
|
||||
@ -187,9 +188,18 @@ template <typename STRING_TYPE> class BasicStringPiece {
|
||||
BasicStringPiece(const value_type* offset, size_type len)
|
||||
: ptr_(offset), length_(len) {}
|
||||
BasicStringPiece(const typename STRING_TYPE::const_iterator& begin,
|
||||
const typename STRING_TYPE::const_iterator& end)
|
||||
: ptr_((end > begin) ? &(*begin) : NULL),
|
||||
length_((end > begin) ? (size_type)(end - begin) : 0) {}
|
||||
const typename STRING_TYPE::const_iterator& end) {
|
||||
#if DCHECK_IS_ON()
|
||||
// This assertion is done out-of-line to avoid bringing in logging.h and
|
||||
// instantiating logging macros for every instantiation.
|
||||
internal::AssertIteratorsInOrder(begin, end);
|
||||
#endif
|
||||
length_ = static_cast<size_t>(std::distance(begin, end));
|
||||
|
||||
// The length test before assignment is to avoid dereferencing an iterator
|
||||
// that may point to the end() of a string.
|
||||
ptr_ = length_ > 0 ? &*begin : nullptr;
|
||||
}
|
||||
|
||||
// data() may return a pointer to a buffer with embedded NULs, and the
|
||||
// returned buffer may or may not be null terminated. Therefore it is
|
||||
|
@ -4,211 +4,261 @@
|
||||
|
||||
#include "base/strings/string_split.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/third_party/icu/icu_utf.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename STR>
|
||||
void SplitStringT(const STR& str,
|
||||
const typename STR::value_type s,
|
||||
bool trim_whitespace,
|
||||
std::vector<STR>* r) {
|
||||
r->clear();
|
||||
size_t last = 0;
|
||||
size_t c = str.size();
|
||||
for (size_t i = 0; i <= c; ++i) {
|
||||
if (i == c || str[i] == s) {
|
||||
STR tmp(str, last, i - last);
|
||||
if (trim_whitespace)
|
||||
TrimWhitespace(tmp, TRIM_ALL, &tmp);
|
||||
// Avoid converting an empty or all-whitespace source string into a vector
|
||||
// of one empty string.
|
||||
if (i != c || !r->empty() || !tmp.empty())
|
||||
r->push_back(tmp);
|
||||
last = i + 1;
|
||||
}
|
||||
}
|
||||
// PieceToOutputType converts a StringPiece as needed to a given output type,
|
||||
// which is either the same type of StringPiece (a NOP) or the corresponding
|
||||
// non-piece string type.
|
||||
//
|
||||
// The default converter is a NOP, it works when the OutputType is the
|
||||
// correct StringPiece.
|
||||
template<typename Str, typename OutputType>
|
||||
OutputType PieceToOutputType(BasicStringPiece<Str> piece) {
|
||||
return piece;
|
||||
}
|
||||
template<> // Convert StringPiece to std::string
|
||||
std::string PieceToOutputType<std::string, std::string>(StringPiece piece) {
|
||||
return piece.as_string();
|
||||
}
|
||||
template<> // Convert StringPiece16 to string16.
|
||||
string16 PieceToOutputType<string16, string16>(StringPiece16 piece) {
|
||||
return piece.as_string();
|
||||
}
|
||||
|
||||
bool SplitStringIntoKeyValue(const std::string& line,
|
||||
char key_value_delimiter,
|
||||
std::string* key,
|
||||
std::string* value) {
|
||||
key->clear();
|
||||
value->clear();
|
||||
// Returns either the ASCII or UTF-16 whitespace.
|
||||
template<typename Str> BasicStringPiece<Str> WhitespaceForType();
|
||||
template<> StringPiece16 WhitespaceForType<string16>() {
|
||||
return kWhitespaceUTF16;
|
||||
}
|
||||
template<> StringPiece WhitespaceForType<std::string>() {
|
||||
return kWhitespaceASCII;
|
||||
}
|
||||
|
||||
// Optimize the single-character case to call find() on the string instead,
|
||||
// since this is the common case and can be made faster. This could have been
|
||||
// done with template specialization too, but would have been less clear.
|
||||
//
|
||||
// There is no corresponding FindFirstNotOf because StringPiece already
|
||||
// implements these different versions that do the optimized searching.
|
||||
size_t FindFirstOf(StringPiece piece, char c, size_t pos) {
|
||||
return piece.find(c, pos);
|
||||
}
|
||||
size_t FindFirstOf(StringPiece16 piece, char16 c, size_t pos) {
|
||||
return piece.find(c, pos);
|
||||
}
|
||||
size_t FindFirstOf(StringPiece piece, StringPiece one_of, size_t pos) {
|
||||
return piece.find_first_of(one_of, pos);
|
||||
}
|
||||
size_t FindFirstOf(StringPiece16 piece, StringPiece16 one_of, size_t pos) {
|
||||
return piece.find_first_of(one_of, pos);
|
||||
}
|
||||
|
||||
// General string splitter template. Can take 8- or 16-bit input, can produce
|
||||
// the corresponding string or StringPiece output, and can take single- or
|
||||
// multiple-character delimiters.
|
||||
//
|
||||
// DelimiterType is either a character (Str::value_type) or a string piece of
|
||||
// multiple characters (BasicStringPiece<Str>). StringPiece has a version of
|
||||
// find for both of these cases, and the single-character version is the most
|
||||
// common and can be implemented faster, which is why this is a template.
|
||||
template<typename Str, typename OutputStringType, typename DelimiterType>
|
||||
static std::vector<OutputStringType> SplitStringT(
|
||||
BasicStringPiece<Str> str,
|
||||
DelimiterType delimiter,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type) {
|
||||
std::vector<OutputStringType> result;
|
||||
if (str.empty())
|
||||
return result;
|
||||
|
||||
size_t start = 0;
|
||||
while (start != Str::npos) {
|
||||
size_t end = FindFirstOf(str, delimiter, start);
|
||||
|
||||
BasicStringPiece<Str> piece;
|
||||
if (end == Str::npos) {
|
||||
piece = str.substr(start);
|
||||
start = Str::npos;
|
||||
} else {
|
||||
piece = str.substr(start, end - start);
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
if (whitespace == TRIM_WHITESPACE)
|
||||
piece = TrimString(piece, WhitespaceForType<Str>(), TRIM_ALL);
|
||||
|
||||
if (result_type == SPLIT_WANT_ALL || !piece.empty())
|
||||
result.push_back(PieceToOutputType<Str, OutputStringType>(piece));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AppendStringKeyValue(StringPiece input,
|
||||
char delimiter,
|
||||
StringPairs* result) {
|
||||
// Always append a new item regardless of success (it might be empty). The
|
||||
// below code will copy the strings directly into the result pair.
|
||||
result->resize(result->size() + 1);
|
||||
auto& result_pair = result->back();
|
||||
|
||||
// Find the delimiter.
|
||||
size_t end_key_pos = line.find_first_of(key_value_delimiter);
|
||||
size_t end_key_pos = input.find_first_of(delimiter);
|
||||
if (end_key_pos == std::string::npos) {
|
||||
DVLOG(1) << "cannot find delimiter in: " << line;
|
||||
return false; // no delimiter
|
||||
DVLOG(1) << "cannot find delimiter in: " << input;
|
||||
return false; // No delimiter.
|
||||
}
|
||||
key->assign(line, 0, end_key_pos);
|
||||
input.substr(0, end_key_pos).CopyToString(&result_pair.first);
|
||||
|
||||
// Find the value string.
|
||||
std::string remains(line, end_key_pos, line.size() - end_key_pos);
|
||||
size_t begin_value_pos = remains.find_first_not_of(key_value_delimiter);
|
||||
if (begin_value_pos == std::string::npos) {
|
||||
DVLOG(1) << "cannot parse value from line: " << line;
|
||||
return false; // no value
|
||||
StringPiece remains = input.substr(end_key_pos, input.size() - end_key_pos);
|
||||
size_t begin_value_pos = remains.find_first_not_of(delimiter);
|
||||
if (begin_value_pos == StringPiece::npos) {
|
||||
DVLOG(1) << "cannot parse value from input: " << input;
|
||||
return false; // No value.
|
||||
}
|
||||
value->assign(remains, begin_value_pos, remains.size() - begin_value_pos);
|
||||
remains.substr(begin_value_pos, remains.size() - begin_value_pos)
|
||||
.CopyToString(&result_pair.second);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename STR>
|
||||
void SplitStringUsingSubstrT(const STR& str,
|
||||
const STR& s,
|
||||
std::vector<STR>* r) {
|
||||
r->clear();
|
||||
typename STR::size_type begin_index = 0;
|
||||
while (true) {
|
||||
const typename STR::size_type end_index = str.find(s, begin_index);
|
||||
if (end_index == STR::npos) {
|
||||
const STR term = str.substr(begin_index);
|
||||
STR tmp;
|
||||
TrimWhitespace(term, TRIM_ALL, &tmp);
|
||||
r->push_back(tmp);
|
||||
return;
|
||||
}
|
||||
const STR term = str.substr(begin_index, end_index - begin_index);
|
||||
STR tmp;
|
||||
TrimWhitespace(term, TRIM_ALL, &tmp);
|
||||
r->push_back(tmp);
|
||||
begin_index = end_index + s.size();
|
||||
}
|
||||
}
|
||||
template <typename Str, typename OutputStringType>
|
||||
void SplitStringUsingSubstrT(BasicStringPiece<Str> input,
|
||||
BasicStringPiece<Str> delimiter,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type,
|
||||
std::vector<OutputStringType>* result) {
|
||||
using Piece = BasicStringPiece<Str>;
|
||||
using size_type = typename Piece::size_type;
|
||||
|
||||
template<typename STR>
|
||||
void SplitStringAlongWhitespaceT(const STR& str, std::vector<STR>* result) {
|
||||
result->clear();
|
||||
const size_t length = str.length();
|
||||
if (!length)
|
||||
return;
|
||||
for (size_type begin_index = 0, end_index = 0; end_index != Piece::npos;
|
||||
begin_index = end_index + delimiter.size()) {
|
||||
end_index = input.find(delimiter, begin_index);
|
||||
Piece term = end_index == Piece::npos
|
||||
? input.substr(begin_index)
|
||||
: input.substr(begin_index, end_index - begin_index);
|
||||
|
||||
bool last_was_ws = false;
|
||||
size_t last_non_ws_start = 0;
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
switch (str[i]) {
|
||||
// HTML 5 defines whitespace as: space, tab, LF, line tab, FF, or CR.
|
||||
case L' ':
|
||||
case L'\t':
|
||||
case L'\xA':
|
||||
case L'\xB':
|
||||
case L'\xC':
|
||||
case L'\xD':
|
||||
if (!last_was_ws) {
|
||||
if (i > 0) {
|
||||
result->push_back(
|
||||
str.substr(last_non_ws_start, i - last_non_ws_start));
|
||||
}
|
||||
last_was_ws = true;
|
||||
}
|
||||
break;
|
||||
if (whitespace == TRIM_WHITESPACE)
|
||||
term = TrimString(term, WhitespaceForType<Str>(), TRIM_ALL);
|
||||
|
||||
default: // Not a space character.
|
||||
if (last_was_ws) {
|
||||
last_was_ws = false;
|
||||
last_non_ws_start = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!last_was_ws) {
|
||||
result->push_back(
|
||||
str.substr(last_non_ws_start, length - last_non_ws_start));
|
||||
if (result_type == SPLIT_WANT_ALL || !term.empty())
|
||||
result->push_back(PieceToOutputType<Str, OutputStringType>(term));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SplitString(const string16& str,
|
||||
char16 c,
|
||||
std::vector<string16>* r) {
|
||||
DCHECK(CBU16_IS_SINGLE(c));
|
||||
SplitStringT(str, c, true, r);
|
||||
std::vector<std::string> SplitString(StringPiece input,
|
||||
StringPiece separators,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type) {
|
||||
if (separators.size() == 1) {
|
||||
return SplitStringT<std::string, std::string, char>(
|
||||
input, separators[0], whitespace, result_type);
|
||||
}
|
||||
return SplitStringT<std::string, std::string, StringPiece>(
|
||||
input, separators, whitespace, result_type);
|
||||
}
|
||||
|
||||
void SplitString(const std::string& str,
|
||||
char c,
|
||||
std::vector<std::string>* r) {
|
||||
#if CHAR_MIN < 0
|
||||
DCHECK(c >= 0);
|
||||
#endif
|
||||
DCHECK(c < 0x7F);
|
||||
SplitStringT(str, c, true, r);
|
||||
std::vector<string16> SplitString(StringPiece16 input,
|
||||
StringPiece16 separators,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type) {
|
||||
if (separators.size() == 1) {
|
||||
return SplitStringT<string16, string16, char16>(
|
||||
input, separators[0], whitespace, result_type);
|
||||
}
|
||||
return SplitStringT<string16, string16, StringPiece16>(
|
||||
input, separators, whitespace, result_type);
|
||||
}
|
||||
|
||||
bool SplitStringIntoKeyValuePairs(const std::string& line,
|
||||
std::vector<StringPiece> SplitStringPiece(StringPiece input,
|
||||
StringPiece separators,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type) {
|
||||
if (separators.size() == 1) {
|
||||
return SplitStringT<std::string, StringPiece, char>(
|
||||
input, separators[0], whitespace, result_type);
|
||||
}
|
||||
return SplitStringT<std::string, StringPiece, StringPiece>(
|
||||
input, separators, whitespace, result_type);
|
||||
}
|
||||
|
||||
std::vector<StringPiece16> SplitStringPiece(StringPiece16 input,
|
||||
StringPiece16 separators,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type) {
|
||||
if (separators.size() == 1) {
|
||||
return SplitStringT<string16, StringPiece16, char16>(
|
||||
input, separators[0], whitespace, result_type);
|
||||
}
|
||||
return SplitStringT<string16, StringPiece16, StringPiece16>(
|
||||
input, separators, whitespace, result_type);
|
||||
}
|
||||
|
||||
bool SplitStringIntoKeyValuePairs(StringPiece input,
|
||||
char key_value_delimiter,
|
||||
char key_value_pair_delimiter,
|
||||
StringPairs* key_value_pairs) {
|
||||
key_value_pairs->clear();
|
||||
|
||||
std::vector<std::string> pairs;
|
||||
SplitString(line, key_value_pair_delimiter, &pairs);
|
||||
std::vector<StringPiece> pairs = SplitStringPiece(
|
||||
input, std::string(1, key_value_pair_delimiter),
|
||||
TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
|
||||
key_value_pairs->reserve(pairs.size());
|
||||
|
||||
bool success = true;
|
||||
for (size_t i = 0; i < pairs.size(); ++i) {
|
||||
// Don't add empty pairs into the result.
|
||||
if (pairs[i].empty())
|
||||
continue;
|
||||
|
||||
std::string key;
|
||||
std::string value;
|
||||
if (!SplitStringIntoKeyValue(pairs[i], key_value_delimiter, &key, &value)) {
|
||||
for (const StringPiece& pair : pairs) {
|
||||
if (!AppendStringKeyValue(pair, key_value_delimiter, key_value_pairs)) {
|
||||
// Don't return here, to allow for pairs without associated
|
||||
// value or key; just record that the split failed.
|
||||
success = false;
|
||||
}
|
||||
key_value_pairs->push_back(make_pair(key, value));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void SplitStringUsingSubstr(const string16& str,
|
||||
const string16& s,
|
||||
std::vector<string16>* r) {
|
||||
SplitStringUsingSubstrT(str, s, r);
|
||||
}
|
||||
|
||||
void SplitStringUsingSubstr(const std::string& str,
|
||||
const std::string& s,
|
||||
std::vector<std::string>* r) {
|
||||
SplitStringUsingSubstrT(str, s, r);
|
||||
}
|
||||
|
||||
void SplitStringDontTrim(const string16& str,
|
||||
char16 c,
|
||||
std::vector<string16>* r) {
|
||||
DCHECK(CBU16_IS_SINGLE(c));
|
||||
SplitStringT(str, c, false, r);
|
||||
}
|
||||
|
||||
void SplitStringDontTrim(const std::string& str,
|
||||
char c,
|
||||
std::vector<std::string>* r) {
|
||||
DCHECK(IsStringUTF8(str));
|
||||
#if CHAR_MIN < 0
|
||||
DCHECK(c >= 0);
|
||||
#endif
|
||||
DCHECK(c < 0x7F);
|
||||
SplitStringT(str, c, false, r);
|
||||
}
|
||||
|
||||
void SplitStringAlongWhitespace(const string16& str,
|
||||
void SplitStringUsingSubstr(StringPiece16 input,
|
||||
StringPiece16 delimiter,
|
||||
std::vector<string16>* result) {
|
||||
SplitStringAlongWhitespaceT(str, result);
|
||||
SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
|
||||
result);
|
||||
}
|
||||
|
||||
void SplitStringAlongWhitespace(const std::string& str,
|
||||
void SplitStringUsingSubstr(StringPiece input,
|
||||
StringPiece delimiter,
|
||||
std::vector<std::string>* result) {
|
||||
SplitStringAlongWhitespaceT(str, result);
|
||||
SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
|
||||
result);
|
||||
}
|
||||
|
||||
std::vector<StringPiece16> SplitStringPieceUsingSubstr(
|
||||
StringPiece16 input,
|
||||
StringPiece16 delimiter,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type) {
|
||||
std::vector<StringPiece16> result;
|
||||
SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<StringPiece> SplitStringPieceUsingSubstr(
|
||||
StringPiece input,
|
||||
StringPiece delimiter,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type) {
|
||||
std::vector<StringPiece> result;
|
||||
SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
@ -11,72 +11,119 @@
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Splits |str| into a vector of strings delimited by |c|, placing the results
|
||||
// in |r|. If several instances of |c| are contiguous, or if |str| begins with
|
||||
// or ends with |c|, then an empty string is inserted.
|
||||
enum WhitespaceHandling {
|
||||
KEEP_WHITESPACE,
|
||||
TRIM_WHITESPACE,
|
||||
};
|
||||
|
||||
enum SplitResult {
|
||||
// Strictly return all results.
|
||||
//
|
||||
// If the input is ",," and the separator is ',' this will return a
|
||||
// vector of three empty strings.
|
||||
SPLIT_WANT_ALL,
|
||||
|
||||
// Only nonempty results will be added to the results. Multiple separators
|
||||
// will be coalesced. Separators at the beginning and end of the input will
|
||||
// be ignored. With TRIM_WHITESPACE, whitespace-only results will be dropped.
|
||||
//
|
||||
// If the input is ",," and the separator is ',', this will return an empty
|
||||
// vector.
|
||||
SPLIT_WANT_NONEMPTY,
|
||||
};
|
||||
|
||||
// Split the given string on ANY of the given separators, returning copies of
|
||||
// the result.
|
||||
//
|
||||
// Every substring is trimmed of any leading or trailing white space.
|
||||
// NOTE: |c| must be in BMP (Basic Multilingual Plane)
|
||||
BASE_EXPORT void SplitString(const string16& str,
|
||||
char16 c,
|
||||
std::vector<string16>* r);
|
||||
// To split on either commas or semicolons, keeping all whitespace:
|
||||
//
|
||||
// std::vector<std::string> tokens = base::SplitString(
|
||||
// input, ",;", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
|
||||
BASE_EXPORT std::vector<std::string> SplitString(
|
||||
StringPiece input,
|
||||
StringPiece separators,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type);
|
||||
BASE_EXPORT std::vector<string16> SplitString(
|
||||
StringPiece16 input,
|
||||
StringPiece16 separators,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type);
|
||||
|
||||
// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
|
||||
// the trailing byte of a multi-byte character can be in the ASCII range.
|
||||
// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
|
||||
// Note: |c| must be in the ASCII range.
|
||||
BASE_EXPORT void SplitString(const std::string& str,
|
||||
char c,
|
||||
std::vector<std::string>* r);
|
||||
// Like SplitString above except it returns a vector of StringPieces which
|
||||
// reference the original buffer without copying. Although you have to be
|
||||
// careful to keep the original string unmodified, this provides an efficient
|
||||
// way to iterate through tokens in a string.
|
||||
//
|
||||
// To iterate through all whitespace-separated tokens in an input string:
|
||||
//
|
||||
// for (const auto& cur :
|
||||
// base::SplitStringPiece(input, base::kWhitespaceASCII,
|
||||
// base::KEEP_WHITESPACE,
|
||||
// base::SPLIT_WANT_NONEMPTY)) {
|
||||
// ...
|
||||
BASE_EXPORT std::vector<StringPiece> SplitStringPiece(
|
||||
StringPiece input,
|
||||
StringPiece separators,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type);
|
||||
BASE_EXPORT std::vector<StringPiece16> SplitStringPiece(
|
||||
StringPiece16 input,
|
||||
StringPiece16 separators,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type);
|
||||
|
||||
typedef std::vector<std::pair<std::string, std::string> > StringPairs;
|
||||
using StringPairs = std::vector<std::pair<std::string, std::string>>;
|
||||
|
||||
// Splits |line| into key value pairs according to the given delimiters and
|
||||
// removes whitespace leading each key and trailing each value. Returns true
|
||||
// only if each pair has a non-empty key and value. |key_value_pairs| will
|
||||
// include ("","") pairs for entries without |key_value_delimiter|.
|
||||
BASE_EXPORT bool SplitStringIntoKeyValuePairs(const std::string& line,
|
||||
BASE_EXPORT bool SplitStringIntoKeyValuePairs(StringPiece input,
|
||||
char key_value_delimiter,
|
||||
char key_value_pair_delimiter,
|
||||
StringPairs* key_value_pairs);
|
||||
|
||||
// The same as SplitString, but use a substring delimiter instead of a char.
|
||||
BASE_EXPORT void SplitStringUsingSubstr(const string16& str,
|
||||
const string16& s,
|
||||
std::vector<string16>* r);
|
||||
BASE_EXPORT void SplitStringUsingSubstr(const std::string& str,
|
||||
const std::string& s,
|
||||
std::vector<std::string>* r);
|
||||
|
||||
// The same as SplitString, but don't trim white space.
|
||||
// NOTE: |c| must be in BMP (Basic Multilingual Plane)
|
||||
BASE_EXPORT void SplitStringDontTrim(const string16& str,
|
||||
char16 c,
|
||||
std::vector<string16>* r);
|
||||
// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
|
||||
// the trailing byte of a multi-byte character can be in the ASCII range.
|
||||
// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
|
||||
// Note: |c| must be in the ASCII range.
|
||||
BASE_EXPORT void SplitStringDontTrim(const std::string& str,
|
||||
char c,
|
||||
std::vector<std::string>* r);
|
||||
|
||||
// WARNING: this uses whitespace as defined by the HTML5 spec. If you need
|
||||
// a function similar to this but want to trim all types of whitespace, then
|
||||
// factor this out into a function that takes a string containing the characters
|
||||
// that are treated as whitespace.
|
||||
// Similar to SplitString, but use a substring delimiter instead of a list of
|
||||
// characters that are all possible delimiters.
|
||||
//
|
||||
// Splits the string along whitespace (where whitespace is the five space
|
||||
// characters defined by HTML 5). Each contiguous block of non-whitespace
|
||||
// characters is added to result.
|
||||
BASE_EXPORT void SplitStringAlongWhitespace(const string16& str,
|
||||
// TODO(brettw) this should probably be changed and expanded to provide a
|
||||
// mirror of the SplitString[Piece] API above, just with the different
|
||||
// delimiter handling.
|
||||
BASE_EXPORT void SplitStringUsingSubstr(StringPiece16 input,
|
||||
StringPiece16 delimiter,
|
||||
std::vector<string16>* result);
|
||||
BASE_EXPORT void SplitStringAlongWhitespace(const std::string& str,
|
||||
BASE_EXPORT void SplitStringUsingSubstr(StringPiece input,
|
||||
StringPiece delimiter,
|
||||
std::vector<std::string>* result);
|
||||
|
||||
// Like SplitStringUsingSubstr above except it returns a vector of StringPieces
|
||||
// which reference the original buffer without copying. Although you have to be
|
||||
// careful to keep the original string unmodified, this provides an efficient
|
||||
// way to iterate through tokens in a string.
|
||||
//
|
||||
// To iterate through all newline-separated tokens in an input string:
|
||||
//
|
||||
// for (const auto& cur :
|
||||
// base::SplitStringUsingSubstr(input, "\r\n",
|
||||
// base::KEEP_WHITESPACE,
|
||||
// base::SPLIT_WANT_NONEMPTY)) {
|
||||
// ...
|
||||
BASE_EXPORT std::vector<StringPiece16> SplitStringPieceUsingSubstr(
|
||||
StringPiece16 input,
|
||||
StringPiece16 delimiter,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type);
|
||||
BASE_EXPORT std::vector<StringPiece> SplitStringPieceUsingSubstr(
|
||||
StringPiece input,
|
||||
StringPiece delimiter,
|
||||
WhitespaceHandling whitespace,
|
||||
SplitResult result_type);
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STRINGS_STRING_SPLIT_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,35 +9,24 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h> // va_list
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/string_piece.h" // For implicit conversions.
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// C standard-library functions like "strncasecmp" and "snprintf" that aren't
|
||||
// cross-platform are provided as "base::strncasecmp", and their prototypes
|
||||
// are listed below. These functions are then implemented as inline calls
|
||||
// to the platform-specific equivalents in the platform-specific headers.
|
||||
|
||||
// Compares the two strings s1 and s2 without regard to case using
|
||||
// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
|
||||
// s2 > s1 according to a lexicographic comparison.
|
||||
int strcasecmp(const char* s1, const char* s2);
|
||||
|
||||
// Compares up to count characters of s1 and s2 without regard to case using
|
||||
// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
|
||||
// s2 > s1 according to a lexicographic comparison.
|
||||
int strncasecmp(const char* s1, const char* s2, size_t count);
|
||||
|
||||
// Same as strncmp but for char16 strings.
|
||||
int strncmp16(const char16* s1, const char16* s2, size_t count);
|
||||
// C standard-library functions that aren't cross-platform are provided as
|
||||
// "base::...", and their prototypes are listed below. These functions are
|
||||
// then implemented as inline calls to the platform-specific equivalents in the
|
||||
// platform-specific headers.
|
||||
|
||||
// Wrapper for vsnprintf that always null-terminates and always returns the
|
||||
// number of characters that would be in an untruncated formatted
|
||||
@ -49,9 +38,14 @@ int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments)
|
||||
|
||||
// We separate the declaration from the implementation of this inline
|
||||
// function just so the PRINTF_FORMAT works.
|
||||
inline int snprintf(char* buffer, size_t size, const char* format, ...)
|
||||
PRINTF_FORMAT(3, 4);
|
||||
inline int snprintf(char* buffer, size_t size, const char* format, ...) {
|
||||
inline int snprintf(char* buffer,
|
||||
size_t size,
|
||||
_Printf_format_string_ const char* format,
|
||||
...) PRINTF_FORMAT(3, 4);
|
||||
inline int snprintf(char* buffer,
|
||||
size_t size,
|
||||
_Printf_format_string_ const char* format,
|
||||
...) {
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = vsnprintf(buffer, size, format, arguments);
|
||||
@ -93,27 +87,38 @@ BASE_EXPORT bool IsWprintfFormatPortable(const wchar_t* format);
|
||||
|
||||
// ASCII-specific tolower. The standard library's tolower is locale sensitive,
|
||||
// so we don't want to use it here.
|
||||
template <class Char> inline Char ToLowerASCII(Char c) {
|
||||
inline char ToLowerASCII(char c) {
|
||||
return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
|
||||
}
|
||||
inline char16 ToLowerASCII(char16 c) {
|
||||
return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
|
||||
}
|
||||
|
||||
// ASCII-specific toupper. The standard library's toupper is locale sensitive,
|
||||
// so we don't want to use it here.
|
||||
template <class Char> inline Char ToUpperASCII(Char c) {
|
||||
inline char ToUpperASCII(char c) {
|
||||
return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
|
||||
}
|
||||
inline char16 ToUpperASCII(char16 c) {
|
||||
return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
|
||||
}
|
||||
|
||||
// Function objects to aid in comparing/searching strings.
|
||||
// Converts the given string to it's ASCII-lowercase equivalent.
|
||||
BASE_EXPORT std::string ToLowerASCII(StringPiece str);
|
||||
BASE_EXPORT string16 ToLowerASCII(StringPiece16 str);
|
||||
|
||||
template<typename Char> struct CaseInsensitiveCompare {
|
||||
public:
|
||||
bool operator()(Char x, Char y) const {
|
||||
// TODO(darin): Do we really want to do locale sensitive comparisons here?
|
||||
// See http://crbug.com/24917
|
||||
return tolower(x) == tolower(y);
|
||||
}
|
||||
};
|
||||
// Converts the given string to it's ASCII-uppercase equivalent.
|
||||
BASE_EXPORT std::string ToUpperASCII(StringPiece str);
|
||||
BASE_EXPORT string16 ToUpperASCII(StringPiece16 str);
|
||||
|
||||
// Functor for case-insensitive ASCII comparisons for STL algorithms like
|
||||
// std::search.
|
||||
//
|
||||
// Note that a full Unicode version of this functor is not possible to write
|
||||
// because case mappings might change the number of characters, depend on
|
||||
// context (combining accents), and require handling UTF-16. If you need
|
||||
// proper Unicode support, use base::i18n::ToLower/FoldCase and then just
|
||||
// use a normal operator== on the result.
|
||||
template<typename Char> struct CaseInsensitiveCompareASCII {
|
||||
public:
|
||||
bool operator()(Char x, Char y) const {
|
||||
@ -121,6 +126,22 @@ template<typename Char> struct CaseInsensitiveCompareASCII {
|
||||
}
|
||||
};
|
||||
|
||||
// Like strcasecmp for case-insensitive ASCII characters only. Returns:
|
||||
// -1 (a < b)
|
||||
// 0 (a == b)
|
||||
// 1 (a > b)
|
||||
// (unlike strcasecmp which can return values greater or less than 1/-1). For
|
||||
// full Unicode support, use base::i18n::ToLower or base::i18h::FoldCase
|
||||
// and then just call the normal string operators on the result.
|
||||
BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b);
|
||||
BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
|
||||
|
||||
// Equality for ASCII case-insensitive comparisons. For full Unicode support,
|
||||
// use base::i18n::ToLower or base::i18h::FoldCase and then compare with either
|
||||
// == or !=.
|
||||
BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b);
|
||||
BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
|
||||
|
||||
// These threadsafe functions return references to globally unique empty
|
||||
// strings.
|
||||
//
|
||||
@ -138,10 +159,12 @@ BASE_EXPORT const std::string& EmptyString();
|
||||
BASE_EXPORT const string16& EmptyString16();
|
||||
|
||||
// Contains the set of characters representing whitespace in the corresponding
|
||||
// encoding. Null-terminated.
|
||||
BASE_EXPORT extern const wchar_t kWhitespaceWide[];
|
||||
BASE_EXPORT extern const char16 kWhitespaceUTF16[];
|
||||
// encoding. Null-terminated. The ASCII versions are the whitespaces as defined
|
||||
// by HTML5, and don't include control characters.
|
||||
BASE_EXPORT extern const wchar_t kWhitespaceWide[]; // Includes Unicode.
|
||||
BASE_EXPORT extern const char16 kWhitespaceUTF16[]; // Includes Unicode.
|
||||
BASE_EXPORT extern const char kWhitespaceASCII[];
|
||||
BASE_EXPORT extern const char16 kWhitespaceASCIIAs16[]; // No unicode.
|
||||
|
||||
// Null-terminated string representing the UTF-8 byte order mark.
|
||||
BASE_EXPORT extern const char kUtf8ByteOrderMark[];
|
||||
@ -150,10 +173,10 @@ BASE_EXPORT extern const char kUtf8ByteOrderMark[];
|
||||
// if any characters were removed. |remove_chars| must be null-terminated.
|
||||
// NOTE: Safe to use the same variable for both |input| and |output|.
|
||||
BASE_EXPORT bool RemoveChars(const string16& input,
|
||||
const base::StringPiece16& remove_chars,
|
||||
const StringPiece16& remove_chars,
|
||||
string16* output);
|
||||
BASE_EXPORT bool RemoveChars(const std::string& input,
|
||||
const base::StringPiece& remove_chars,
|
||||
const StringPiece& remove_chars,
|
||||
std::string* output);
|
||||
|
||||
// Replaces characters in |replace_chars| from anywhere in |input| with
|
||||
@ -162,55 +185,65 @@ BASE_EXPORT bool RemoveChars(const std::string& input,
|
||||
// |replace_chars| must be null-terminated.
|
||||
// NOTE: Safe to use the same variable for both |input| and |output|.
|
||||
BASE_EXPORT bool ReplaceChars(const string16& input,
|
||||
const base::StringPiece16& replace_chars,
|
||||
const StringPiece16& replace_chars,
|
||||
const string16& replace_with,
|
||||
string16* output);
|
||||
BASE_EXPORT bool ReplaceChars(const std::string& input,
|
||||
const base::StringPiece& replace_chars,
|
||||
const StringPiece& replace_chars,
|
||||
const std::string& replace_with,
|
||||
std::string* output);
|
||||
|
||||
enum TrimPositions {
|
||||
TRIM_NONE = 0,
|
||||
TRIM_LEADING = 1 << 0,
|
||||
TRIM_TRAILING = 1 << 1,
|
||||
TRIM_ALL = TRIM_LEADING | TRIM_TRAILING,
|
||||
};
|
||||
|
||||
// Removes characters in |trim_chars| from the beginning and end of |input|.
|
||||
// |trim_chars| must be null-terminated.
|
||||
// NOTE: Safe to use the same variable for both |input| and |output|.
|
||||
// The 8-bit version only works on 8-bit characters, not UTF-8.
|
||||
//
|
||||
// It is safe to use the same variable for both |input| and |output| (this is
|
||||
// the normal usage to trim in-place).
|
||||
BASE_EXPORT bool TrimString(const string16& input,
|
||||
const base::StringPiece16& trim_chars,
|
||||
StringPiece16 trim_chars,
|
||||
string16* output);
|
||||
BASE_EXPORT bool TrimString(const std::string& input,
|
||||
const base::StringPiece& trim_chars,
|
||||
StringPiece trim_chars,
|
||||
std::string* output);
|
||||
|
||||
// StringPiece versions of the above. The returned pieces refer to the original
|
||||
// buffer.
|
||||
BASE_EXPORT StringPiece16 TrimString(StringPiece16 input,
|
||||
const StringPiece16& trim_chars,
|
||||
TrimPositions positions);
|
||||
BASE_EXPORT StringPiece TrimString(StringPiece input,
|
||||
const StringPiece& trim_chars,
|
||||
TrimPositions positions);
|
||||
|
||||
// Truncates a string to the nearest UTF-8 character that will leave
|
||||
// the string less than or equal to the specified byte size.
|
||||
BASE_EXPORT void TruncateUTF8ToByteSize(const std::string& input,
|
||||
const size_t byte_size,
|
||||
std::string* output);
|
||||
|
||||
// Trims any whitespace from either end of the input string. Returns where
|
||||
// whitespace was found.
|
||||
// The non-wide version has two functions:
|
||||
// * TrimWhitespaceASCII()
|
||||
// This function is for ASCII strings and only looks for ASCII whitespace;
|
||||
// Please choose the best one according to your usage.
|
||||
// Trims any whitespace from either end of the input string.
|
||||
//
|
||||
// The StringPiece versions return a substring referencing the input buffer.
|
||||
// The ASCII versions look only for ASCII whitespace.
|
||||
//
|
||||
// The std::string versions return where whitespace was found.
|
||||
// NOTE: Safe to use the same variable for both input and output.
|
||||
enum TrimPositions {
|
||||
TRIM_NONE = 0,
|
||||
TRIM_LEADING = 1 << 0,
|
||||
TRIM_TRAILING = 1 << 1,
|
||||
TRIM_ALL = TRIM_LEADING | TRIM_TRAILING,
|
||||
};
|
||||
BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
|
||||
TrimPositions positions,
|
||||
base::string16* output);
|
||||
string16* output);
|
||||
BASE_EXPORT StringPiece16 TrimWhitespace(StringPiece16 input,
|
||||
TrimPositions positions);
|
||||
BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
|
||||
TrimPositions positions,
|
||||
std::string* output);
|
||||
|
||||
// Deprecated. This function is only for backward compatibility and calls
|
||||
// TrimWhitespaceASCII().
|
||||
BASE_EXPORT TrimPositions TrimWhitespace(const std::string& input,
|
||||
TrimPositions positions,
|
||||
std::string* output);
|
||||
BASE_EXPORT StringPiece TrimWhitespaceASCII(StringPiece input,
|
||||
TrimPositions positions);
|
||||
|
||||
// Searches for CR or LF characters. Removes all contiguous whitespace
|
||||
// strings that contain them. This is useful when trying to deal with text
|
||||
@ -248,7 +281,7 @@ BASE_EXPORT bool ContainsOnlyChars(const StringPiece16& input,
|
||||
//
|
||||
// IsStringASCII assumes the input is likely all ASCII, and does not leave early
|
||||
// if it is not the case.
|
||||
BASE_EXPORT bool IsStringUTF8(const std::string& str);
|
||||
BASE_EXPORT bool IsStringUTF8(const StringPiece& str);
|
||||
BASE_EXPORT bool IsStringASCII(const StringPiece& str);
|
||||
BASE_EXPORT bool IsStringASCII(const StringPiece16& str);
|
||||
// A convenience adaptor for WebStrings, as they don't convert into
|
||||
@ -258,85 +291,43 @@ BASE_EXPORT bool IsStringASCII(const string16& str);
|
||||
BASE_EXPORT bool IsStringASCII(const std::wstring& str);
|
||||
#endif
|
||||
|
||||
// Converts the elements of the given string. This version uses a pointer to
|
||||
// clearly differentiate it from the non-pointer variant.
|
||||
template <class str> inline void StringToLowerASCII(str* s) {
|
||||
for (typename str::iterator i = s->begin(); i != s->end(); ++i)
|
||||
*i = ToLowerASCII(*i);
|
||||
}
|
||||
// Compare the lower-case form of the given string against the given
|
||||
// previously-lower-cased ASCII string (typically a constant).
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece str,
|
||||
StringPiece lowecase_ascii);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece16 str,
|
||||
StringPiece lowecase_ascii);
|
||||
|
||||
template <class str> inline str StringToLowerASCII(const str& s) {
|
||||
// for std::string and std::wstring
|
||||
str output(s);
|
||||
StringToLowerASCII(&output);
|
||||
return output;
|
||||
}
|
||||
// Performs a case-sensitive string compare of the given 16-bit string against
|
||||
// the given 8-bit ASCII string (typically a constant). The behavior is
|
||||
// undefined if the |ascii| string is not ASCII.
|
||||
BASE_EXPORT bool EqualsASCII(StringPiece16 str, StringPiece ascii);
|
||||
|
||||
} // namespace base
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/strings/string_util_win.h"
|
||||
#elif defined(OS_POSIX)
|
||||
#include "base/strings/string_util_posix.h"
|
||||
#else
|
||||
#error Define string operations appropriately for your platform
|
||||
#endif
|
||||
|
||||
// Converts the elements of the given string. This version uses a pointer to
|
||||
// clearly differentiate it from the non-pointer variant.
|
||||
template <class str> inline void StringToUpperASCII(str* s) {
|
||||
for (typename str::iterator i = s->begin(); i != s->end(); ++i)
|
||||
*i = base::ToUpperASCII(*i);
|
||||
}
|
||||
|
||||
template <class str> inline str StringToUpperASCII(const str& s) {
|
||||
// for std::string and std::wstring
|
||||
str output(s);
|
||||
StringToUpperASCII(&output);
|
||||
return output;
|
||||
}
|
||||
|
||||
// Compare the lower-case form of the given string against the given ASCII
|
||||
// string. This is useful for doing checking if an input string matches some
|
||||
// token, and it is optimized to avoid intermediate string copies. This API is
|
||||
// borrowed from the equivalent APIs in Mozilla.
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const std::string& a, const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const base::string16& a, const char* b);
|
||||
|
||||
// Same thing, but with string iterators instead.
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
|
||||
std::string::const_iterator a_end,
|
||||
const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(base::string16::const_iterator a_begin,
|
||||
base::string16::const_iterator a_end,
|
||||
const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
|
||||
const char* a_end,
|
||||
const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const base::char16* a_begin,
|
||||
const base::char16* a_end,
|
||||
const char* b);
|
||||
|
||||
// Performs a case-sensitive string compare. The behavior is undefined if both
|
||||
// strings are not ASCII.
|
||||
BASE_EXPORT bool EqualsASCII(const base::string16& a, const base::StringPiece& b);
|
||||
|
||||
// Returns true if str starts with search, or false otherwise.
|
||||
BASE_EXPORT bool StartsWithASCII(const std::string& str,
|
||||
const std::string& search,
|
||||
bool case_sensitive);
|
||||
BASE_EXPORT bool StartsWith(const base::string16& str,
|
||||
const base::string16& search,
|
||||
bool case_sensitive);
|
||||
|
||||
// Returns true if str ends with search, or false otherwise.
|
||||
BASE_EXPORT bool EndsWith(const std::string& str,
|
||||
const std::string& search,
|
||||
bool case_sensitive);
|
||||
BASE_EXPORT bool EndsWith(const base::string16& str,
|
||||
const base::string16& search,
|
||||
bool case_sensitive);
|
||||
// Indicates case sensitivity of comparisons. Only ASCII case insensitivity
|
||||
// is supported. Full Unicode case-insensitive conversions would need to go in
|
||||
// base/i18n so it can use ICU.
|
||||
//
|
||||
// If you need to do Unicode-aware case-insensitive StartsWith/EndsWith, it's
|
||||
// best to call base::i18n::ToLower() or base::i18n::FoldCase() (see
|
||||
// base/i18n/case_conversion.h for usage advice) on the arguments, and then use
|
||||
// the results to a case-sensitive comparison.
|
||||
enum class CompareCase {
|
||||
SENSITIVE,
|
||||
INSENSITIVE_ASCII,
|
||||
};
|
||||
|
||||
BASE_EXPORT bool StartsWith(StringPiece str,
|
||||
StringPiece search_for,
|
||||
CompareCase case_sensitivity);
|
||||
BASE_EXPORT bool StartsWith(StringPiece16 str,
|
||||
StringPiece16 search_for,
|
||||
CompareCase case_sensitivity);
|
||||
BASE_EXPORT bool EndsWith(StringPiece str,
|
||||
StringPiece search_for,
|
||||
CompareCase case_sensitivity);
|
||||
BASE_EXPORT bool EndsWith(StringPiece16 str,
|
||||
StringPiece16 search_for,
|
||||
CompareCase case_sensitivity);
|
||||
|
||||
// Determines the type of ASCII character, independent of locale (the C
|
||||
// library versions will change based on locale).
|
||||
@ -360,41 +351,34 @@ inline bool IsHexDigit(Char c) {
|
||||
(c >= 'a' && c <= 'f');
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline char HexDigitToInt(Char c) {
|
||||
DCHECK(IsHexDigit(c));
|
||||
if (c >= '0' && c <= '9')
|
||||
return static_cast<char>(c - '0');
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return static_cast<char>(c - 'A' + 10);
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return static_cast<char>(c - 'a' + 10);
|
||||
return 0;
|
||||
}
|
||||
// Returns the integer corresponding to the given hex character. For example:
|
||||
// '4' -> 4
|
||||
// 'a' -> 10
|
||||
// 'B' -> 11
|
||||
// Assumes the input is a valid hex character. DCHECKs in debug builds if not.
|
||||
BASE_EXPORT char HexDigitToInt(wchar_t c);
|
||||
|
||||
// Returns true if it's a whitespace character.
|
||||
inline bool IsWhitespace(wchar_t c) {
|
||||
return wcschr(base::kWhitespaceWide, c) != NULL;
|
||||
}
|
||||
// Returns true if it's a Unicode whitespace character.
|
||||
BASE_EXPORT bool IsUnicodeWhitespace(wchar_t c);
|
||||
|
||||
// Return a byte string in human-readable format with a unit suffix. Not
|
||||
// appropriate for use in any UI; use of FormatBytes and friends in ui/base is
|
||||
// highly recommended instead. TODO(avi): Figure out how to get callers to use
|
||||
// FormatBytes instead; remove this.
|
||||
BASE_EXPORT base::string16 FormatBytesUnlocalized(int64 bytes);
|
||||
BASE_EXPORT string16 FormatBytesUnlocalized(int64_t bytes);
|
||||
|
||||
// Starting at |start_offset| (usually 0), replace the first instance of
|
||||
// |find_this| with |replace_with|.
|
||||
BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
|
||||
base::string16* str,
|
||||
size_t start_offset,
|
||||
const base::string16& find_this,
|
||||
const base::string16& replace_with);
|
||||
StringPiece16 find_this,
|
||||
StringPiece16 replace_with);
|
||||
BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
|
||||
std::string* str,
|
||||
size_t start_offset,
|
||||
const std::string& find_this,
|
||||
const std::string& replace_with);
|
||||
StringPiece find_this,
|
||||
StringPiece replace_with);
|
||||
|
||||
// Starting at |start_offset| (usually 0), look through |str| and replace all
|
||||
// instances of |find_this| with |replace_with|.
|
||||
@ -403,14 +387,15 @@ BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
|
||||
// characters, for example:
|
||||
// std::replace(str.begin(), str.end(), 'a', 'b');
|
||||
BASE_EXPORT void ReplaceSubstringsAfterOffset(
|
||||
base::string16* str,
|
||||
string16* str,
|
||||
size_t start_offset,
|
||||
const base::string16& find_this,
|
||||
const base::string16& replace_with);
|
||||
BASE_EXPORT void ReplaceSubstringsAfterOffset(std::string* str,
|
||||
StringPiece16 find_this,
|
||||
StringPiece16 replace_with);
|
||||
BASE_EXPORT void ReplaceSubstringsAfterOffset(
|
||||
std::string* str,
|
||||
size_t start_offset,
|
||||
const std::string& find_this,
|
||||
const std::string& replace_with);
|
||||
StringPiece find_this,
|
||||
StringPiece replace_with);
|
||||
|
||||
// Reserves enough memory in |str| to accommodate |length_with_null| characters,
|
||||
// sets the size of |str| to |length_with_null - 1| characters, and returns a
|
||||
@ -432,101 +417,45 @@ BASE_EXPORT void ReplaceSubstringsAfterOffset(std::string* str,
|
||||
// of the string, and not doing that will mean people who access |str| rather
|
||||
// than str.c_str() will get back a string of whatever size |str| had on entry
|
||||
// to this function (probably 0).
|
||||
template <class string_type>
|
||||
inline typename string_type::value_type* WriteInto(string_type* str,
|
||||
size_t length_with_null) {
|
||||
DCHECK_GT(length_with_null, 1u);
|
||||
str->reserve(length_with_null);
|
||||
str->resize(length_with_null - 1);
|
||||
return &((*str)[0]);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Splits a string into its fields delimited by any of the characters in
|
||||
// |delimiters|. Each field is added to the |tokens| vector. Returns the
|
||||
// number of tokens found.
|
||||
BASE_EXPORT size_t Tokenize(const base::string16& str,
|
||||
const base::string16& delimiters,
|
||||
std::vector<base::string16>* tokens);
|
||||
BASE_EXPORT size_t Tokenize(const std::string& str,
|
||||
const std::string& delimiters,
|
||||
std::vector<std::string>* tokens);
|
||||
BASE_EXPORT size_t Tokenize(const base::StringPiece& str,
|
||||
const base::StringPiece& delimiters,
|
||||
std::vector<base::StringPiece>* tokens);
|
||||
BASE_EXPORT char* WriteInto(std::string* str, size_t length_with_null);
|
||||
BASE_EXPORT char16* WriteInto(string16* str, size_t length_with_null);
|
||||
#ifndef OS_WIN
|
||||
BASE_EXPORT wchar_t* WriteInto(std::wstring* str, size_t length_with_null);
|
||||
#endif
|
||||
|
||||
// Does the opposite of SplitString().
|
||||
BASE_EXPORT base::string16 JoinString(const std::vector<base::string16>& parts,
|
||||
base::char16 s);
|
||||
BASE_EXPORT std::string JoinString(
|
||||
const std::vector<std::string>& parts, char s);
|
||||
|
||||
// Join |parts| using |separator|.
|
||||
BASE_EXPORT std::string JoinString(
|
||||
const std::vector<std::string>& parts,
|
||||
const std::string& separator);
|
||||
BASE_EXPORT base::string16 JoinString(
|
||||
const std::vector<base::string16>& parts,
|
||||
const base::string16& separator);
|
||||
BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts,
|
||||
StringPiece separator);
|
||||
BASE_EXPORT string16 JoinString(const std::vector<string16>& parts,
|
||||
StringPiece16 separator);
|
||||
|
||||
// Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively.
|
||||
// Additionally, any number of consecutive '$' characters is replaced by that
|
||||
// number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be
|
||||
// NULL. This only allows you to use up to nine replacements.
|
||||
BASE_EXPORT base::string16 ReplaceStringPlaceholders(
|
||||
const base::string16& format_string,
|
||||
const std::vector<base::string16>& subst,
|
||||
BASE_EXPORT string16 ReplaceStringPlaceholders(
|
||||
const string16& format_string,
|
||||
const std::vector<string16>& subst,
|
||||
std::vector<size_t>* offsets);
|
||||
|
||||
BASE_EXPORT std::string ReplaceStringPlaceholders(
|
||||
const base::StringPiece& format_string,
|
||||
const StringPiece& format_string,
|
||||
const std::vector<std::string>& subst,
|
||||
std::vector<size_t>* offsets);
|
||||
|
||||
// Single-string shortcut for ReplaceStringHolders. |offset| may be NULL.
|
||||
BASE_EXPORT base::string16 ReplaceStringPlaceholders(
|
||||
const base::string16& format_string,
|
||||
const base::string16& a,
|
||||
BASE_EXPORT string16 ReplaceStringPlaceholders(const string16& format_string,
|
||||
const string16& a,
|
||||
size_t* offset);
|
||||
|
||||
// Returns true if the string passed in matches the pattern. The pattern
|
||||
// string can contain wildcards like * and ?
|
||||
// The backslash character (\) is an escape character for * and ?
|
||||
// We limit the patterns to having a max of 16 * or ? characters.
|
||||
// ? matches 0 or 1 character, while * matches 0 or more characters.
|
||||
BASE_EXPORT bool MatchPattern(const base::StringPiece& string,
|
||||
const base::StringPiece& pattern);
|
||||
BASE_EXPORT bool MatchPattern(const base::string16& string,
|
||||
const base::string16& pattern);
|
||||
} // namespace base
|
||||
|
||||
// Hack to convert any char-like type to its unsigned counterpart.
|
||||
// For example, it will convert char, signed char and unsigned char to unsigned
|
||||
// char.
|
||||
template<typename T>
|
||||
struct ToUnsigned {
|
||||
typedef T Unsigned;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ToUnsigned<char> {
|
||||
typedef unsigned char Unsigned;
|
||||
};
|
||||
template<>
|
||||
struct ToUnsigned<signed char> {
|
||||
typedef unsigned char Unsigned;
|
||||
};
|
||||
template<>
|
||||
struct ToUnsigned<wchar_t> {
|
||||
#if defined(WCHAR_T_IS_UTF16)
|
||||
typedef unsigned short Unsigned;
|
||||
#elif defined(WCHAR_T_IS_UTF32)
|
||||
typedef uint32 Unsigned;
|
||||
#if defined(OS_WIN)
|
||||
#include "base/strings/string_util_win.h"
|
||||
#elif defined(OS_POSIX)
|
||||
#include "base/strings/string_util_posix.h"
|
||||
#else
|
||||
#error Define string operations appropriately for your platform
|
||||
#endif
|
||||
};
|
||||
template<>
|
||||
struct ToUnsigned<short> {
|
||||
typedef unsigned short Unsigned;
|
||||
};
|
||||
|
||||
#endif // BASE_STRINGS_STRING_UTIL_H_
|
||||
|
@ -52,6 +52,16 @@ const char kWhitespaceASCII[] = {
|
||||
0
|
||||
};
|
||||
|
||||
const char16 kWhitespaceASCIIAs16[] = {
|
||||
0x09, // CHARACTER TABULATION
|
||||
0x0A, // LINE FEED (LF)
|
||||
0x0B, // LINE TABULATION
|
||||
0x0C, // FORM FEED (FF)
|
||||
0x0D, // CARRIAGE RETURN (CR)
|
||||
0x20, // SPACE
|
||||
0
|
||||
};
|
||||
|
||||
const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
|
||||
|
||||
} // namespace base
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define BASE_STRINGS_STRING_UTIL_POSIX_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
@ -20,27 +21,11 @@ inline char* strdup(const char* str) {
|
||||
return ::strdup(str);
|
||||
}
|
||||
|
||||
inline int strcasecmp(const char* string1, const char* string2) {
|
||||
return ::strcasecmp(string1, string2);
|
||||
}
|
||||
|
||||
inline int strncasecmp(const char* string1, const char* string2, size_t count) {
|
||||
return ::strncasecmp(string1, string2, count);
|
||||
}
|
||||
|
||||
inline int vsnprintf(char* buffer, size_t size,
|
||||
const char* format, va_list arguments) {
|
||||
return ::vsnprintf(buffer, size, format, arguments);
|
||||
}
|
||||
|
||||
inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
|
||||
#if defined(WCHAR_T_IS_UTF16)
|
||||
return ::wcsncmp(s1, s2, count);
|
||||
#elif defined(WCHAR_T_IS_UTF32)
|
||||
return c16memcmp(s1, s2, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int vswprintf(wchar_t* buffer, size_t size,
|
||||
const wchar_t* format, va_list arguments) {
|
||||
DCHECK(IsWprintfFormatPortable(format));
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define BASE_STRINGS_STRING_UTIL_WIN_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
@ -20,26 +21,11 @@ inline char* strdup(const char* str) {
|
||||
return _strdup(str);
|
||||
}
|
||||
|
||||
inline int strcasecmp(const char* s1, const char* s2) {
|
||||
return _stricmp(s1, s2);
|
||||
}
|
||||
|
||||
inline int strncasecmp(const char* s1, const char* s2, size_t count) {
|
||||
return _strnicmp(s1, s2, count);
|
||||
}
|
||||
|
||||
inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
|
||||
return ::wcsncmp(s1, s2, count);
|
||||
}
|
||||
|
||||
inline int vsnprintf(char* buffer, size_t size,
|
||||
const char* format, va_list arguments) {
|
||||
int length = _vsprintf_p(buffer, size, format, arguments);
|
||||
if (length < 0) {
|
||||
if (size > 0)
|
||||
buffer[0] = 0;
|
||||
return _vscprintf_p(format, arguments);
|
||||
}
|
||||
int length = vsnprintf_s(buffer, size, size - 1, format, arguments);
|
||||
if (length < 0)
|
||||
return _vscprintf(format, arguments);
|
||||
return length;
|
||||
}
|
||||
|
||||
@ -47,12 +33,9 @@ inline int vswprintf(wchar_t* buffer, size_t size,
|
||||
const wchar_t* format, va_list arguments) {
|
||||
DCHECK(IsWprintfFormatPortable(format));
|
||||
|
||||
int length = _vswprintf_p(buffer, size, format, arguments);
|
||||
if (length < 0) {
|
||||
if (size > 0)
|
||||
buffer[0] = 0;
|
||||
return _vscwprintf_p(format, arguments);
|
||||
}
|
||||
int length = _vsnwprintf_s(buffer, size, size - 1, format, arguments);
|
||||
if (length < 0)
|
||||
return _vscwprintf(format, arguments);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -5,10 +5,15 @@
|
||||
#include "base/strings/stringprintf.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/scoped_clear_errno.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -27,7 +32,7 @@ inline int vsnprintfT(char* buffer,
|
||||
return base::vsnprintf(buffer, buf_size, format, argptr);
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
#if defined(OS_WIN)
|
||||
inline int vsnprintfT(wchar_t* buffer,
|
||||
size_t buf_size,
|
||||
const wchar_t* format,
|
||||
@ -48,7 +53,7 @@ static void StringAppendVT(StringType* dst,
|
||||
typename StringType::value_type stack_buf[1024];
|
||||
|
||||
va_list ap_copy;
|
||||
GG_VA_COPY(ap_copy, ap);
|
||||
va_copy(ap_copy, ap);
|
||||
|
||||
#if !defined(OS_WIN)
|
||||
ScopedClearErrno clear_errno;
|
||||
@ -94,7 +99,7 @@ static void StringAppendVT(StringType* dst,
|
||||
|
||||
// NOTE: You can only use a va_list once. Since we're in a while loop, we
|
||||
// need to make a new copy each time so we don't use up the original.
|
||||
GG_VA_COPY(ap_copy, ap);
|
||||
va_copy(ap_copy, ap);
|
||||
result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
@ -117,7 +122,7 @@ std::string StringPrintf(const char* format, ...) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
#if defined(OS_WIN)
|
||||
std::wstring StringPrintf(const wchar_t* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
@ -143,7 +148,7 @@ const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
|
||||
return *dst;
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
#if defined(OS_WIN)
|
||||
const std::wstring& SStringPrintf(std::wstring* dst,
|
||||
const wchar_t* format, ...) {
|
||||
va_list ap;
|
||||
@ -162,7 +167,7 @@ void StringAppendF(std::string* dst, const char* format, ...) {
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
#if defined(OS_WIN)
|
||||
void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
@ -175,7 +180,7 @@ void StringAppendV(std::string* dst, const char* format, va_list ap) {
|
||||
StringAppendVT(dst, format, ap);
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
#if defined(OS_WIN)
|
||||
void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
|
||||
StringAppendVT(dst, format, ap);
|
||||
}
|
||||
|
@ -11,16 +11,18 @@
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Return a C++ string given printf-like input.
|
||||
BASE_EXPORT std::string StringPrintf(const char* format, ...)
|
||||
BASE_EXPORT std::string StringPrintf(_Printf_format_string_ const char* format,
|
||||
...)
|
||||
PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
|
||||
// OS_ANDROID's libc does not support wchar_t, so several overloads are omitted.
|
||||
#if !defined(OS_ANDROID)
|
||||
BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
|
||||
WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
|
||||
#if defined(OS_WIN)
|
||||
BASE_EXPORT std::wstring StringPrintf(
|
||||
_Printf_format_string_ const wchar_t* format,
|
||||
...) WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
|
||||
#endif
|
||||
|
||||
// Return a C++ string given vprintf-like input.
|
||||
@ -28,30 +30,32 @@ BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
|
||||
PRINTF_FORMAT(1, 0) WARN_UNUSED_RESULT;
|
||||
|
||||
// Store result into a supplied string and return it.
|
||||
BASE_EXPORT const std::string& SStringPrintf(std::string* dst,
|
||||
const char* format, ...)
|
||||
PRINTF_FORMAT(2, 3);
|
||||
#if !defined(OS_ANDROID)
|
||||
BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
|
||||
const wchar_t* format, ...)
|
||||
WPRINTF_FORMAT(2, 3);
|
||||
BASE_EXPORT const std::string& SStringPrintf(
|
||||
std::string* dst,
|
||||
_Printf_format_string_ const char* format,
|
||||
...) PRINTF_FORMAT(2, 3);
|
||||
#if defined(OS_WIN)
|
||||
BASE_EXPORT const std::wstring& SStringPrintf(
|
||||
std::wstring* dst,
|
||||
_Printf_format_string_ const wchar_t* format,
|
||||
...) WPRINTF_FORMAT(2, 3);
|
||||
#endif
|
||||
|
||||
// Append result to a supplied string.
|
||||
BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
|
||||
PRINTF_FORMAT(2, 3);
|
||||
#if !defined(OS_ANDROID)
|
||||
// TODO(evanm): this is only used in a few places in the code;
|
||||
// replace with string16 version.
|
||||
BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
|
||||
WPRINTF_FORMAT(2, 3);
|
||||
BASE_EXPORT void StringAppendF(std::string* dst,
|
||||
_Printf_format_string_ const char* format,
|
||||
...) PRINTF_FORMAT(2, 3);
|
||||
#if defined(OS_WIN)
|
||||
BASE_EXPORT void StringAppendF(std::wstring* dst,
|
||||
_Printf_format_string_ const wchar_t* format,
|
||||
...) WPRINTF_FORMAT(2, 3);
|
||||
#endif
|
||||
|
||||
// Lower-level routine that takes a va_list and appends to a specified
|
||||
// string. All other routines are just convenience wrappers around it.
|
||||
BASE_EXPORT void StringAppendV(std::string* dst, const char* format, va_list ap)
|
||||
PRINTF_FORMAT(2, 0);
|
||||
#if !defined(OS_ANDROID)
|
||||
#if defined(OS_WIN)
|
||||
BASE_EXPORT void StringAppendV(std::wstring* dst,
|
||||
const wchar_t* format, va_list ap)
|
||||
WPRINTF_FORMAT(2, 0);
|
||||
|
@ -11,15 +11,15 @@ namespace base {
|
||||
// ReadUnicodeCharacter --------------------------------------------------------
|
||||
|
||||
bool ReadUnicodeCharacter(const char* src,
|
||||
int32 src_len,
|
||||
int32* char_index,
|
||||
uint32* code_point_out) {
|
||||
int32_t src_len,
|
||||
int32_t* char_index,
|
||||
uint32_t* code_point_out) {
|
||||
// U8_NEXT expects to be able to use -1 to signal an error, so we must
|
||||
// use a signed type for code_point. But this function returns false
|
||||
// on error anyway, so code_point_out is unsigned.
|
||||
int32 code_point;
|
||||
int32_t code_point;
|
||||
CBU8_NEXT(src, *char_index, src_len, code_point);
|
||||
*code_point_out = static_cast<uint32>(code_point);
|
||||
*code_point_out = static_cast<uint32_t>(code_point);
|
||||
|
||||
// The ICU macro above moves to the next char, we want to point to the last
|
||||
// char consumed.
|
||||
@ -30,9 +30,9 @@ bool ReadUnicodeCharacter(const char* src,
|
||||
}
|
||||
|
||||
bool ReadUnicodeCharacter(const char16* src,
|
||||
int32 src_len,
|
||||
int32* char_index,
|
||||
uint32* code_point) {
|
||||
int32_t src_len,
|
||||
int32_t* char_index,
|
||||
uint32_t* code_point) {
|
||||
if (CBU16_IS_SURROGATE(src[*char_index])) {
|
||||
if (!CBU16_IS_SURROGATE_LEAD(src[*char_index]) ||
|
||||
*char_index + 1 >= src_len ||
|
||||
@ -55,9 +55,9 @@ bool ReadUnicodeCharacter(const char16* src,
|
||||
|
||||
#if defined(WCHAR_T_IS_UTF32)
|
||||
bool ReadUnicodeCharacter(const wchar_t* src,
|
||||
int32 src_len,
|
||||
int32* char_index,
|
||||
uint32* code_point) {
|
||||
int32_t src_len,
|
||||
int32_t* char_index,
|
||||
uint32_t* code_point) {
|
||||
// Conversion is easy since the source is 32-bit.
|
||||
*code_point = src[*char_index];
|
||||
|
||||
@ -68,7 +68,7 @@ bool ReadUnicodeCharacter(const wchar_t* src,
|
||||
|
||||
// WriteUnicodeCharacter -------------------------------------------------------
|
||||
|
||||
size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) {
|
||||
size_t WriteUnicodeCharacter(uint32_t code_point, std::string* output) {
|
||||
if (code_point <= 0x7f) {
|
||||
// Fast path the common case of one byte.
|
||||
output->push_back(static_cast<char>(code_point));
|
||||
@ -89,7 +89,7 @@ size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) {
|
||||
return char_offset - original_char_offset;
|
||||
}
|
||||
|
||||
size_t WriteUnicodeCharacter(uint32 code_point, string16* output) {
|
||||
size_t WriteUnicodeCharacter(uint32_t code_point, string16* output) {
|
||||
if (CBU16_LENGTH(code_point) == 1) {
|
||||
// Thie code point is in the Basic Multilingual Plane (BMP).
|
||||
output->push_back(static_cast<char16>(code_point));
|
||||
|
@ -7,12 +7,15 @@
|
||||
|
||||
// This should only be used by the various UTF string conversion files.
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
inline bool IsValidCodepoint(uint32 code_point) {
|
||||
inline bool IsValidCodepoint(uint32_t code_point) {
|
||||
// Excludes the surrogate code points ([0xD800, 0xDFFF]) and
|
||||
// codepoints larger than 0x10FFFF (the highest codepoint allowed).
|
||||
// Non-characters and unassigned codepoints are allowed.
|
||||
@ -20,7 +23,7 @@ inline bool IsValidCodepoint(uint32 code_point) {
|
||||
(code_point >= 0xE000u && code_point <= 0x10FFFFu);
|
||||
}
|
||||
|
||||
inline bool IsValidCharacter(uint32 code_point) {
|
||||
inline bool IsValidCharacter(uint32_t code_point) {
|
||||
// Excludes non-characters (U+FDD0..U+FDEF, and all codepoints ending in
|
||||
// 0xFFFE or 0xFFFF) from the set of valid code points.
|
||||
return code_point < 0xD800u || (code_point >= 0xE000u &&
|
||||
@ -38,40 +41,39 @@ inline bool IsValidCharacter(uint32 code_point) {
|
||||
//
|
||||
// Returns true on success. On false, |*code_point| will be invalid.
|
||||
BASE_EXPORT bool ReadUnicodeCharacter(const char* src,
|
||||
int32 src_len,
|
||||
int32* char_index,
|
||||
uint32* code_point_out);
|
||||
int32_t src_len,
|
||||
int32_t* char_index,
|
||||
uint32_t* code_point_out);
|
||||
|
||||
// Reads a UTF-16 character. The usage is the same as the 8-bit version above.
|
||||
BASE_EXPORT bool ReadUnicodeCharacter(const char16* src,
|
||||
int32 src_len,
|
||||
int32* char_index,
|
||||
uint32* code_point);
|
||||
int32_t src_len,
|
||||
int32_t* char_index,
|
||||
uint32_t* code_point);
|
||||
|
||||
#if defined(WCHAR_T_IS_UTF32)
|
||||
// Reads UTF-32 character. The usage is the same as the 8-bit version above.
|
||||
BASE_EXPORT bool ReadUnicodeCharacter(const wchar_t* src,
|
||||
int32 src_len,
|
||||
int32* char_index,
|
||||
uint32* code_point);
|
||||
int32_t src_len,
|
||||
int32_t* char_index,
|
||||
uint32_t* code_point);
|
||||
#endif // defined(WCHAR_T_IS_UTF32)
|
||||
|
||||
// WriteUnicodeCharacter -------------------------------------------------------
|
||||
|
||||
// Appends a UTF-8 character to the given 8-bit string. Returns the number of
|
||||
// bytes written.
|
||||
// TODO(brettw) Bug 79631: This function should not be exposed.
|
||||
BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point,
|
||||
BASE_EXPORT size_t WriteUnicodeCharacter(uint32_t code_point,
|
||||
std::string* output);
|
||||
|
||||
// Appends the given code point as a UTF-16 character to the given 16-bit
|
||||
// string. Returns the number of 16-bit values written.
|
||||
BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point, string16* output);
|
||||
BASE_EXPORT size_t WriteUnicodeCharacter(uint32_t code_point, string16* output);
|
||||
|
||||
#if defined(WCHAR_T_IS_UTF32)
|
||||
// Appends the given UTF-32 character to the given 32-bit string. Returns the
|
||||
// number of 32-bit values written.
|
||||
inline size_t WriteUnicodeCharacter(uint32 code_point, std::wstring* output) {
|
||||
inline size_t WriteUnicodeCharacter(uint32_t code_point, std::wstring* output) {
|
||||
// This is the easy case, just append the character.
|
||||
output->push_back(code_point);
|
||||
return 1;
|
||||
|
@ -4,9 +4,12 @@
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversion_utils.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -24,9 +27,9 @@ bool ConvertUnicode(const SRC_CHAR* src,
|
||||
DEST_STRING* output) {
|
||||
// ICU requires 32-bit numbers.
|
||||
bool success = true;
|
||||
int32 src_len32 = static_cast<int32>(src_len);
|
||||
for (int32 i = 0; i < src_len32; i++) {
|
||||
uint32 code_point;
|
||||
int32_t src_len32 = static_cast<int32_t>(src_len);
|
||||
for (int32_t i = 0; i < src_len32; i++) {
|
||||
uint32_t code_point;
|
||||
if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
|
||||
WriteUnicodeCharacter(code_point, output);
|
||||
} else {
|
||||
@ -73,7 +76,7 @@ bool UTF8ToWide(const char* src, size_t src_len, std::wstring* output) {
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring UTF8ToWide(const StringPiece& utf8) {
|
||||
std::wstring UTF8ToWide(StringPiece utf8) {
|
||||
if (IsStringASCII(utf8)) {
|
||||
return std::wstring(utf8.begin(), utf8.end());
|
||||
}
|
||||
@ -153,7 +156,7 @@ bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
|
||||
}
|
||||
}
|
||||
|
||||
string16 UTF8ToUTF16(const StringPiece& utf8) {
|
||||
string16 UTF8ToUTF16(StringPiece utf8) {
|
||||
if (IsStringASCII(utf8)) {
|
||||
return string16(utf8.begin(), utf8.end());
|
||||
}
|
||||
@ -176,7 +179,7 @@ bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string UTF16ToUTF8(const string16& utf16) {
|
||||
std::string UTF16ToUTF8(StringPiece16 utf16) {
|
||||
if (IsStringASCII(utf16)) {
|
||||
return std::string(utf16.begin(), utf16.end());
|
||||
}
|
||||
@ -195,7 +198,7 @@ bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
|
||||
return UTF8ToWide(src, src_len, output);
|
||||
}
|
||||
|
||||
string16 UTF8ToUTF16(const StringPiece& utf8) {
|
||||
string16 UTF8ToUTF16(StringPiece utf8) {
|
||||
return UTF8ToWide(utf8);
|
||||
}
|
||||
|
||||
@ -203,23 +206,24 @@ bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
|
||||
return WideToUTF8(src, src_len, output);
|
||||
}
|
||||
|
||||
std::string UTF16ToUTF8(const string16& utf16) {
|
||||
return WideToUTF8(utf16);
|
||||
std::string UTF16ToUTF8(StringPiece16 utf16) {
|
||||
if (IsStringASCII(utf16))
|
||||
return std::string(utf16.data(), utf16.data() + utf16.length());
|
||||
|
||||
std::string ret;
|
||||
PrepareForUTF8Output(utf16.data(), utf16.length(), &ret);
|
||||
ConvertUnicode(utf16.data(), utf16.length(), &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::wstring ASCIIToWide(const StringPiece& ascii) {
|
||||
DCHECK(IsStringASCII(ascii)) << ascii;
|
||||
return std::wstring(ascii.begin(), ascii.end());
|
||||
}
|
||||
|
||||
string16 ASCIIToUTF16(const StringPiece& ascii) {
|
||||
string16 ASCIIToUTF16(StringPiece ascii) {
|
||||
DCHECK(IsStringASCII(ascii)) << ascii;
|
||||
return string16(ascii.begin(), ascii.end());
|
||||
}
|
||||
|
||||
std::string UTF16ToASCII(const string16& utf16) {
|
||||
std::string UTF16ToASCII(StringPiece16 utf16) {
|
||||
DCHECK(IsStringASCII(utf16)) << UTF16ToUTF8(utf16);
|
||||
return std::string(utf16.begin(), utf16.end());
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
|
||||
#define BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
@ -24,7 +26,7 @@ BASE_EXPORT bool WideToUTF8(const wchar_t* src, size_t src_len,
|
||||
BASE_EXPORT std::string WideToUTF8(const std::wstring& wide);
|
||||
BASE_EXPORT bool UTF8ToWide(const char* src, size_t src_len,
|
||||
std::wstring* output);
|
||||
BASE_EXPORT std::wstring UTF8ToWide(const StringPiece& utf8);
|
||||
BASE_EXPORT std::wstring UTF8ToWide(StringPiece utf8);
|
||||
|
||||
BASE_EXPORT bool WideToUTF16(const wchar_t* src, size_t src_len,
|
||||
string16* output);
|
||||
@ -34,19 +36,18 @@ BASE_EXPORT bool UTF16ToWide(const char16* src, size_t src_len,
|
||||
BASE_EXPORT std::wstring UTF16ToWide(const string16& utf16);
|
||||
|
||||
BASE_EXPORT bool UTF8ToUTF16(const char* src, size_t src_len, string16* output);
|
||||
BASE_EXPORT string16 UTF8ToUTF16(const StringPiece& utf8);
|
||||
BASE_EXPORT string16 UTF8ToUTF16(StringPiece utf8);
|
||||
BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
|
||||
std::string* output);
|
||||
BASE_EXPORT std::string UTF16ToUTF8(const string16& utf16);
|
||||
BASE_EXPORT std::string UTF16ToUTF8(StringPiece16 utf16);
|
||||
|
||||
// These convert an ASCII string, typically a hardcoded constant, to a
|
||||
// UTF16/Wide string.
|
||||
BASE_EXPORT std::wstring ASCIIToWide(const StringPiece& ascii);
|
||||
BASE_EXPORT string16 ASCIIToUTF16(const StringPiece& ascii);
|
||||
// This converts an ASCII string, typically a hardcoded constant, to a UTF16
|
||||
// string.
|
||||
BASE_EXPORT string16 ASCIIToUTF16(StringPiece ascii);
|
||||
|
||||
// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
|
||||
// beforehand.
|
||||
BASE_EXPORT std::string UTF16ToASCII(const string16& utf16);
|
||||
BASE_EXPORT std::string UTF16ToASCII(StringPiece16 utf16);
|
||||
|
||||
} // namespace base
|
||||
|
||||
|
@ -65,16 +65,16 @@
|
||||
#ifndef BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
|
||||
#define BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class ConditionVarImpl;
|
||||
@ -104,7 +104,7 @@ class BASE_EXPORT ConditionVariable {
|
||||
#elif defined(OS_POSIX)
|
||||
pthread_cond_t condition_;
|
||||
pthread_mutex_t* user_mutex_;
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
#if DCHECK_IS_ON()
|
||||
base::Lock* user_lock_; // Needed to adjust shadow lock state on wait.
|
||||
#endif
|
||||
|
||||
|
@ -5,18 +5,19 @@
|
||||
#include "base/synchronization/condition_variable.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
ConditionVariable::ConditionVariable(Lock* user_lock)
|
||||
: user_mutex_(user_lock->lock_.native_handle())
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
#if DCHECK_IS_ON()
|
||||
, user_lock_(user_lock)
|
||||
#endif
|
||||
{
|
||||
@ -42,31 +43,45 @@ ConditionVariable::ConditionVariable(Lock* user_lock)
|
||||
}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
#if defined(OS_MACOSX)
|
||||
// This hack is necessary to avoid a fatal pthreads subsystem bug in the
|
||||
// Darwin kernel. http://crbug.com/517681.
|
||||
{
|
||||
base::Lock lock;
|
||||
base::AutoLock l(lock);
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1;
|
||||
pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(),
|
||||
&ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
int rv = pthread_cond_destroy(&condition_);
|
||||
DCHECK_EQ(0, rv);
|
||||
}
|
||||
|
||||
void ConditionVariable::Wait() {
|
||||
base::ThreadRestrictions::AssertWaitAllowed();
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
#if DCHECK_IS_ON()
|
||||
user_lock_->CheckHeldAndUnmark();
|
||||
#endif
|
||||
int rv = pthread_cond_wait(&condition_, user_mutex_);
|
||||
DCHECK_EQ(0, rv);
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
#if DCHECK_IS_ON()
|
||||
user_lock_->CheckUnheldAndMark();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariable::TimedWait(const TimeDelta& max_time) {
|
||||
base::ThreadRestrictions::AssertWaitAllowed();
|
||||
int64 usecs = max_time.InMicroseconds();
|
||||
int64_t usecs = max_time.InMicroseconds();
|
||||
struct timespec relative_time;
|
||||
relative_time.tv_sec = usecs / Time::kMicrosecondsPerSecond;
|
||||
relative_time.tv_nsec =
|
||||
(usecs % Time::kMicrosecondsPerSecond) * Time::kNanosecondsPerMicrosecond;
|
||||
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
#if DCHECK_IS_ON()
|
||||
user_lock_->CheckHeldAndUnmark();
|
||||
#endif
|
||||
|
||||
@ -104,7 +119,7 @@ void ConditionVariable::TimedWait(const TimeDelta& max_time) {
|
||||
#endif // OS_MACOSX
|
||||
|
||||
DCHECK(rv == 0 || rv == ETIMEDOUT);
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
#if DCHECK_IS_ON()
|
||||
user_lock_->CheckUnheldAndMark();
|
||||
#endif
|
||||
}
|
||||
|
@ -6,10 +6,9 @@
|
||||
// is functionally a wrapper around the LockImpl class, so the only
|
||||
// real intelligence in the class is in the debugging logic.
|
||||
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -36,4 +35,4 @@ void Lock::CheckUnheldAndMark() {
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // !NDEBUG || DCHECK_ALWAYS_ON
|
||||
#endif // DCHECK_IS_ON()
|
||||
|
@ -6,8 +6,11 @@
|
||||
#define BASE_SYNCHRONIZATION_LOCK_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/synchronization/lock_impl.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -16,7 +19,7 @@ namespace base {
|
||||
// AssertAcquired() method.
|
||||
class BASE_EXPORT Lock {
|
||||
public:
|
||||
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
|
||||
#if !DCHECK_IS_ON()
|
||||
// Optimized wrapper implementation
|
||||
Lock() : lock_() {}
|
||||
~Lock() {}
|
||||
@ -56,7 +59,7 @@ class BASE_EXPORT Lock {
|
||||
}
|
||||
|
||||
void AssertAcquired() const;
|
||||
#endif // NDEBUG && !DCHECK_ALWAYS_ON
|
||||
#endif // DCHECK_IS_ON()
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// The posix implementation of ConditionVariable needs to be able
|
||||
@ -70,7 +73,7 @@ class BASE_EXPORT Lock {
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
#if DCHECK_IS_ON()
|
||||
// Members and routines taking care of locks assertions.
|
||||
// Note that this checks for recursive locks and allows them
|
||||
// if the variable is set. This is allowed by the underlying implementation
|
||||
@ -82,7 +85,7 @@ class BASE_EXPORT Lock {
|
||||
// All private data is implicitly protected by lock_.
|
||||
// Be VERY careful to only access members under that lock.
|
||||
base::PlatformThreadRef owning_thread_ref_;
|
||||
#endif // !NDEBUG || DCHECK_ALWAYS_ON
|
||||
#endif // DCHECK_IS_ON()
|
||||
|
||||
// Platform specific underlying lock implementation.
|
||||
internal::LockImpl lock_;
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
|
||||
#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
@ -13,9 +15,6 @@
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
|
@ -5,8 +5,11 @@
|
||||
#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
|
||||
#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/scoped_handle.h"
|
||||
@ -21,9 +24,6 @@
|
||||
|
||||
namespace base {
|
||||
|
||||
// This replaces INFINITE from Win32
|
||||
static const int kNoTimeout = -1;
|
||||
|
||||
class TimeDelta;
|
||||
|
||||
// A WaitableEvent can be a useful thread synchronization tool when you want to
|
||||
@ -53,11 +53,7 @@ class BASE_EXPORT WaitableEvent {
|
||||
// Create a WaitableEvent from an Event HANDLE which has already been
|
||||
// created. This objects takes ownership of the HANDLE and will close it when
|
||||
// deleted.
|
||||
// TODO(rvargas): Pass ScopedHandle instead (and on Release).
|
||||
explicit WaitableEvent(HANDLE event_handle);
|
||||
|
||||
// Releases ownership of the handle from this object.
|
||||
HANDLE Release();
|
||||
explicit WaitableEvent(win::ScopedHandle event_handle);
|
||||
#endif
|
||||
|
||||
~WaitableEvent();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user