mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 13:58:49 +00:00
Nuke the sandbox
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef security_sandbox_MissingBasicTypes_h__
|
||||
#define security_sandbox_MissingBasicTypes_h__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// These types are still used by the Chromium sandbox code. When referencing
|
||||
// Chromium sandbox code from Gecko we can't use the normal base/basictypes.h as
|
||||
// it clashes with the one from ipc/chromium/src/base/. These types have been
|
||||
// removed from the one in ipc/chromium/src/base/.
|
||||
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;
|
||||
|
||||
#endif // security_sandbox_MissingBasicTypes_h__
|
||||
@@ -1,19 +0,0 @@
|
||||
/* -*- 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_
|
||||
@@ -1,29 +0,0 @@
|
||||
/* -*- 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_
|
||||
@@ -1,19 +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.
|
||||
|
||||
// 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
|
||||
@@ -1,17 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef FRIEND_TEST
|
||||
#define FRIEND_TEST(A, B)
|
||||
#endif
|
||||
|
||||
#ifndef FRIEND_TEST_ALL_PREFIXES
|
||||
#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name)
|
||||
#endif
|
||||
|
||||
#ifndef FORWARD_DECLARE_TEST
|
||||
#define FORWARD_DECLARE_TEST(test_case_name, test_name)
|
||||
#endif
|
||||
@@ -1,156 +0,0 @@
|
||||
/* -*- 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 stripped down version of the Chromium source file base/logging.cc
|
||||
// This prevents dependency on the Chromium logging and dependency creep in
|
||||
// general.
|
||||
// At some point we should find a way to hook this into our own logging see
|
||||
// bug 1013988.
|
||||
// The formatting in this file matches the original Chromium file to aid future
|
||||
// merging.
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace logging {
|
||||
|
||||
namespace {
|
||||
|
||||
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 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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Explicit instantiations for commonly used comparisons.
|
||||
template std::string* MakeCheckOpString<int, int>(
|
||||
const int&, const int&, const char* names);
|
||||
template std::string* MakeCheckOpString<unsigned long, unsigned long>(
|
||||
const unsigned long&, const unsigned long&, const char* names);
|
||||
template std::string* MakeCheckOpString<unsigned long, unsigned int>(
|
||||
const unsigned long&, const unsigned int&, const char* names);
|
||||
template std::string* MakeCheckOpString<unsigned int, unsigned long>(
|
||||
const unsigned int&, const unsigned long&, const char* names);
|
||||
template std::string* MakeCheckOpString<std::string, std::string>(
|
||||
const std::string&, const std::string&, const char* name);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
|
||||
}
|
||||
|
||||
LogMessage::SaveLastError::~SaveLastError() {
|
||||
::SetLastError(last_error_);
|
||||
}
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
|
||||
std::string* result)
|
||||
: severity_(severity), file_(file), line_(line) {
|
||||
delete result;
|
||||
}
|
||||
|
||||
LogMessage::~LogMessage() {
|
||||
}
|
||||
|
||||
SystemErrorCode GetLastSystemErrorCode() {
|
||||
#if defined(OS_WIN)
|
||||
return ::GetLastError();
|
||||
#elif defined(OS_POSIX)
|
||||
return errno;
|
||||
#else
|
||||
#error Not implemented
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
|
||||
int line,
|
||||
LogSeverity severity,
|
||||
SystemErrorCode err)
|
||||
: err_(err),
|
||||
log_message_(file, line, severity) {
|
||||
}
|
||||
|
||||
Win32ErrorLogMessage::~Win32ErrorLogMessage() {
|
||||
}
|
||||
#elif defined(OS_POSIX)
|
||||
ErrnoLogMessage::ErrnoLogMessage(const char* file,
|
||||
int line,
|
||||
LogSeverity severity,
|
||||
SystemErrorCode err)
|
||||
: err_(err),
|
||||
log_message_(file, line, severity) {
|
||||
}
|
||||
|
||||
ErrnoLogMessage::~ErrnoLogMessage() {
|
||||
}
|
||||
#endif // OS_WIN
|
||||
|
||||
void RawLog(int level, const char* message) {
|
||||
}
|
||||
|
||||
} // namespace logging
|
||||
|
||||
#if defined(OS_WIN)
|
||||
std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) {
|
||||
return out << base::WideToUTF8(std::wstring(wstr));
|
||||
}
|
||||
#endif
|
||||
@@ -1,8 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
// Grab the copy from in our tree
|
||||
#include "pr/include/prtime.h"
|
||||
@@ -1,8 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
// Grab the copy from in our tree
|
||||
#include "pr/include/prtypes.h"
|
||||
@@ -1,19 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef _SECURITY_SANDBOX_TRACKED_OBJECTS_H_
|
||||
#define _SECURITY_SANDBOX_TRACKED_OBJECTS_H_
|
||||
namespace tracked_objects
|
||||
{
|
||||
class ThreadData
|
||||
{
|
||||
public:
|
||||
static void InitializeThreadContext(const std::string& name)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
/* -*- 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 stripped down version of Chromium source file base/win/registry.h
|
||||
// Within our copy of Chromium files this is only used in base/win/windows_version.cc
|
||||
// in OSInfo::processor_model_name, which we don't use.
|
||||
|
||||
#ifndef BASE_WIN_REGISTRY_H_
|
||||
#define BASE_WIN_REGISTRY_H_
|
||||
|
||||
namespace base {
|
||||
namespace win {
|
||||
|
||||
class BASE_EXPORT RegKey {
|
||||
public:
|
||||
RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) {}
|
||||
~RegKey() {}
|
||||
|
||||
LONG ReadValue(const wchar_t* name, std::wstring* out_value) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(RegKey);
|
||||
};
|
||||
|
||||
} // namespace win
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_WIN_REGISTRY_H_
|
||||
@@ -1,191 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef _SECURITY_SANDBOX_BASE_SHIM_SDKDECLS_H_
|
||||
#define _SECURITY_SANDBOX_BASE_SHIM_SDKDECLS_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// This file contains definitions required for things dynamically loaded
|
||||
// while building or targetting lower platform versions or lower SDKs.
|
||||
|
||||
#if (_WIN32_WINNT < 0x0600)
|
||||
typedef struct _STARTUPINFOEXA {
|
||||
STARTUPINFOA StartupInfo;
|
||||
LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
|
||||
} STARTUPINFOEXA, *LPSTARTUPINFOEXA;
|
||||
typedef struct _STARTUPINFOEXW {
|
||||
STARTUPINFOW StartupInfo;
|
||||
LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
|
||||
} STARTUPINFOEXW, *LPSTARTUPINFOEXW;
|
||||
#ifdef UNICODE
|
||||
typedef STARTUPINFOEXW STARTUPINFOEX;
|
||||
typedef LPSTARTUPINFOEXW LPSTARTUPINFOEX;
|
||||
#else
|
||||
typedef STARTUPINFOEXA STARTUPINFOEX;
|
||||
typedef LPSTARTUPINFOEXA LPSTARTUPINFOEX;
|
||||
#endif // UNICODE
|
||||
|
||||
#define PROC_THREAD_ATTRIBUTE_NUMBER 0x0000FFFF
|
||||
#define PROC_THREAD_ATTRIBUTE_THREAD 0x00010000 // Attribute may be used with thread creation
|
||||
#define PROC_THREAD_ATTRIBUTE_INPUT 0x00020000 // Attribute is input only
|
||||
#define PROC_THREAD_ATTRIBUTE_ADDITIVE 0x00040000 // Attribute may be "accumulated," e.g. bitmasks, counters, etc.
|
||||
|
||||
#define ProcThreadAttributeValue(Number, Thread, Input, Additive) \
|
||||
(((Number) & PROC_THREAD_ATTRIBUTE_NUMBER) | \
|
||||
((Thread != FALSE) ? PROC_THREAD_ATTRIBUTE_THREAD : 0) | \
|
||||
((Input != FALSE) ? PROC_THREAD_ATTRIBUTE_INPUT : 0) | \
|
||||
((Additive != FALSE) ? PROC_THREAD_ATTRIBUTE_ADDITIVE : 0))
|
||||
|
||||
#define ProcThreadAttributeHandleList 2
|
||||
|
||||
#define PROC_THREAD_ATTRIBUTE_HANDLE_LIST \
|
||||
ProcThreadAttributeValue (ProcThreadAttributeHandleList, FALSE, TRUE, FALSE)
|
||||
|
||||
#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)
|
||||
#define ProcThreadAttributeMitigationPolicy 7
|
||||
#define PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY \
|
||||
ProcThreadAttributeValue (ProcThreadAttributeMitigationPolicy, FALSE, TRUE, FALSE)
|
||||
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE 0x01
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE 0x02
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE 0x04
|
||||
#endif // (_WIN32_WINNT >= 0x0601)
|
||||
|
||||
#if (_WIN32_WINNT < 0x0602)
|
||||
#define ProcThreadAttributeSecurityCapabilities 9
|
||||
#define PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES \
|
||||
ProcThreadAttributeValue (ProcThreadAttributeSecurityCapabilities, FALSE, TRUE, FALSE)
|
||||
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_MASK (0x00000003 << 8)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_DEFER (0x00000000 << 8)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON (0x00000001 << 8)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_OFF (0x00000002 << 8)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS (0x00000003 << 8)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_MASK (0x00000003 << 12)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_DEFER (0x00000000 << 12)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON (0x00000001 << 12)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_OFF (0x00000002 << 12)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_RESERVED (0x00000003 << 12)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_MASK (0x00000003 << 16)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_DEFER (0x00000000 << 16)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON (0x00000001 << 16)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_OFF (0x00000002 << 16)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_RESERVED (0x00000003 << 16)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_MASK (0x00000003 << 20)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_DEFER (0x00000000 << 20)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON (0x00000001 << 20)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_OFF (0x00000002 << 20)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_RESERVED (0x00000003 << 20)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_MASK (0x00000003 << 24)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_DEFER (0x00000000 << 24)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON (0x00000001 << 24)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_OFF (0x00000002 << 24)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_RESERVED (0x00000003 << 24)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_MASK (0x00000003 << 28)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_DEFER (0x00000000 << 28)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON (0x00000001 << 28)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_OFF (0x00000002 << 28)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_RESERVED (0x00000003 << 28)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_MASK (0x00000003ui64 << 32)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_DEFER (0x00000000ui64 << 32)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON (0x00000001ui64 << 32)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_OFF (0x00000002ui64 << 32)
|
||||
#define PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_RESERVED (0x00000003ui64 << 32)
|
||||
|
||||
// Check if we're including >= win8 winnt.h
|
||||
#ifndef NTDDI_WIN8
|
||||
|
||||
typedef struct _SECURITY_CAPABILITIES {
|
||||
PSID AppContainerSid;
|
||||
PSID_AND_ATTRIBUTES Capabilities;
|
||||
DWORD CapabilityCount;
|
||||
DWORD Reserved;
|
||||
} SECURITY_CAPABILITIES, *PSECURITY_CAPABILITIES, *LPSECURITY_CAPABILITIES;
|
||||
|
||||
typedef enum _PROCESS_MITIGATION_POLICY {
|
||||
ProcessDEPPolicy,
|
||||
ProcessASLRPolicy,
|
||||
ProcessReserved1MitigationPolicy,
|
||||
ProcessStrictHandleCheckPolicy,
|
||||
ProcessSystemCallDisablePolicy,
|
||||
ProcessMitigationOptionsMask,
|
||||
ProcessExtensionPointDisablePolicy,
|
||||
MaxProcessMitigationPolicy
|
||||
} PROCESS_MITIGATION_POLICY, *PPROCESS_MITIGATION_POLICY;
|
||||
|
||||
#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
|
||||
|
||||
typedef struct _PROCESS_MITIGATION_ASLR_POLICY {
|
||||
union {
|
||||
DWORD Flags;
|
||||
struct {
|
||||
DWORD EnableBottomUpRandomization : 1;
|
||||
DWORD EnableForceRelocateImages : 1;
|
||||
DWORD EnableHighEntropy : 1;
|
||||
DWORD DisallowStrippedImages : 1;
|
||||
DWORD ReservedFlags : 28;
|
||||
};
|
||||
};
|
||||
} PROCESS_MITIGATION_ASLR_POLICY, *PPROCESS_MITIGATION_ASLR_POLICY;
|
||||
|
||||
typedef struct _PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY {
|
||||
union {
|
||||
DWORD Flags;
|
||||
struct {
|
||||
DWORD RaiseExceptionOnInvalidHandleReference : 1;
|
||||
DWORD HandleExceptionsPermanentlyEnabled : 1;
|
||||
DWORD ReservedFlags : 30;
|
||||
};
|
||||
};
|
||||
} PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY, *PPROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY;
|
||||
|
||||
typedef struct _PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY {
|
||||
union {
|
||||
DWORD Flags;
|
||||
struct {
|
||||
DWORD DisallowWin32kSystemCalls : 1;
|
||||
DWORD ReservedFlags : 31;
|
||||
};
|
||||
};
|
||||
} PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY, *PPROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY;
|
||||
|
||||
typedef struct _PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY {
|
||||
union {
|
||||
DWORD Flags;
|
||||
struct {
|
||||
DWORD DisableExtensionPoints : 1;
|
||||
DWORD ReservedFlags : 31;
|
||||
};
|
||||
};
|
||||
} PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY, *PPROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY;
|
||||
|
||||
#endif // NTDDI_WIN8
|
||||
#endif // (_WIN32_WINNT < 0x0602)
|
||||
#endif // _SECURITY_SANDBOX_BASE_SHIM_SDKDECLS_H_
|
||||
@@ -1,98 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef security_sandbox_loggingCallbacks_h__
|
||||
#define security_sandbox_loggingCallbacks_h__
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/sandboxing/loggingTypes.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "mozilla/StackWalk.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static LazyLogModule sSandboxTargetLog("SandboxTarget");
|
||||
|
||||
#define LOG_D(...) MOZ_LOG(sSandboxTargetLog, LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
namespace sandboxing {
|
||||
|
||||
static uint32_t sStackTraceDepth = 0;
|
||||
|
||||
// NS_WalkStackCallback to write a formatted stack frame to an ostringstream.
|
||||
static void
|
||||
StackFrameToOStringStream(uint32_t aFrameNumber, void* aPC, void* aSP,
|
||||
void* aClosure)
|
||||
{
|
||||
std::ostringstream* stream = static_cast<std::ostringstream*>(aClosure);
|
||||
MozCodeAddressDetails details;
|
||||
char buf[1024];
|
||||
MozDescribeCodeAddress(aPC, &details);
|
||||
MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
|
||||
*stream << std::endl << "--" << buf;
|
||||
stream->flush();
|
||||
}
|
||||
|
||||
// Log to the browser console and, if DEBUG build, stderr.
|
||||
static void
|
||||
Log(const char* aMessageType,
|
||||
const char* aFunctionName,
|
||||
const char* aContext,
|
||||
const bool aShouldLogStackTrace = false,
|
||||
uint32_t aFramesToSkip = 0)
|
||||
{
|
||||
std::ostringstream msgStream;
|
||||
msgStream << "Process Sandbox " << aMessageType << ": " << aFunctionName;
|
||||
if (aContext) {
|
||||
msgStream << " for : " << aContext;
|
||||
}
|
||||
|
||||
if (aShouldLogStackTrace) {
|
||||
if (sStackTraceDepth) {
|
||||
msgStream << std::endl << "Stack Trace:";
|
||||
MozStackWalk(StackFrameToOStringStream, aFramesToSkip, sStackTraceDepth,
|
||||
&msgStream, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::string msg = msgStream.str();
|
||||
#if defined(DEBUG)
|
||||
// Use NS_DebugBreak directly as we want child process prefix, but not source
|
||||
// file or line number.
|
||||
NS_DebugBreak(NS_DEBUG_WARNING, nullptr, msg.c_str(), nullptr, -1);
|
||||
#endif
|
||||
|
||||
if (nsContentUtils::IsInitialized()) {
|
||||
nsContentUtils::LogMessageToConsole(msg.c_str());
|
||||
}
|
||||
|
||||
// As we don't always have the facility to log to console use MOZ_LOG as well.
|
||||
LOG_D("%s", msg.c_str());
|
||||
}
|
||||
|
||||
// Initialize sandbox logging if required.
|
||||
static void
|
||||
InitLoggingIfRequired(ProvideLogFunctionCb aProvideLogFunctionCb)
|
||||
{
|
||||
if (!aProvideLogFunctionCb) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("security.sandbox.windows.log") ||
|
||||
PR_GetEnv("MOZ_WIN_SANDBOX_LOGGING")) {
|
||||
aProvideLogFunctionCb(Log);
|
||||
}
|
||||
}
|
||||
|
||||
} // sandboxing
|
||||
} // mozilla
|
||||
|
||||
#endif // security_sandbox_loggingCallbacks_h__
|
||||
@@ -1,27 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef security_sandbox_loggingTypes_h__
|
||||
#define security_sandbox_loggingTypes_h__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace sandboxing {
|
||||
|
||||
// We are using callbacks here that are passed in from the core code to prevent
|
||||
// a circular dependency in the linking during the build.
|
||||
typedef void (*LogFunction) (const char* aMessageType,
|
||||
const char* aFunctionName,
|
||||
const char* aContext,
|
||||
const bool aShouldLogStackTrace,
|
||||
uint32_t aFramesToSkip);
|
||||
typedef void (*ProvideLogFunctionCb) (LogFunction aLogFunction);
|
||||
|
||||
} // sandboxing
|
||||
} // mozilla
|
||||
|
||||
#endif // security_sandbox_loggingTypes_h__
|
||||
@@ -1,82 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "sandboxLogging.h"
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "sandbox/win/src/sandbox_policy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace sandboxing {
|
||||
|
||||
static LogFunction sLogFunction = nullptr;
|
||||
|
||||
void
|
||||
ProvideLogFunction(LogFunction aLogFunction)
|
||||
{
|
||||
sLogFunction = aLogFunction;
|
||||
}
|
||||
|
||||
void
|
||||
LogBlocked(const char* aFunctionName, const char* aContext, uint32_t aFramesToSkip)
|
||||
{
|
||||
if (sLogFunction) {
|
||||
sLogFunction("BLOCKED", aFunctionName, aContext,
|
||||
/* aShouldLogStackTrace */ true, aFramesToSkip);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogBlocked(const char* aFunctionName, const wchar_t* aContext)
|
||||
{
|
||||
if (sLogFunction) {
|
||||
// Skip an extra frame to allow for this function.
|
||||
LogBlocked(aFunctionName, base::WideToUTF8(aContext).c_str(),
|
||||
/* aFramesToSkip */ 3);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogBlocked(const char* aFunctionName, const wchar_t* aContext,
|
||||
uint16_t aLengthInBytes)
|
||||
{
|
||||
if (sLogFunction) {
|
||||
// Skip an extra frame to allow for this function.
|
||||
LogBlocked(aFunctionName,
|
||||
base::WideToUTF8(std::wstring(aContext, aLengthInBytes / sizeof(wchar_t))).c_str(),
|
||||
/* aFramesToSkip */ 3);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogAllowed(const char* aFunctionName, const char* aContext)
|
||||
{
|
||||
if (sLogFunction) {
|
||||
sLogFunction("Broker ALLOWED", aFunctionName, aContext,
|
||||
/* aShouldLogStackTrace */ false, /* aFramesToSkip */ 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogAllowed(const char* aFunctionName, const wchar_t* aContext)
|
||||
{
|
||||
if (sLogFunction) {
|
||||
LogAllowed(aFunctionName, base::WideToUTF8(aContext).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogAllowed(const char* aFunctionName, const wchar_t* aContext,
|
||||
uint16_t aLengthInBytes)
|
||||
{
|
||||
if (sLogFunction) {
|
||||
LogAllowed(aFunctionName,
|
||||
base::WideToUTF8(std::wstring(aContext, aLengthInBytes / sizeof(wchar_t))).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // sandboxing
|
||||
} // mozilla
|
||||
@@ -1,51 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
/*
|
||||
* Set of helper methods to implement logging for Windows sandbox.
|
||||
*/
|
||||
|
||||
#ifndef security_sandbox_sandboxLogging_h__
|
||||
#define security_sandbox_sandboxLogging_h__
|
||||
|
||||
#include "loggingTypes.h"
|
||||
|
||||
namespace sandbox {
|
||||
class TargetPolicy;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace sandboxing {
|
||||
|
||||
// This is used to pass a LogCallback to the sandboxing code, as the logging
|
||||
// requires code to which we cannot link directly.
|
||||
void ProvideLogFunction(LogFunction aLogFunction);
|
||||
|
||||
// Log a "BLOCKED" msg to the browser console and, if DEBUG build, stderr.
|
||||
// If the logging of a stack trace is enabled then the default aFramesToSkip
|
||||
// will start from our caller's caller, which should normally be the function
|
||||
// that triggered the interception.
|
||||
void LogBlocked(const char* aFunctionName, const char* aContext = nullptr,
|
||||
uint32_t aFramesToSkip = 2);
|
||||
|
||||
// Convenience functions to convert to char*.
|
||||
void LogBlocked(const char* aFunctionName, const wchar_t* aContext);
|
||||
void LogBlocked(const char* aFunctionName, const wchar_t* aContext,
|
||||
uint16_t aLengthInBytes);
|
||||
|
||||
// Log a "ALLOWED" msg to the browser console and, if DEBUG build, stderr.
|
||||
void LogAllowed(const char* aFunctionName, const char* aContext = nullptr);
|
||||
|
||||
// Convenience functions to convert to char*.
|
||||
void LogAllowed(const char* aFunctionName, const wchar_t* aContext);
|
||||
void LogAllowed(const char* aFunctionName, const wchar_t* aContext,
|
||||
uint16_t aLengthInBytes);
|
||||
|
||||
|
||||
} // sandboxing
|
||||
} // mozilla
|
||||
|
||||
#endif // security_sandbox_sandboxLogging_h__
|
||||
@@ -1,27 +0,0 @@
|
||||
// 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
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,82 +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.
|
||||
|
||||
#include "base/at_exit.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <ostream>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Keep a stack of registered AtExitManagers. We always operate on the most
|
||||
// recent, and we should never have more than one outside of testing (for a
|
||||
// statically linked version of this library). Testing may use the shadow
|
||||
// version of the constructor, and if we are building a dynamic library we may
|
||||
// end up with multiple AtExitManagers on the same process. We don't protect
|
||||
// this for thread-safe access, since it will only be modified in testing.
|
||||
static AtExitManager* g_top_manager = NULL;
|
||||
|
||||
AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
|
||||
// If multiple modules instantiate AtExitManagers they'll end up living in this
|
||||
// module... they have to coexist.
|
||||
#if !defined(COMPONENT_BUILD)
|
||||
DCHECK(!g_top_manager);
|
||||
#endif
|
||||
g_top_manager = this;
|
||||
}
|
||||
|
||||
AtExitManager::~AtExitManager() {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
|
||||
return;
|
||||
}
|
||||
DCHECK_EQ(this, g_top_manager);
|
||||
|
||||
ProcessCallbacksNow();
|
||||
g_top_manager = next_manager_;
|
||||
}
|
||||
|
||||
// static
|
||||
void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
|
||||
DCHECK(func);
|
||||
RegisterTask(base::Bind(func, param));
|
||||
}
|
||||
|
||||
// static
|
||||
void AtExitManager::RegisterTask(base::Closure task) {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLock lock(g_top_manager->lock_);
|
||||
g_top_manager->stack_.push(task);
|
||||
}
|
||||
|
||||
// static
|
||||
void AtExitManager::ProcessCallbacksNow() {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLock lock(g_top_manager->lock_);
|
||||
|
||||
while (!g_top_manager->stack_.empty()) {
|
||||
base::Closure task = g_top_manager->stack_.top();
|
||||
task.Run();
|
||||
g_top_manager->stack_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
|
||||
DCHECK(shadow || !g_top_manager);
|
||||
g_top_manager = this;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
@@ -1,76 +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_AT_EXIT_H_
|
||||
#define BASE_AT_EXIT_H_
|
||||
|
||||
#include <stack>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// This class provides a facility similar to the CRT atexit(), except that
|
||||
// we control when the callbacks are executed. Under Windows for a DLL they
|
||||
// happen at a really bad time and under the loader lock. This facility is
|
||||
// mostly used by base::Singleton.
|
||||
//
|
||||
// The usage is simple. Early in the main() or WinMain() scope create an
|
||||
// AtExitManager object on the stack:
|
||||
// int main(...) {
|
||||
// base::AtExitManager exit_manager;
|
||||
//
|
||||
// }
|
||||
// When the exit_manager object goes out of scope, all the registered
|
||||
// callbacks and singleton destructors will be called.
|
||||
|
||||
class BASE_EXPORT AtExitManager {
|
||||
public:
|
||||
typedef void (*AtExitCallbackType)(void*);
|
||||
|
||||
AtExitManager();
|
||||
|
||||
// The dtor calls all the registered callbacks. Do not try to register more
|
||||
// callbacks after this point.
|
||||
~AtExitManager();
|
||||
|
||||
// Registers the specified function to be called at exit. The prototype of
|
||||
// the callback function is void func(void*).
|
||||
static void RegisterCallback(AtExitCallbackType func, void* param);
|
||||
|
||||
// Registers the specified task to be called at exit.
|
||||
static void RegisterTask(base::Closure task);
|
||||
|
||||
// Calls the functions registered with RegisterCallback in LIFO order. It
|
||||
// is possible to register new callbacks after calling this function.
|
||||
static void ProcessCallbacksNow();
|
||||
|
||||
protected:
|
||||
// This constructor will allow this instance of AtExitManager to be created
|
||||
// even if one already exists. This should only be used for testing!
|
||||
// AtExitManagers are kept on a global stack, and it will be removed during
|
||||
// destruction. This allows you to shadow another AtExitManager.
|
||||
explicit AtExitManager(bool shadow);
|
||||
|
||||
private:
|
||||
base::Lock lock_;
|
||||
std::stack<base::Closure> stack_;
|
||||
AtExitManager* next_manager_; // Stack of managers to allow shadowing.
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtExitManager);
|
||||
};
|
||||
|
||||
#if defined(UNIT_TEST)
|
||||
class ShadowingAtExitManager : public AtExitManager {
|
||||
public:
|
||||
ShadowingAtExitManager() : AtExitManager(true) {}
|
||||
};
|
||||
#endif // defined(UNIT_TEST)
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_AT_EXIT_H_
|
||||
@@ -1,66 +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 is a low level implementation of atomic semantics for reference
|
||||
// counting. Please use base/memory/ref_counted.h directly instead.
|
||||
|
||||
#ifndef BASE_ATOMIC_REF_COUNT_H_
|
||||
#define BASE_ATOMIC_REF_COUNT_H_
|
||||
|
||||
#include "base/atomicops.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
typedef subtle::Atomic32 AtomicRefCount;
|
||||
|
||||
// Increment a reference count by "increment", which must exceed 0.
|
||||
inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,
|
||||
AtomicRefCount increment) {
|
||||
subtle::NoBarrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
// Decrement a reference count by "decrement", which must exceed 0,
|
||||
// and return whether the result is non-zero.
|
||||
// Insert barriers to ensure that state written before the reference count
|
||||
// became zero will be visible to a thread that has just made the count zero.
|
||||
inline bool AtomicRefCountDecN(volatile AtomicRefCount *ptr,
|
||||
AtomicRefCount decrement) {
|
||||
bool res = (subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Increment a reference count by 1.
|
||||
inline void AtomicRefCountInc(volatile AtomicRefCount *ptr) {
|
||||
base::AtomicRefCountIncN(ptr, 1);
|
||||
}
|
||||
|
||||
// Decrement a reference count by 1 and return whether the result is non-zero.
|
||||
// Insert barriers to ensure that state written before the reference count
|
||||
// became zero will be visible to a thread that has just made the count zero.
|
||||
inline bool AtomicRefCountDec(volatile AtomicRefCount *ptr) {
|
||||
return base::AtomicRefCountDecN(ptr, 1);
|
||||
}
|
||||
|
||||
// Return whether the reference count is one. If the reference count is used
|
||||
// in the conventional way, a refrerence count of 1 implies that the current
|
||||
// thread owns the reference and no other thread shares it. This call performs
|
||||
// the test for a reference count of one, and performs the memory barrier
|
||||
// needed for the owning thread to act on the object, knowing that it has
|
||||
// exclusive access to the object.
|
||||
inline bool AtomicRefCountIsOne(volatile AtomicRefCount *ptr) {
|
||||
bool res = (subtle::Acquire_Load(ptr) == 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Return whether the reference count is zero. With conventional object
|
||||
// referencing counting, the object will be destroyed, so the reference count
|
||||
// should never be zero. Hence this is generally used for a debug check.
|
||||
inline bool AtomicRefCountIsZero(volatile AtomicRefCount *ptr) {
|
||||
bool res = (subtle::Acquire_Load(ptr) == 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMIC_REF_COUNT_H_
|
||||
@@ -1,60 +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_ATOMIC_SEQUENCE_NUM_H_
|
||||
#define BASE_ATOMIC_SEQUENCE_NUM_H_
|
||||
|
||||
#include "base/atomicops.h"
|
||||
#include "base/macros.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class AtomicSequenceNumber;
|
||||
|
||||
// Static (POD) AtomicSequenceNumber that MUST be used in global scope (or
|
||||
// non-function scope) ONLY. This implementation does not generate any static
|
||||
// initializer. Note that it does not implement any constructor which means
|
||||
// that its fields are not initialized except when it is stored in the global
|
||||
// data section (.data in ELF). If you want to allocate an atomic sequence
|
||||
// number on the stack (or heap), please use the AtomicSequenceNumber class
|
||||
// declared below.
|
||||
class StaticAtomicSequenceNumber {
|
||||
public:
|
||||
inline int GetNext() {
|
||||
return static_cast<int>(
|
||||
base::subtle::NoBarrier_AtomicIncrement(&seq_, 1) - 1);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class AtomicSequenceNumber;
|
||||
|
||||
inline void Reset() {
|
||||
base::subtle::Release_Store(&seq_, 0);
|
||||
}
|
||||
|
||||
base::subtle::Atomic32 seq_;
|
||||
};
|
||||
|
||||
// AtomicSequenceNumber that can be stored and used safely (i.e. its fields are
|
||||
// always initialized as opposed to StaticAtomicSequenceNumber declared above).
|
||||
// Please use StaticAtomicSequenceNumber if you want to declare an atomic
|
||||
// sequence number in the global scope.
|
||||
class AtomicSequenceNumber {
|
||||
public:
|
||||
AtomicSequenceNumber() {
|
||||
seq_.Reset();
|
||||
}
|
||||
|
||||
inline int GetNext() {
|
||||
return seq_.GetNext();
|
||||
}
|
||||
|
||||
private:
|
||||
StaticAtomicSequenceNumber seq_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMIC_SEQUENCE_NUM_H_
|
||||
@@ -1,161 +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.
|
||||
|
||||
// For atomic operations on reference counts, see atomic_refcount.h.
|
||||
// For atomic operations on sequence numbers, see atomic_sequence_num.h.
|
||||
|
||||
// The routines exported by this module are subtle. If you use them, even if
|
||||
// you get the code right, it will depend on careful reasoning about atomicity
|
||||
// and memory ordering; it will be less readable, and harder to maintain. If
|
||||
// you plan to use these routines, you should have a good reason, such as solid
|
||||
// evidence that performance would otherwise suffer, or there being no
|
||||
// alternative. You should assume only properties explicitly guaranteed by the
|
||||
// specifications in this file. You are almost certainly _not_ writing code
|
||||
// just for the x86; if you assume x86 semantics, x86 hardware bugs and
|
||||
// implementations on other archtectures will cause your code to break. If you
|
||||
// do not know what you are doing, avoid these routines, and use a Mutex.
|
||||
//
|
||||
// It is incorrect to make direct assignments to/from an atomic variable.
|
||||
// You should use one of the Load or Store routines. The NoBarrier
|
||||
// versions are provided when no barriers are needed:
|
||||
// NoBarrier_Store()
|
||||
// NoBarrier_Load()
|
||||
// Although there are currently no compiler enforcement, you are encouraged
|
||||
// to use these.
|
||||
//
|
||||
|
||||
#ifndef BASE_ATOMICOPS_H_
|
||||
#define BASE_ATOMICOPS_H_
|
||||
|
||||
#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"
|
||||
|
||||
#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
|
||||
// windows.h #defines this (only on x64). This causes problems because the
|
||||
// public API also uses MemoryBarrier at the public name for this fence. So, on
|
||||
// X64, undef it, and call its documented
|
||||
// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
|
||||
// implementation directly.
|
||||
#undef MemoryBarrier
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
typedef int32_t Atomic32;
|
||||
#ifdef ARCH_CPU_64_BITS
|
||||
// We need to be able to go between Atomic64 and AtomicWord implicitly. This
|
||||
// means Atomic64 and AtomicWord should be the same type on 64-bit.
|
||||
#if defined(__ILP32__) || defined(OS_NACL)
|
||||
// NaCl's intptr_t is not actually 64-bits on 64-bit!
|
||||
// http://code.google.com/p/nativeclient/issues/detail?id=1162
|
||||
typedef int64_t Atomic64;
|
||||
#else
|
||||
typedef intptr_t Atomic64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
|
||||
// Atomic64 routines below, depending on your architecture.
|
||||
typedef intptr_t AtomicWord;
|
||||
|
||||
// Atomically execute:
|
||||
// result = *ptr;
|
||||
// if (*ptr == old_value)
|
||||
// *ptr = new_value;
|
||||
// return result;
|
||||
//
|
||||
// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
|
||||
// Always return the old value of "*ptr"
|
||||
//
|
||||
// This routine implies no memory barriers.
|
||||
Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value);
|
||||
|
||||
// Atomically store new_value into *ptr, returning the previous value held in
|
||||
// *ptr. This routine implies no memory barriers.
|
||||
Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
|
||||
|
||||
// Atomically increment *ptr by "increment". Returns the new value of
|
||||
// *ptr with the increment applied. This routine implies no memory barriers.
|
||||
Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
|
||||
|
||||
Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment);
|
||||
|
||||
// These following lower-level operations are typically useful only to people
|
||||
// implementing higher-level synchronization operations like spinlocks,
|
||||
// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or
|
||||
// a store with appropriate memory-ordering instructions. "Acquire" operations
|
||||
// ensure that no later memory access can be reordered ahead of the operation.
|
||||
// "Release" operations ensure that no previous memory access can be reordered
|
||||
// after the operation. "Barrier" operations have both "Acquire" and "Release"
|
||||
// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
|
||||
// access.
|
||||
Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value);
|
||||
Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value);
|
||||
|
||||
void MemoryBarrier();
|
||||
void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
|
||||
void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
|
||||
void Release_Store(volatile Atomic32* ptr, Atomic32 value);
|
||||
|
||||
Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
|
||||
Atomic32 Acquire_Load(volatile const Atomic32* ptr);
|
||||
Atomic32 Release_Load(volatile const Atomic32* ptr);
|
||||
|
||||
// 64-bit atomic operations (only available on 64-bit processors).
|
||||
#ifdef ARCH_CPU_64_BITS
|
||||
Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value);
|
||||
Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
|
||||
Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
|
||||
Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
|
||||
|
||||
Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value);
|
||||
Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value);
|
||||
void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
|
||||
void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
|
||||
void Release_Store(volatile Atomic64* ptr, Atomic64 value);
|
||||
Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
|
||||
Atomic64 Acquire_Load(volatile const Atomic64* ptr);
|
||||
Atomic64 Release_Load(volatile const Atomic64* ptr);
|
||||
#endif // ARCH_CPU_64_BITS
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
#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"
|
||||
#else
|
||||
# include "base/atomicops_internals_portable.h"
|
||||
#endif
|
||||
|
||||
// On some platforms we need additional declarations to make
|
||||
// AtomicWord compatible with our other Atomic* types.
|
||||
#if defined(OS_MACOSX) || defined(OS_OPENBSD)
|
||||
#include "base/atomicops_internals_atomicword_compat.h"
|
||||
#endif
|
||||
|
||||
#endif // BASE_ATOMICOPS_H_
|
||||
@@ -1,229 +0,0 @@
|
||||
// Copyright (c) 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.
|
||||
|
||||
// This file is an internal atomic implementation, use atomicops.h instead.
|
||||
//
|
||||
// This implementation uses C++11 atomics' member functions. The code base is
|
||||
// currently written assuming atomicity revolves around accesses instead of
|
||||
// C++11's memory locations. The burden is on the programmer to ensure that all
|
||||
// memory locations accessed atomically are never accessed non-atomically (tsan
|
||||
// should help with this).
|
||||
//
|
||||
// TODO(jfb) Modify the atomicops.h API and user code to declare atomic
|
||||
// locations as truly atomic. See the static_assert below.
|
||||
//
|
||||
// Of note in this implementation:
|
||||
// * All NoBarrier variants are implemented as relaxed.
|
||||
// * All Barrier variants are implemented as sequentially-consistent.
|
||||
// * Compare exchange's failure ordering is always the same as the success one
|
||||
// (except for release, which fails as relaxed): using a weaker ordering is
|
||||
// only valid under certain uses of compare exchange.
|
||||
// * Acquire store doesn't exist in the C11 memory model, it is instead
|
||||
// implemented as a relaxed store followed by a sequentially consistent
|
||||
// fence.
|
||||
// * Release load doesn't exist in the C11 memory model, it is instead
|
||||
// implemented as sequentially consistent fence followed by a relaxed load.
|
||||
// * Atomic increment is expected to return the post-incremented value, whereas
|
||||
// C11 fetch add returns the previous value. The implementation therefore
|
||||
// needs to increment twice (which the compiler should be able to detect and
|
||||
// optimize).
|
||||
|
||||
#ifndef BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
|
||||
#define BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
// This implementation is transitional and maintains the original API for
|
||||
// atomicops.h. This requires casting memory locations to the atomic types, and
|
||||
// assumes that the API and the C++11 implementation are layout-compatible,
|
||||
// which isn't true for all implementations or hardware platforms. The static
|
||||
// assertion should detect this issue, were it to fire then this header
|
||||
// shouldn't be used.
|
||||
//
|
||||
// TODO(jfb) If this header manages to stay committed then the API should be
|
||||
// modified, and all call sites updated.
|
||||
typedef volatile std::atomic<Atomic32>* AtomicLocation32;
|
||||
static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
|
||||
"incompatible 32-bit atomic layout");
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
#if defined(__GLIBCXX__)
|
||||
// Work around libstdc++ bug 51038 where atomic_thread_fence was declared but
|
||||
// not defined, leading to the linker complaining about undefined references.
|
||||
__atomic_thread_fence(std::memory_order_seq_cst);
|
||||
#else
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
((AtomicLocation32)ptr)
|
||||
->compare_exchange_strong(old_value,
|
||||
new_value,
|
||||
std::memory_order_relaxed,
|
||||
std::memory_order_relaxed);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
return ((AtomicLocation32)ptr)
|
||||
->exchange(new_value, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return increment +
|
||||
((AtomicLocation32)ptr)
|
||||
->fetch_add(increment, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
((AtomicLocation32)ptr)
|
||||
->compare_exchange_strong(old_value,
|
||||
new_value,
|
||||
std::memory_order_acquire,
|
||||
std::memory_order_acquire);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
((AtomicLocation32)ptr)
|
||||
->compare_exchange_strong(old_value,
|
||||
new_value,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
((AtomicLocation32)ptr)->store(value, std::memory_order_release);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
|
||||
typedef volatile std::atomic<Atomic64>* AtomicLocation64;
|
||||
static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
|
||||
"incompatible 64-bit atomic layout");
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
((AtomicLocation64)ptr)
|
||||
->compare_exchange_strong(old_value,
|
||||
new_value,
|
||||
std::memory_order_relaxed,
|
||||
std::memory_order_relaxed);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
|
||||
Atomic64 new_value) {
|
||||
return ((AtomicLocation64)ptr)
|
||||
->exchange(new_value, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
return increment +
|
||||
((AtomicLocation64)ptr)
|
||||
->fetch_add(increment, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
((AtomicLocation64)ptr)
|
||||
->compare_exchange_strong(old_value,
|
||||
new_value,
|
||||
std::memory_order_acquire,
|
||||
std::memory_order_acquire);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
((AtomicLocation64)ptr)
|
||||
->compare_exchange_strong(old_value,
|
||||
new_value,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
((AtomicLocation64)ptr)->store(value, std::memory_order_release);
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
MemoryBarrier();
|
||||
return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
#endif // defined(ARCH_CPU_64_BITS)
|
||||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
|
||||
@@ -1,196 +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.
|
||||
|
||||
// This file is an internal atomic implementation, use base/atomicops.h instead.
|
||||
|
||||
#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
|
||||
#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#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
|
||||
// public API also uses MemoryBarrier at the public name for this fence. So, on
|
||||
// X64, undef it, and call its documented
|
||||
// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
|
||||
// implementation directly.
|
||||
#undef MemoryBarrier
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
LONG result = _InterlockedCompareExchange(
|
||||
reinterpret_cast<volatile LONG*>(ptr),
|
||||
static_cast<LONG>(new_value),
|
||||
static_cast<LONG>(old_value));
|
||||
return static_cast<Atomic32>(result);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
LONG result = _InterlockedExchange(
|
||||
reinterpret_cast<volatile LONG*>(ptr),
|
||||
static_cast<LONG>(new_value));
|
||||
return static_cast<Atomic32>(result);
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return _InterlockedExchangeAdd(
|
||||
reinterpret_cast<volatile LONG*>(ptr),
|
||||
static_cast<LONG>(increment)) + increment;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
// See #undef and note at the top of this file.
|
||||
__faststorefence();
|
||||
#else
|
||||
// We use MemoryBarrier from WinNT.h
|
||||
::MemoryBarrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
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 Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
NoBarrier_AtomicExchange(ptr, value);
|
||||
// acts as a barrier in this implementation
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value; // works w/o barrier for current Intel chips as of June 2005
|
||||
// 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;
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
|
||||
// 64-bit low-level operations on 64-bit platform.
|
||||
|
||||
static_assert(sizeof(Atomic64) == sizeof(PVOID), "atomic word is atomic");
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
PVOID result = InterlockedCompareExchangePointer(
|
||||
reinterpret_cast<volatile PVOID*>(ptr),
|
||||
reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
|
||||
return reinterpret_cast<Atomic64>(result);
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
|
||||
Atomic64 new_value) {
|
||||
PVOID result = InterlockedExchangePointer(
|
||||
reinterpret_cast<volatile PVOID*>(ptr),
|
||||
reinterpret_cast<PVOID>(new_value));
|
||||
return reinterpret_cast<Atomic64>(result);
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
return InterlockedExchangeAdd64(
|
||||
reinterpret_cast<volatile LONGLONG*>(ptr),
|
||||
static_cast<LONGLONG>(increment)) + increment;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
NoBarrier_AtomicExchange(ptr, value);
|
||||
// acts as a barrier in this implementation
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value; // works w/o barrier for current Intel chips as of June 2005
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
Atomic64 value = *ptr;
|
||||
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) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
|
||||
#endif // defined(_WIN64)
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
|
||||
@@ -1,29 +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_BASE_EXPORT_H_
|
||||
#define BASE_BASE_EXPORT_H_
|
||||
|
||||
#if defined(COMPONENT_BUILD)
|
||||
#if defined(WIN32)
|
||||
|
||||
#if defined(BASE_IMPLEMENTATION)
|
||||
#define BASE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define BASE_EXPORT __declspec(dllimport)
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
|
||||
#else // defined(WIN32)
|
||||
#if defined(BASE_IMPLEMENTATION)
|
||||
#define BASE_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define BASE_EXPORT
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
#endif
|
||||
|
||||
#else // defined(COMPONENT_BUILD)
|
||||
#define BASE_EXPORT
|
||||
#endif
|
||||
|
||||
#endif // BASE_BASE_EXPORT_H_
|
||||
@@ -1,55 +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_BASE_PATHS_H_
|
||||
#define BASE_BASE_PATHS_H_
|
||||
|
||||
// This file declares path keys for the base module. These can be used with
|
||||
// the PathService to access various special directories and files.
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/base_paths_win.h"
|
||||
#elif defined(OS_MACOSX)
|
||||
#include "base/base_paths_mac.h"
|
||||
#elif defined(OS_ANDROID)
|
||||
#include "base/base_paths_android.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include "base/base_paths_posix.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
enum BasePathKey {
|
||||
PATH_START = 0,
|
||||
|
||||
DIR_CURRENT, // Current directory.
|
||||
DIR_EXE, // Directory containing FILE_EXE.
|
||||
DIR_MODULE, // Directory containing FILE_MODULE.
|
||||
DIR_TEMP, // Temporary directory.
|
||||
DIR_HOME, // User's root home directory. On Windows this will look
|
||||
// like "C:\Users\you" (or on XP
|
||||
// "C:\Document and Settings\you") which isn't necessarily
|
||||
// a great place to put files.
|
||||
FILE_EXE, // Path and filename of the current executable.
|
||||
FILE_MODULE, // Path and filename of the module containing the code for
|
||||
// the PathService (which could differ from FILE_EXE if the
|
||||
// PathService were compiled into a shared object, for
|
||||
// example).
|
||||
DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
|
||||
// for tests that need to locate various resources. It
|
||||
// should not be used outside of test code.
|
||||
DIR_USER_DESKTOP, // The current user's Desktop.
|
||||
|
||||
DIR_TEST_DATA, // Used only for testing.
|
||||
|
||||
PATH_END
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BASE_PATHS_H_
|
||||
@@ -1,54 +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_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
|
||||
// directories and files.
|
||||
|
||||
namespace base {
|
||||
|
||||
enum {
|
||||
PATH_WIN_START = 100,
|
||||
|
||||
DIR_WINDOWS, // Windows directory, usually "c:\windows"
|
||||
DIR_SYSTEM, // Usually c:\windows\system32"
|
||||
// 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\
|
||||
// Start Menu\Programs"
|
||||
DIR_START_MENU, // Usually "C:\Documents and Settings\<user>\
|
||||
// Start Menu\Programs"
|
||||
DIR_APP_DATA, // Application Data directory under the user profile.
|
||||
DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory under
|
||||
// the user profile.
|
||||
DIR_COMMON_APP_DATA, // W2K, XP, W2K3: "C:\Documents and Settings\
|
||||
// All Users\Application Data".
|
||||
// Vista, W2K8 and above: "C:\ProgramData".
|
||||
DIR_APP_SHORTCUTS, // Where tiles on the start screen are stored, only
|
||||
// for Windows 8. Maps to "Local\AppData\Microsoft\
|
||||
// Windows\Application Shortcuts\".
|
||||
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
|
||||
// (Win7-8) via base::win::PinShortcutToTaskbar().
|
||||
DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts.
|
||||
|
||||
PATH_WIN_END
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BASE_PATHS_WIN_H_
|
||||
@@ -1,95 +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.
|
||||
|
||||
#include "base/base_switches.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace switches {
|
||||
|
||||
// Disables the crash reporting.
|
||||
const char kDisableBreakpad[] = "disable-breakpad";
|
||||
|
||||
// Indicates that crash reporting should be enabled. On platforms where helper
|
||||
// processes cannot access to files needed to make this decision, this flag is
|
||||
// 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 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";
|
||||
|
||||
// When running certain tests that spawn child processes, this switch indicates
|
||||
// to the test framework that the current process is a child process.
|
||||
const char kTestChildProcess[] = "test-child-process";
|
||||
|
||||
// Gives the default maximal active V-logging level; 0 is the default.
|
||||
// Normally positive values are used for V-logging levels.
|
||||
const char kV[] = "v";
|
||||
|
||||
// Gives the per-module maximal V-logging levels to override the value
|
||||
// given by --v. E.g. "my_module=2,foo*=3" would change the logging
|
||||
// level for all code in source files "my_module.*" and "foo*.*"
|
||||
// ("-inl" suffixes are also disregarded for this matching).
|
||||
//
|
||||
// Any pattern containing a forward or backward slash will be tested
|
||||
// against the whole pathname and not just the module. E.g.,
|
||||
// "*/foo/bar/*=2" would change the logging level for all code in
|
||||
// source files under a "foo/bar" directory.
|
||||
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 trace events from these categories to a file.
|
||||
// --trace-to-file on its own sends to default categories.
|
||||
const char kTraceToFile[] = "trace-to-file";
|
||||
|
||||
// Specifies the file name for --trace-to-file. If unspecified, it will
|
||||
// go to a default file name.
|
||||
const char kTraceToFileName[] = "trace-to-file-name";
|
||||
|
||||
// Configure whether chrome://profiler will contain timing information. This
|
||||
// option is enabled by default. A value of "0" will disable profiler timing,
|
||||
// while all other values will enable it.
|
||||
const char kProfilerTiming[] = "profiler-timing";
|
||||
// Value of the --profiler-timing flag that will disable timing information for
|
||||
// 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.
|
||||
const char kEnableCrashReporterForTesting[] =
|
||||
"enable-crash-reporter-for-testing";
|
||||
#endif
|
||||
|
||||
} // namespace switches
|
||||
@@ -1,41 +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.
|
||||
|
||||
// Defines all the "base" command-line switches.
|
||||
|
||||
#ifndef BASE_BASE_SWITCHES_H_
|
||||
#define BASE_BASE_SWITCHES_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
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 kNoErrorDialogs[];
|
||||
extern const char kProfilerTiming[];
|
||||
extern const char kProfilerTimingDisabledValue[];
|
||||
extern const char kTestChildProcess[];
|
||||
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
|
||||
|
||||
} // namespace switches
|
||||
|
||||
#endif // BASE_BASE_SWITCHES_H_
|
||||
@@ -1,101 +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_BIND_H_
|
||||
#define BASE_BIND_H_
|
||||
|
||||
#include "base/bind_internal.h"
|
||||
#include "base/callback_internal.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Usage documentation
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// See base/callback.h for documentation.
|
||||
//
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation notes
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// If you're reading the implementation, before proceeding further, you should
|
||||
// read the top comment of base/bind_internal.h for a definition of common
|
||||
// terms and concepts.
|
||||
//
|
||||
// RETURN TYPES
|
||||
//
|
||||
// Though Bind()'s result is meant to be stored in a Callback<> type, it
|
||||
// cannot actually return the exact type without requiring a large amount
|
||||
// of extra template specializations. The problem is that in order to
|
||||
// discern the correct specialization of Callback<>, Bind would need to
|
||||
// unwrap the function signature to determine the signature's arity, and
|
||||
// whether or not it is a method.
|
||||
//
|
||||
// Each unique combination of (arity, function_type, num_prebound) where
|
||||
// function_type is one of {function, method, const_method} would require
|
||||
// one specialization. We eventually have to do a similar number of
|
||||
// specializations anyways in the implementation (see the Invoker<>,
|
||||
// classes). However, it is avoidable in Bind if we return the result
|
||||
// via an indirection like we do below.
|
||||
//
|
||||
// TODO(ajwong): We might be able to avoid this now, but need to test.
|
||||
//
|
||||
// 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, typename... Args>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
typename internal::CallbackParamTraits<Args>::StorageType...>
|
||||
::UnboundRunType>
|
||||
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 below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
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.
|
||||
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.
|
||||
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), args...));
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BIND_H_
|
||||
@@ -1,658 +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 defines a set of argument wrappers and related factory methods that
|
||||
// can be used specify the refcounting and reference semantics of arguments
|
||||
// that are bound by the Bind() function in base/bind.h.
|
||||
//
|
||||
// It also defines a set of simple functions and utilities that people want
|
||||
// when using Callback<> and Bind().
|
||||
//
|
||||
//
|
||||
// ARGUMENT BINDING WRAPPERS
|
||||
//
|
||||
// The wrapper functions are base::Unretained(), base::Owned(), base::Passed(),
|
||||
// base::ConstRef(), and base::IgnoreResult().
|
||||
//
|
||||
// Unretained() allows Bind() to bind a non-refcounted class, and to disable
|
||||
// refcounting on arguments that are refcounted objects.
|
||||
//
|
||||
// Owned() transfers ownership of an object to the Callback resulting from
|
||||
// bind; the object will be deleted when the Callback is deleted.
|
||||
//
|
||||
// Passed() is for transferring movable-but-not-copyable types (eg. scoped_ptr)
|
||||
// through a Callback. Logically, this signifies a destructive transfer of
|
||||
// the state of the argument into the target function. Invoking
|
||||
// Callback::Run() twice on a Callback that was created with a Passed()
|
||||
// argument will CHECK() because the first invocation would have already
|
||||
// transferred ownership to the target function.
|
||||
//
|
||||
// ConstRef() allows binding a constant reference to an argument rather
|
||||
// than a copy.
|
||||
//
|
||||
// IgnoreResult() is used to adapt a function or Callback with a return type to
|
||||
// one with a void return. This is most useful if you have a function with,
|
||||
// say, a pesky ignorable bool return that you want to use with PostTask or
|
||||
// something else that expect a Callback with a void return.
|
||||
//
|
||||
// EXAMPLE OF Unretained():
|
||||
//
|
||||
// class Foo {
|
||||
// public:
|
||||
// void func() { cout << "Foo:f" << endl; }
|
||||
// };
|
||||
//
|
||||
// // In some function somewhere.
|
||||
// Foo foo;
|
||||
// Closure foo_callback =
|
||||
// Bind(&Foo::func, Unretained(&foo));
|
||||
// foo_callback.Run(); // Prints "Foo:f".
|
||||
//
|
||||
// Without the Unretained() wrapper on |&foo|, the above call would fail
|
||||
// to compile because Foo does not support the AddRef() and Release() methods.
|
||||
//
|
||||
//
|
||||
// EXAMPLE OF Owned():
|
||||
//
|
||||
// void foo(int* arg) { cout << *arg << endl }
|
||||
//
|
||||
// int* pn = new int(1);
|
||||
// Closure foo_callback = Bind(&foo, Owned(pn));
|
||||
//
|
||||
// foo_callback.Run(); // Prints "1"
|
||||
// foo_callback.Run(); // Prints "1"
|
||||
// *n = 2;
|
||||
// foo_callback.Run(); // Prints "2"
|
||||
//
|
||||
// foo_callback.Reset(); // |pn| is deleted. Also will happen when
|
||||
// // |foo_callback| goes out of scope.
|
||||
//
|
||||
// Without Owned(), someone would have to know to delete |pn| when the last
|
||||
// reference to the Callback is deleted.
|
||||
//
|
||||
//
|
||||
// EXAMPLE OF ConstRef():
|
||||
//
|
||||
// void foo(int arg) { cout << arg << endl }
|
||||
//
|
||||
// int n = 1;
|
||||
// Closure no_ref = Bind(&foo, n);
|
||||
// Closure has_ref = Bind(&foo, ConstRef(n));
|
||||
//
|
||||
// no_ref.Run(); // Prints "1"
|
||||
// has_ref.Run(); // Prints "1"
|
||||
//
|
||||
// n = 2;
|
||||
// no_ref.Run(); // Prints "1"
|
||||
// has_ref.Run(); // Prints "2"
|
||||
//
|
||||
// Note that because ConstRef() takes a reference on |n|, |n| must outlive all
|
||||
// its bound callbacks.
|
||||
//
|
||||
//
|
||||
// EXAMPLE OF IgnoreResult():
|
||||
//
|
||||
// int DoSomething(int arg) { cout << arg << endl; }
|
||||
//
|
||||
// // Assign to a Callback with a void return type.
|
||||
// Callback<void(int)> cb = Bind(IgnoreResult(&DoSomething));
|
||||
// cb->Run(1); // Prints "1".
|
||||
//
|
||||
// // Prints "1" on |ml|.
|
||||
// ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1);
|
||||
//
|
||||
//
|
||||
// EXAMPLE OF Passed():
|
||||
//
|
||||
// void TakesOwnership(scoped_ptr<Foo> arg) { }
|
||||
// scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); }
|
||||
//
|
||||
// scoped_ptr<Foo> f(new Foo());
|
||||
//
|
||||
// // |cb| is given ownership of Foo(). |f| is now NULL.
|
||||
// // 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
|
||||
// // it on Reset().
|
||||
// cb.Reset();
|
||||
//
|
||||
// // |cb| is given a new Foo created by CreateFoo().
|
||||
// cb = Bind(&TakesOwnership, Passed(CreateFoo()));
|
||||
//
|
||||
// // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
|
||||
// // no longer owns Foo() and, if reset, would not delete Foo().
|
||||
// cb.Run(); // Foo() is now transferred to |arg| and deleted.
|
||||
// cb.Run(); // This CHECK()s since Foo() already been used once.
|
||||
//
|
||||
// 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 TaskRunner.
|
||||
//
|
||||
//
|
||||
// SIMPLE FUNCTIONS AND UTILITIES.
|
||||
//
|
||||
// DoNothing() - Useful for creating a Closure that does nothing when called.
|
||||
// DeletePointer<T>() - Useful for creating a Closure that will delete a
|
||||
// pointer when invoked. Only use this when necessary.
|
||||
// In most cases MessageLoop::DeleteSoon() is a better
|
||||
// fit.
|
||||
|
||||
#ifndef BASE_BIND_HELPERS_H_
|
||||
#define BASE_BIND_HELPERS_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 {
|
||||
|
||||
// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T
|
||||
// for the existence of AddRef() and Release() functions of the correct
|
||||
// signature.
|
||||
//
|
||||
// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
|
||||
// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
|
||||
// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison
|
||||
// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
|
||||
//
|
||||
// The last link in particular show the method used below.
|
||||
//
|
||||
// For SFINAE to work with inherited methods, we need to pull some extra tricks
|
||||
// with multiple inheritance. In the more standard formulation, the overloads
|
||||
// of Check would be:
|
||||
//
|
||||
// template <typename C>
|
||||
// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*);
|
||||
//
|
||||
// template <typename C>
|
||||
// No NotTheCheckWeWant(...);
|
||||
//
|
||||
// static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes);
|
||||
//
|
||||
// The problem here is that template resolution will not match
|
||||
// C::TargetFunc if TargetFunc does not exist directly in C. That is, if
|
||||
// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match,
|
||||
// |value| will be false. This formulation only checks for whether or
|
||||
// not TargetFunc exist directly in the class being introspected.
|
||||
//
|
||||
// To get around this, we play a dirty trick with multiple inheritance.
|
||||
// First, We create a class BaseMixin that declares each function that we
|
||||
// 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().
|
||||
//
|
||||
// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
|
||||
// ambiguous resolution between BaseMixin and T. This lets us write the
|
||||
// following:
|
||||
//
|
||||
// template <typename C>
|
||||
// No GoodCheck(Helper<&C::TargetFunc>*);
|
||||
//
|
||||
// template <typename C>
|
||||
// Yes GoodCheck(...);
|
||||
//
|
||||
// static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes);
|
||||
//
|
||||
// Notice here that the variadic version of GoodCheck() returns Yes here
|
||||
// instead of No like the previous one. Also notice that we calculate |value|
|
||||
// by specializing GoodCheck() on Base instead of T.
|
||||
//
|
||||
// We've reversed the roles of the variadic, and Helper overloads.
|
||||
// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid
|
||||
// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve
|
||||
// to the variadic version if T has TargetFunc. If T::TargetFunc does not
|
||||
// exist, then &C::TargetFunc is not ambiguous, and the overload resolution
|
||||
// will prefer GoodCheck(Helper<&C::TargetFunc>*).
|
||||
//
|
||||
// This method of SFINAE will correctly probe for inherited names, but it cannot
|
||||
// typecheck those names. It's still a good enough sanity check though.
|
||||
//
|
||||
// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008.
|
||||
//
|
||||
// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted
|
||||
// this works well.
|
||||
//
|
||||
// TODO(ajwong): Make this check for Release() as well.
|
||||
// See http://crbug.com/82038.
|
||||
template <typename T>
|
||||
class SupportsAddRefAndRelease {
|
||||
using Yes = char[1];
|
||||
using No = char[2];
|
||||
|
||||
struct BaseMixin {
|
||||
void AddRef();
|
||||
};
|
||||
|
||||
// MSVC warns when you try to use Base if T has a private destructor, the
|
||||
// common pattern for refcounted types. It does this even though no attempt to
|
||||
// instantiate Base is made. We disable the warning for this definition.
|
||||
#if defined(OS_WIN)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4624)
|
||||
#endif
|
||||
struct Base : public T, public BaseMixin {
|
||||
};
|
||||
#if defined(OS_WIN)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <void(BaseMixin::*)()> struct Helper {};
|
||||
|
||||
template <typename C>
|
||||
static No& Check(Helper<&C::AddRef>*);
|
||||
|
||||
template <typename >
|
||||
static Yes& Check(...);
|
||||
|
||||
public:
|
||||
enum { value = sizeof(Check<Base>(0)) == sizeof(Yes) };
|
||||
};
|
||||
|
||||
// Helpers to assert that arguments of a recounted type are bound with a
|
||||
// scoped_refptr.
|
||||
template <bool IsClasstype, typename T>
|
||||
struct UnsafeBindtoRefCountedArgHelper : false_type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnsafeBindtoRefCountedArgHelper<true, T>
|
||||
: integral_constant<bool, SupportsAddRefAndRelease<T>::value> {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnsafeBindtoRefCountedArg : false_type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnsafeBindtoRefCountedArg<T*>
|
||||
: UnsafeBindtoRefCountedArgHelper<is_class<T>::value, T> {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class HasIsMethodTag {
|
||||
using Yes = char[1];
|
||||
using No = char[2];
|
||||
|
||||
template <typename U>
|
||||
static Yes& Check(typename U::IsMethod*);
|
||||
|
||||
template <typename U>
|
||||
static No& Check(...);
|
||||
|
||||
public:
|
||||
enum { value = sizeof(Check<T>(0)) == sizeof(Yes) };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class UnretainedWrapper {
|
||||
public:
|
||||
explicit UnretainedWrapper(T* o) : ptr_(o) {}
|
||||
T* get() const { return ptr_; }
|
||||
private:
|
||||
T* ptr_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ConstRefWrapper {
|
||||
public:
|
||||
explicit ConstRefWrapper(const T& o) : ptr_(&o) {}
|
||||
const T& get() const { return *ptr_; }
|
||||
private:
|
||||
const T* ptr_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IgnoreResultHelper {
|
||||
explicit IgnoreResultHelper(T functor) : functor_(functor) {}
|
||||
|
||||
T functor_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IgnoreResultHelper<Callback<T> > {
|
||||
explicit IgnoreResultHelper(const Callback<T>& functor) : functor_(functor) {}
|
||||
|
||||
const Callback<T>& functor_;
|
||||
};
|
||||
|
||||
// An alternate implementation is to avoid the destructive copy, and instead
|
||||
// specialize ParamTraits<> for OwnedWrapper<> to change the StorageType to
|
||||
// a class that is essentially a scoped_ptr<>.
|
||||
//
|
||||
// The current implementation has the benefit though of leaving ParamTraits<>
|
||||
// fully in callback_internal.h as well as avoiding type conversions during
|
||||
// storage.
|
||||
template <typename T>
|
||||
class OwnedWrapper {
|
||||
public:
|
||||
explicit OwnedWrapper(T* o) : ptr_(o) {}
|
||||
~OwnedWrapper() { delete ptr_; }
|
||||
T* get() const { return ptr_; }
|
||||
OwnedWrapper(const OwnedWrapper& other) {
|
||||
ptr_ = other.ptr_;
|
||||
other.ptr_ = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable T* ptr_;
|
||||
};
|
||||
|
||||
// PassedWrapper is a copyable adapter for a scoper that ignores const.
|
||||
//
|
||||
// It is needed to get around the fact that Bind() takes a const reference to
|
||||
// all its arguments. Because Bind() takes a const reference to avoid
|
||||
// unnecessary copies, it is incompatible with movable-but-not-copyable
|
||||
// types; doing a destructive "move" of the type into Bind() would violate
|
||||
// the const correctness.
|
||||
//
|
||||
// This conundrum cannot be solved without either C++11 rvalue references or
|
||||
// a O(2^n) blowup of Bind() templates to handle each combination of regular
|
||||
// types and movable-but-not-copyable types. Thus we introduce a wrapper type
|
||||
// that is copyable to transmit the correct type information down into
|
||||
// BindState<>. Ignoring const in this type makes sense because it is only
|
||||
// created when we are explicitly trying to do a destructive move.
|
||||
//
|
||||
// Two notes:
|
||||
// 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_(std::move(scoper)) {}
|
||||
PassedWrapper(const PassedWrapper& other)
|
||||
: is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
|
||||
T Pass() const {
|
||||
CHECK(is_valid_);
|
||||
is_valid_ = false;
|
||||
return std::move(scoper_);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable bool is_valid_;
|
||||
mutable T scoper_;
|
||||
};
|
||||
|
||||
// Unwrap the stored parameters for the wrappers above.
|
||||
template <typename T>
|
||||
struct UnwrapTraits {
|
||||
using ForwardType = const T&;
|
||||
static ForwardType Unwrap(const T& o) { return o; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<UnretainedWrapper<T> > {
|
||||
using ForwardType = T*;
|
||||
static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
|
||||
return unretained.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<ConstRefWrapper<T> > {
|
||||
using ForwardType = const T&;
|
||||
static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
|
||||
return const_ref.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<scoped_refptr<T> > {
|
||||
using ForwardType = T*;
|
||||
static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<WeakPtr<T> > {
|
||||
using ForwardType = const WeakPtr<T>&;
|
||||
static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<OwnedWrapper<T> > {
|
||||
using ForwardType = T*;
|
||||
static ForwardType Unwrap(const OwnedWrapper<T>& o) {
|
||||
return o.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<PassedWrapper<T> > {
|
||||
using ForwardType = T;
|
||||
static T Unwrap(PassedWrapper<T>& o) {
|
||||
return o.Pass();
|
||||
}
|
||||
};
|
||||
|
||||
// Utility for handling different refcounting semantics in the Bind()
|
||||
// function.
|
||||
template <bool is_method, typename... T>
|
||||
struct MaybeScopedRefPtr;
|
||||
|
||||
template <bool is_method>
|
||||
struct MaybeScopedRefPtr<is_method> {
|
||||
MaybeScopedRefPtr() {}
|
||||
};
|
||||
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<false, T, Rest...> {
|
||||
MaybeScopedRefPtr(const T&, const Rest&...) {}
|
||||
};
|
||||
|
||||
template <typename T, size_t n, typename... Rest>
|
||||
struct MaybeScopedRefPtr<false, T[n], Rest...> {
|
||||
MaybeScopedRefPtr(const T*, const Rest&...) {}
|
||||
};
|
||||
|
||||
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, typename... Rest>
|
||||
struct MaybeScopedRefPtr<true, scoped_refptr<T>, Rest...> {
|
||||
MaybeScopedRefPtr(const scoped_refptr<T>&, const Rest&...) {}
|
||||
};
|
||||
|
||||
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
|
||||
// method. It is used internally by Bind() to select the correct
|
||||
// InvokeHelper that will no-op itself in the event the WeakPtr<> for
|
||||
// the target object is invalidated.
|
||||
//
|
||||
// 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, typename... Args>
|
||||
struct IsWeakMethod<true, WeakPtr<T>, Args...> : 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
|
||||
|
||||
template <typename T>
|
||||
static inline internal::UnretainedWrapper<T> Unretained(T* o) {
|
||||
return internal::UnretainedWrapper<T>(o);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline internal::ConstRefWrapper<T> ConstRef(const T& o) {
|
||||
return internal::ConstRefWrapper<T>(o);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline internal::OwnedWrapper<T> Owned(T* o) {
|
||||
return internal::OwnedWrapper<T>(o);
|
||||
}
|
||||
|
||||
// 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,
|
||||
typename std::enable_if<internal::IsMoveOnlyType<T>::value>::type* =
|
||||
nullptr>
|
||||
static inline internal::PassedWrapper<T> Passed(T* scoper) {
|
||||
return internal::PassedWrapper<T>(std::move(*scoper));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
|
||||
return internal::IgnoreResultHelper<T>(data);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline internal::IgnoreResultHelper<Callback<T> >
|
||||
IgnoreResult(const Callback<T>& data) {
|
||||
return internal::IgnoreResultHelper<Callback<T> >(data);
|
||||
}
|
||||
|
||||
BASE_EXPORT void DoNothing();
|
||||
|
||||
template<typename T>
|
||||
void DeletePointer(T* obj) {
|
||||
delete obj;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BIND_HELPERS_H_
|
||||
@@ -1,425 +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_BIND_INTERNAL_H_
|
||||
#define BASE_BIND_INTERNAL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/bind_helpers.h"
|
||||
#include "base/callback_internal.h"
|
||||
#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/template_util.h"
|
||||
#include "base/tuple.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/bind_internal_win.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
// See base/callback.h for user documentation.
|
||||
//
|
||||
//
|
||||
// CONCEPTS:
|
||||
// Runnable -- A type (really a type class) that has a single Run() method
|
||||
// and a RunType typedef that corresponds to the type of Run().
|
||||
// A Runnable can declare that it should treated like a method
|
||||
// call by including a typedef named IsMethod. The value of
|
||||
// this typedef is NOT inspected, only the existence. When a
|
||||
// Runnable declares itself a method, Bind() will enforce special
|
||||
// refcounting + WeakPtr handling semantics for the first
|
||||
// parameter which is expected to be an object.
|
||||
// Functor -- A copyable type representing something that should be called.
|
||||
// All function pointers, Callback<>, and Runnables are functors
|
||||
// even if the invocation syntax differs.
|
||||
// RunType -- A function type (as opposed to function _pointer_ type) for
|
||||
// a Run() function. Usually just a convenience typedef.
|
||||
// (Bound)Args -- A set of types that stores the arguments.
|
||||
//
|
||||
// Types:
|
||||
// RunnableAdapter<> -- Wraps the various "function" pointer types into an
|
||||
// object that adheres to the Runnable interface.
|
||||
// ForceVoidReturn<> -- Helper class for translating function signatures to
|
||||
// equivalent forms with a "void" return type.
|
||||
// FunctorTraits<> -- Type traits used determine the correct RunType and
|
||||
// RunnableType for a Functor. This is where function
|
||||
// signature adapters are applied.
|
||||
// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
|
||||
// type class that represents the underlying Functor.
|
||||
// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
|
||||
// Handle the differing syntaxes needed for WeakPtr<>
|
||||
// support, and for ignoring return values. This is separate
|
||||
// from Invoker to avoid creating multiple version of
|
||||
// Invoker<>.
|
||||
// Invoker<> -- Unwraps the curried parameters and executes the Runnable.
|
||||
// BindState<> -- Stores the curried parameters, and is the main entry point
|
||||
// into the Bind() system, doing most of the type resolution.
|
||||
// There are ARITY BindState types.
|
||||
|
||||
// HasNonConstReferenceParam selects true_type when any of the parameters in
|
||||
// |Sig| is a non-const reference.
|
||||
// Implementation note: This non-specialized case handles zero-arity case only.
|
||||
// Non-zero-arity cases should be handled by the specialization below.
|
||||
template <typename List>
|
||||
struct HasNonConstReferenceItem : false_type {};
|
||||
|
||||
// Implementation note: Select true_type if the first parameter is a non-const
|
||||
// reference. Otherwise, skip the first parameter and check rest of parameters
|
||||
// recursively.
|
||||
template <typename T, typename... Args>
|
||||
struct HasNonConstReferenceItem<TypeList<T, Args...>>
|
||||
: std::conditional<is_non_const_reference<T>::value,
|
||||
true_type,
|
||||
HasNonConstReferenceItem<TypeList<Args...>>>::type {};
|
||||
|
||||
// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
|
||||
// pointer to a RefCounted type.
|
||||
// Implementation note: This non-specialized case handles zero-arity case only.
|
||||
// Non-zero-arity cases should be handled by the specialization below.
|
||||
template <typename... Args>
|
||||
struct HasRefCountedTypeAsRawPtr : false_type {};
|
||||
|
||||
// Implementation note: Select true_type if the first parameter is a raw pointer
|
||||
// to a RefCounted type. Otherwise, skip the first parameter and check rest of
|
||||
// parameters recursively.
|
||||
template <typename T, typename... Args>
|
||||
struct HasRefCountedTypeAsRawPtr<T, Args...>
|
||||
: std::conditional<NeedsScopedRefptrButGetsRawPtr<T>::value,
|
||||
true_type,
|
||||
HasRefCountedTypeAsRawPtr<Args...>>::type {};
|
||||
|
||||
// BindsArrayToFirstArg selects true_type when |is_method| is true and the first
|
||||
// item of |Args| is an array type.
|
||||
// Implementation note: This non-specialized case handles !is_method case and
|
||||
// zero-arity case only. Other cases should be handled by the specialization
|
||||
// below.
|
||||
template <bool is_method, typename... Args>
|
||||
struct BindsArrayToFirstArg : false_type {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct BindsArrayToFirstArg<true, T, Args...> : is_array<T> {};
|
||||
|
||||
// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except
|
||||
// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument.
|
||||
// Implementation note: This non-specialized case handles !is_method case and
|
||||
// zero-arity case only. Other cases should be handled by the specialization
|
||||
// below.
|
||||
template <bool is_method, typename... Args>
|
||||
struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr<Args...> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct HasRefCountedParamAsRawPtr<true, T, Args...>
|
||||
: HasRefCountedTypeAsRawPtr<Args...> {};
|
||||
|
||||
// RunnableAdapter<>
|
||||
//
|
||||
// The RunnableAdapter<> templates provide a uniform interface for invoking
|
||||
// a function pointer, method pointer, or const method pointer. The adapter
|
||||
// exposes a Run() method with an appropriate signature. Using this wrapper
|
||||
// allows for writing code that supports all three pointer types without
|
||||
// undue repetition. Without it, a lot of code would need to be repeated 3
|
||||
// times.
|
||||
//
|
||||
// For method pointers and const method pointers the first argument to Run()
|
||||
// is considered to be the received of the method. This is similar to STL's
|
||||
// mem_fun().
|
||||
//
|
||||
// This class also exposes a RunType typedef that is the function type of the
|
||||
// Run() function.
|
||||
//
|
||||
// If and only if the wrapper contains a method or const method pointer, an
|
||||
// IsMethod typedef is exposed. The existence of this typedef (NOT the value)
|
||||
// marks that the wrapper should be considered a method wrapper.
|
||||
|
||||
template <typename Functor>
|
||||
class RunnableAdapter;
|
||||
|
||||
// Function.
|
||||
template <typename R, typename... Args>
|
||||
class RunnableAdapter<R(*)(Args...)> {
|
||||
public:
|
||||
// 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(*function)(Args...))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
|
||||
return function_(CallbackForward(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
R (*function_)(Args...);
|
||||
};
|
||||
|
||||
// Method.
|
||||
template <typename R, typename T, typename... Args>
|
||||
class RunnableAdapter<R(T::*)(Args...)> {
|
||||
public:
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef R RunType(T*, Args...);
|
||||
using IsMethod = true_type;
|
||||
|
||||
explicit RunnableAdapter(R(T::*method)(Args...))
|
||||
: method_(method) {
|
||||
}
|
||||
|
||||
R Run(T* object, typename CallbackParamTraits<Args>::ForwardType... args) {
|
||||
return (object->*method_)(CallbackForward(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
R (T::*method_)(Args...);
|
||||
};
|
||||
|
||||
// Const Method.
|
||||
template <typename R, typename T, typename... Args>
|
||||
class RunnableAdapter<R(T::*)(Args...) const> {
|
||||
public:
|
||||
using RunType = R(const T*, Args...);
|
||||
using IsMethod = true_type;
|
||||
|
||||
explicit RunnableAdapter(R(T::*method)(Args...) const)
|
||||
: method_(method) {
|
||||
}
|
||||
|
||||
R Run(const T* object,
|
||||
typename CallbackParamTraits<Args>::ForwardType... args) {
|
||||
return (object->*method_)(CallbackForward(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
R (T::*method_)(Args...) const;
|
||||
};
|
||||
|
||||
|
||||
// ForceVoidReturn<>
|
||||
//
|
||||
// Set of templates that support forcing the function return type to void.
|
||||
template <typename Sig>
|
||||
struct ForceVoidReturn;
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct ForceVoidReturn<R(Args...)> {
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef void RunType(Args...);
|
||||
};
|
||||
|
||||
|
||||
// FunctorTraits<>
|
||||
//
|
||||
// See description at top of file.
|
||||
template <typename T>
|
||||
struct FunctorTraits {
|
||||
using RunnableType = RunnableAdapter<T>;
|
||||
using RunType = typename RunnableType::RunType;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FunctorTraits<IgnoreResultHelper<T>> {
|
||||
using RunnableType = typename FunctorTraits<T>::RunnableType;
|
||||
using RunType =
|
||||
typename ForceVoidReturn<typename RunnableType::RunType>::RunType;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FunctorTraits<Callback<T>> {
|
||||
using RunnableType = Callback<T> ;
|
||||
using RunType = typename Callback<T>::RunType;
|
||||
};
|
||||
|
||||
|
||||
// MakeRunnable<>
|
||||
//
|
||||
// Converts a passed in functor to a RunnableType using type inference.
|
||||
|
||||
template <typename T>
|
||||
typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) {
|
||||
return RunnableAdapter<T>(t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename FunctorTraits<T>::RunnableType
|
||||
MakeRunnable(const IgnoreResultHelper<T>& t) {
|
||||
return MakeRunnable(t.functor_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const typename FunctorTraits<Callback<T>>::RunnableType&
|
||||
MakeRunnable(const Callback<T>& t) {
|
||||
DCHECK(!t.is_null());
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
// InvokeHelper<>
|
||||
//
|
||||
// There are 3 logical InvokeHelper<> specializations: normal, void-return,
|
||||
// WeakCalls.
|
||||
//
|
||||
// The normal type just calls the underlying runnable.
|
||||
//
|
||||
// We need a InvokeHelper to handle void return types in order to support
|
||||
// IgnoreResult(). Normally, if the Runnable's RunType had a void return,
|
||||
// the template system would just accept "return functor.Run()" ignoring
|
||||
// the fact that a void function is being used with return. This piece of
|
||||
// sugar breaks though when the Runnable's RunType is not void. Thus, we
|
||||
// need a partial specialization to change the syntax to drop the "return"
|
||||
// from the invocation call.
|
||||
//
|
||||
// WeakCalls similarly need special syntax that is applied to the first
|
||||
// argument to check if they should no-op themselves.
|
||||
template <bool IsWeakCall, typename ReturnType, typename Runnable,
|
||||
typename ArgsType>
|
||||
struct InvokeHelper;
|
||||
|
||||
template <typename ReturnType, typename Runnable, typename... Args>
|
||||
struct InvokeHelper<false, ReturnType, Runnable, TypeList<Args...>> {
|
||||
static ReturnType MakeItSo(Runnable runnable, Args... args) {
|
||||
return runnable.Run(CallbackForward(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Runnable, typename... Args>
|
||||
struct InvokeHelper<false, void, Runnable, TypeList<Args...>> {
|
||||
static void MakeItSo(Runnable runnable, Args... args) {
|
||||
runnable.Run(CallbackForward(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Runnable, typename BoundWeakPtr, typename... Args>
|
||||
struct InvokeHelper<true, void, Runnable, TypeList<BoundWeakPtr, Args...>> {
|
||||
static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) {
|
||||
if (!weak_ptr.get()) {
|
||||
return;
|
||||
}
|
||||
runnable.Run(weak_ptr.get(), CallbackForward(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
|
||||
template <typename ReturnType, typename Runnable, typename ArgsType>
|
||||
struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
|
||||
// WeakCalls are only supported for functions with a void return type.
|
||||
// Otherwise, the function result would be undefined if the the WeakPtr<>
|
||||
// is invalidated.
|
||||
static_assert(is_void<ReturnType>::value,
|
||||
"weak_ptrs can only bind to methods without return values");
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// Invoker<>
|
||||
//
|
||||
// See description at the top of the file.
|
||||
template <typename BoundIndices,
|
||||
typename StorageType, typename Unwrappers,
|
||||
typename InvokeHelperType, typename UnboundForwardRunType>
|
||||
struct Invoker;
|
||||
|
||||
template <size_t... bound_indices,
|
||||
typename StorageType,
|
||||
typename... Unwrappers,
|
||||
typename InvokeHelperType,
|
||||
typename R,
|
||||
typename... UnboundForwardArgs>
|
||||
struct Invoker<IndexSequence<bound_indices...>,
|
||||
StorageType, TypeList<Unwrappers...>,
|
||||
InvokeHelperType, R(UnboundForwardArgs...)> {
|
||||
static R Run(BindStateBase* base,
|
||||
UnboundForwardArgs... unbound_args) {
|
||||
StorageType* storage = static_cast<StorageType*>(base);
|
||||
// Local references to make debugger stepping easier. If in a debugger,
|
||||
// you really want to warp ahead and step through the
|
||||
// InvokeHelper<>::MakeItSo() call below.
|
||||
return InvokeHelperType::MakeItSo(
|
||||
storage->runnable_,
|
||||
Unwrappers::Unwrap(get<bound_indices>(storage->bound_args_))...,
|
||||
CallbackForward(unbound_args)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// BindState<>
|
||||
//
|
||||
// This stores all the state passed into Bind() and is also where most
|
||||
// of the template resolution magic occurs.
|
||||
//
|
||||
// Runnable is the functor we are binding arguments to.
|
||||
// RunType is type of the Run() function that the Invoker<> should use.
|
||||
// Normally, this is the same as the RunType of the Runnable, but it can
|
||||
// be different if an adapter like IgnoreResult() has been used.
|
||||
//
|
||||
// BoundArgs contains the storage type for all the bound arguments.
|
||||
template <typename Runnable, typename RunType, typename... BoundArgs>
|
||||
struct BindState;
|
||||
|
||||
template <typename Runnable,
|
||||
typename R,
|
||||
typename... Args,
|
||||
typename... BoundArgs>
|
||||
struct BindState<Runnable, R(Args...), BoundArgs...> final
|
||||
: public BindStateBase {
|
||||
private:
|
||||
using StorageType = BindState<Runnable, R(Args...), BoundArgs...>;
|
||||
using RunnableType = Runnable;
|
||||
|
||||
// true_type if Runnable is a method invocation and the first bound argument
|
||||
// is a WeakPtr.
|
||||
using IsWeakCall =
|
||||
IsWeakMethod<HasIsMethodTag<Runnable>::value, BoundArgs...>;
|
||||
|
||||
using BoundIndices = MakeIndexSequence<sizeof...(BoundArgs)>;
|
||||
using Unwrappers = TypeList<UnwrapTraits<BoundArgs>...>;
|
||||
using UnboundForwardArgs = DropTypeListItem<
|
||||
sizeof...(BoundArgs),
|
||||
TypeList<typename CallbackParamTraits<Args>::ForwardType...>>;
|
||||
using UnboundForwardRunType = MakeFunctionType<R, UnboundForwardArgs>;
|
||||
|
||||
using InvokeHelperArgs = ConcatTypeLists<
|
||||
TypeList<typename UnwrapTraits<BoundArgs>::ForwardType...>,
|
||||
UnboundForwardArgs>;
|
||||
using InvokeHelperType =
|
||||
InvokeHelper<IsWeakCall::value, R, Runnable, InvokeHelperArgs>;
|
||||
|
||||
using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), TypeList<Args...>>;
|
||||
|
||||
public:
|
||||
using InvokerType = Invoker<BoundIndices, StorageType, Unwrappers,
|
||||
InvokeHelperType, UnboundForwardRunType>;
|
||||
using UnboundRunType = MakeFunctionType<R, UnboundArgs>;
|
||||
|
||||
BindState(const Runnable& runnable, const BoundArgs&... bound_args)
|
||||
: BindStateBase(&Destroy),
|
||||
runnable_(runnable),
|
||||
ref_(bound_args...),
|
||||
bound_args_(bound_args...) {}
|
||||
|
||||
RunnableType runnable_;
|
||||
MaybeScopedRefPtr<HasIsMethodTag<Runnable>::value, BoundArgs...> ref_;
|
||||
Tuple<BoundArgs...> bound_args_;
|
||||
|
||||
private:
|
||||
~BindState() {}
|
||||
|
||||
static void Destroy(BindStateBase* self) {
|
||||
delete static_cast<BindState*>(self);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BIND_INTERNAL_H_
|
||||
@@ -1,69 +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.
|
||||
|
||||
// Specializations of RunnableAdapter<> for Windows specific calling
|
||||
// conventions. Please see base/bind_internal.h for more info.
|
||||
|
||||
#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.
|
||||
#if !defined(ARCH_CPU_X86_64)
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
template <typename Functor>
|
||||
class RunnableAdapter;
|
||||
|
||||
// __stdcall Function.
|
||||
template <typename R, typename... Args>
|
||||
class RunnableAdapter<R(__stdcall *)(Args...)> {
|
||||
public:
|
||||
// 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) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
|
||||
return function_(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__stdcall *function_)(Args...);
|
||||
};
|
||||
|
||||
// __fastcall Function.
|
||||
template <typename R, typename... Args>
|
||||
class RunnableAdapter<R(__fastcall *)(Args...)> {
|
||||
public:
|
||||
// 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) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
|
||||
return function_(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__fastcall *function_)(Args...);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
#endif // !defined(ARCH_CPU_X86_64)
|
||||
|
||||
#endif // BASE_BIND_INTERNAL_WIN_H_
|
||||
@@ -1,71 +0,0 @@
|
||||
// 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,405 +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_CALLBACK_H_
|
||||
#define BASE_CALLBACK_H_
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/callback_internal.h"
|
||||
#include "base/template_util.h"
|
||||
|
||||
// NOTE: Header files that do not require the full definition of Callback or
|
||||
// Closure should #include "base/callback_forward.h" instead of this file.
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Introduction
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// The templated Callback class is a generalized function object. Together
|
||||
// with the Bind() function in bind.h, they provide a type-safe method for
|
||||
// performing partial application of functions.
|
||||
//
|
||||
// Partial application (or "currying") is the process of binding a subset of
|
||||
// a function's arguments to produce another function that takes fewer
|
||||
// arguments. This can be used to pass around a unit of delayed execution,
|
||||
// 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()>)
|
||||
// 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.
|
||||
//
|
||||
// MEMORY MANAGEMENT AND PASSING
|
||||
//
|
||||
// The Callback objects themselves should be passed by const-reference, and
|
||||
// stored by copy. They internally store their state via a refcounted class
|
||||
// and thus do not need to be deleted.
|
||||
//
|
||||
// The reason to pass via a const-reference is to avoid unnecessary
|
||||
// AddRef/Release pairs to the internal state.
|
||||
//
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Quick reference for basic stuff
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// BINDING A BARE FUNCTION
|
||||
//
|
||||
// int Return5() { return 5; }
|
||||
// base::Callback<int()> func_cb = base::Bind(&Return5);
|
||||
// LOG(INFO) << func_cb.Run(); // Prints 5.
|
||||
//
|
||||
// BINDING A CLASS METHOD
|
||||
//
|
||||
// The first argument to bind is the member function to call, the second is
|
||||
// the object on which to call it.
|
||||
//
|
||||
// class Ref : public base::RefCountedThreadSafe<Ref> {
|
||||
// public:
|
||||
// int Foo() { return 3; }
|
||||
// void PrintBye() { LOG(INFO) << "bye."; }
|
||||
// };
|
||||
// scoped_refptr<Ref> ref = new 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
|
||||
// error. If you're passing between threads, be sure it's
|
||||
// RefCountedThreadSafe! See "Advanced binding of member functions" below if
|
||||
// you don't want to use reference counting.
|
||||
//
|
||||
// RUNNING A CALLBACK
|
||||
//
|
||||
// Callbacks can be run with their "Run" method, which has the same
|
||||
// signature as the template argument to the callback.
|
||||
//
|
||||
// void DoSomething(const base::Callback<void(int, std::string)>& callback) {
|
||||
// callback.Run(5, "hello");
|
||||
// }
|
||||
//
|
||||
// Callbacks can be run more than once (they don't get deleted or marked when
|
||||
// run). However, this precludes using base::Passed (see below).
|
||||
//
|
||||
// void DoSomething(const base::Callback<double(double)>& callback) {
|
||||
// double myresult = callback.Run(3.14159);
|
||||
// myresult += callback.Run(2.71828);
|
||||
// }
|
||||
//
|
||||
// PASSING UNBOUND INPUT PARAMETERS
|
||||
//
|
||||
// Unbound parameters are specified at the time a callback is Run(). They are
|
||||
// specified in the Callback template type:
|
||||
//
|
||||
// void MyFunc(int i, const std::string& str) {}
|
||||
// base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
|
||||
// cb.Run(23, "hello, world");
|
||||
//
|
||||
// PASSING BOUND INPUT PARAMETERS
|
||||
//
|
||||
// Bound parameters are specified when you create thee callback as arguments
|
||||
// to Bind(). They will be passed to the function and the Run()ner of the
|
||||
// callback doesn't see those values or even know that the function it's
|
||||
// calling.
|
||||
//
|
||||
// void MyFunc(int i, const std::string& str) {}
|
||||
// base::Callback<void()> cb = base::Bind(&MyFunc, 23, "hello world");
|
||||
// cb.Run();
|
||||
//
|
||||
// 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");
|
||||
//
|
||||
// When calling member functions, bound parameters just go after the object
|
||||
// pointer.
|
||||
//
|
||||
// base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
|
||||
//
|
||||
// PARTIAL BINDING OF PARAMETERS
|
||||
//
|
||||
// You can specify some parameters when you create the callback, and specify
|
||||
// the rest when you execute the callback.
|
||||
//
|
||||
// void MyFunc(int i, const std::string& str) {}
|
||||
// base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
|
||||
// cb.Run("hello world");
|
||||
//
|
||||
// When calling a function bound parameters are first, followed by unbound
|
||||
// parameters.
|
||||
//
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Quick reference for advanced binding
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// BINDING A CLASS METHOD WITH WEAK POINTERS
|
||||
//
|
||||
// base::Bind(&MyClass::Foo, GetWeakPtr());
|
||||
//
|
||||
// The callback will not be run if the object has already been destroyed.
|
||||
// DANGER: weak pointers are not threadsafe, so don't use this
|
||||
// when passing between threads!
|
||||
//
|
||||
// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
|
||||
//
|
||||
// base::Bind(&MyClass::Foo, base::Unretained(this));
|
||||
//
|
||||
// This disables all lifetime management on the object. You're responsible
|
||||
// for making sure the object is alive at the time of the call. You break it,
|
||||
// you own it!
|
||||
//
|
||||
// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS
|
||||
//
|
||||
// MyClass* myclass = new MyClass;
|
||||
// base::Bind(&MyClass::Foo, base::Owned(myclass));
|
||||
//
|
||||
// The object will be deleted when the callback is destroyed, even if it's
|
||||
// not run (like if you post a task during shutdown). Potentially useful for
|
||||
// "fire and forget" cases.
|
||||
//
|
||||
// IGNORING RETURN VALUES
|
||||
//
|
||||
// Sometimes you want to call a function that returns a value in a callback
|
||||
// that doesn't expect a return value.
|
||||
//
|
||||
// int DoSomething(int arg) { cout << arg << endl; }
|
||||
// base::Callback<void(int)> cb =
|
||||
// base::Bind(base::IgnoreResult(&DoSomething));
|
||||
//
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Quick reference for binding parameters to Bind()
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// 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()> and base::Closure are the same thing).
|
||||
//
|
||||
// PASSING PARAMETERS OWNED BY THE CALLBACK
|
||||
//
|
||||
// void Foo(int* arg) { cout << *arg << endl; }
|
||||
// int* pn = new int(1);
|
||||
// base::Closure foo_callback = base::Bind(&foo, base::Owned(pn));
|
||||
//
|
||||
// The parameter will be deleted when the callback is destroyed, even if it's
|
||||
// not run (like if you post a task during shutdown).
|
||||
//
|
||||
// PASSING PARAMETERS AS A scoped_ptr
|
||||
//
|
||||
// void TakesOwnership(scoped_ptr<Foo> arg) {}
|
||||
// scoped_ptr<Foo> f(new Foo);
|
||||
// // f becomes null during the following call.
|
||||
// base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));
|
||||
//
|
||||
// Ownership of the parameter will be with the callback until the it is run,
|
||||
// when ownership is passed to the callback function. This means the callback
|
||||
// can only be run once. If the callback is never run, it will delete the
|
||||
// object when it's destroyed.
|
||||
//
|
||||
// PASSING PARAMETERS AS A scoped_refptr
|
||||
//
|
||||
// void TakesOneRef(scoped_refptr<Foo> arg) {}
|
||||
// scoped_refptr<Foo> f(new Foo)
|
||||
// base::Closure cb = base::Bind(&TakesOneRef, f);
|
||||
//
|
||||
// This should "just work." The closure will take a reference as long as it
|
||||
// is alive, and another reference will be taken for the called function.
|
||||
//
|
||||
// PASSING PARAMETERS BY REFERENCE
|
||||
//
|
||||
// Const references are *copied* unless ConstRef is used. Example:
|
||||
//
|
||||
// void foo(const int& arg) { printf("%d %p\n", arg, &arg); }
|
||||
// int n = 1;
|
||||
// base::Closure has_copy = base::Bind(&foo, n);
|
||||
// base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
|
||||
// n = 2;
|
||||
// foo(n); // Prints "2 0xaaaaaaaaaaaa"
|
||||
// has_copy.Run(); // Prints "1 0xbbbbbbbbbbbb"
|
||||
// has_ref.Run(); // Prints "2 0xaaaaaaaaaaaa"
|
||||
//
|
||||
// Normally parameters are copied in the closure. DANGER: ConstRef stores a
|
||||
// const reference instead, referencing the original parameter. This means
|
||||
// that you must ensure the object outlives the callback!
|
||||
//
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation notes
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// WHERE IS THIS DESIGN FROM:
|
||||
//
|
||||
// The design Callback and Bind is heavily influenced by C++'s
|
||||
// tr1::function/tr1::bind, and by the "Google Callback" system used inside
|
||||
// Google.
|
||||
//
|
||||
//
|
||||
// HOW THE IMPLEMENTATION WORKS:
|
||||
//
|
||||
// There are three main components to the system:
|
||||
// 1) The Callback classes.
|
||||
// 2) The Bind() functions.
|
||||
// 3) The arguments wrappers (e.g., Unretained() and ConstRef()).
|
||||
//
|
||||
// The Callback classes represent a generic function pointer. Internally,
|
||||
// it stores a refcounted piece of state that represents the target function
|
||||
// and all its bound parameters. Each Callback specialization has a templated
|
||||
// constructor that takes an BindState<>*. In the context of the constructor,
|
||||
// the static type of this BindState<> pointer uniquely identifies the
|
||||
// function it is representing, all its bound parameters, and a Run() method
|
||||
// that is capable of invoking the target.
|
||||
//
|
||||
// Callback's constructor takes the BindState<>* that has the full static type
|
||||
// and erases the target function type as well as the types of the bound
|
||||
// parameters. It does this by storing a pointer to the specific Run()
|
||||
// function, and upcasting the state of BindState<>* to a
|
||||
// BindStateBase*. This is safe as long as this BindStateBase pointer
|
||||
// is only used with the stored Run() pointer.
|
||||
//
|
||||
// To BindState<> objects are created inside the Bind() functions.
|
||||
// These functions, along with a set of internal templates, are responsible for
|
||||
//
|
||||
// - Unwrapping the function signature into return type, and parameters
|
||||
// - Determining the number of parameters that are bound
|
||||
// - Creating the BindState storing the bound parameters
|
||||
// - Performing compile-time asserts to avoid error-prone behavior
|
||||
// - Returning an Callback<> with an arity matching the number of unbound
|
||||
// parameters and that knows the correct refcounting semantics for the
|
||||
// target object if we are binding a method.
|
||||
//
|
||||
// The Bind functions do the above using type-inference, and template
|
||||
// specializations.
|
||||
//
|
||||
// By default Bind() will store copies of all bound parameters, and attempt
|
||||
// to refcount a target object if the function being bound is a class method.
|
||||
// These copies are created even if the function takes parameters as const
|
||||
// references. (Binding to non-const references is forbidden, see bind.h.)
|
||||
//
|
||||
// To change this behavior, we introduce a set of argument wrappers
|
||||
// (e.g., Unretained(), and ConstRef()). These are simple container templates
|
||||
// that are passed by value, and wrap a pointer to argument. See the
|
||||
// file-level comment in base/bind_helpers.h for more info.
|
||||
//
|
||||
// These types are passed to the Unwrap() functions, and the MaybeRefcount()
|
||||
// functions respectively to modify the behavior of Bind(). The Unwrap()
|
||||
// and MaybeRefcount() functions change behavior by doing partial
|
||||
// specialization based on whether or not a parameter is a wrapper type.
|
||||
//
|
||||
// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium.
|
||||
//
|
||||
//
|
||||
// WHY NOT TR1 FUNCTION/BIND?
|
||||
//
|
||||
// Direct use of tr1::function and tr1::bind was considered, but ultimately
|
||||
// rejected because of the number of copy constructors invocations involved
|
||||
// in the binding of arguments during construction, and the forwarding of
|
||||
// arguments during invocation. These copies will no longer be an issue in
|
||||
// C++0x because C++0x will support rvalue reference allowing for the compiler
|
||||
// to avoid these copies. However, waiting for C++0x is not an option.
|
||||
//
|
||||
// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
|
||||
// tr1::bind call itself will invoke a non-trivial copy constructor three times
|
||||
// for each bound parameter. Also, each when passing a tr1::function, each
|
||||
// bound argument will be copied again.
|
||||
//
|
||||
// In addition to the copies taken at binding and invocation, copying a
|
||||
// tr1::function causes a copy to be made of all the bound parameters and
|
||||
// state.
|
||||
//
|
||||
// Furthermore, in Chromium, it is desirable for the Callback to take a
|
||||
// reference on a target object when representing a class method call. This
|
||||
// is not supported by tr1.
|
||||
//
|
||||
// Lastly, tr1::function and tr1::bind has a more general and flexible API.
|
||||
// This includes things like argument reordering by use of
|
||||
// tr1::bind::placeholder, support for non-const reference parameters, and some
|
||||
// limited amount of subtyping of the tr1::function object (e.g.,
|
||||
// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
|
||||
//
|
||||
// These are not features that are required in Chromium. Some of them, such as
|
||||
// allowing for reference parameters, and subtyping of functions, may actually
|
||||
// become a source of errors. Removing support for these features actually
|
||||
// allows for a simpler implementation, and a terser Currying API.
|
||||
//
|
||||
//
|
||||
// WHY NOT GOOGLE CALLBACKS?
|
||||
//
|
||||
// The Google callback system also does not support refcounting. Furthermore,
|
||||
// its implementation has a number of strange edge cases with respect to type
|
||||
// conversion of its arguments. In particular, the argument's constness must
|
||||
// at times match exactly the function signature, or the type-inference might
|
||||
// break. Given the above, writing a custom solution was easier.
|
||||
//
|
||||
//
|
||||
// MISSING FUNCTIONALITY
|
||||
// - Invoking the return of Bind. Bind(&foo).Run() does not work;
|
||||
// - Binding arrays to functions that take a non-const pointer.
|
||||
// Example:
|
||||
// void Foo(const char* ptr);
|
||||
// void Bar(char* ptr);
|
||||
// Bind(&Foo, "test");
|
||||
// Bind(&Bar, "test"); // This fails because ptr is not const.
|
||||
|
||||
namespace base {
|
||||
|
||||
// First, we forward declare the Callback class template. This informs the
|
||||
// compiler that the template only has 1 type parameter which is the function
|
||||
// signature that the Callback is representing.
|
||||
//
|
||||
// After this, create template specializations for 0-7 parameters. Note that
|
||||
// even though the template typelist grows, the specialization still
|
||||
// only has one type: the function signature.
|
||||
//
|
||||
// If you are thinking of forward declaring Callback in your own header file,
|
||||
// please include "base/callback_forward.h" instead.
|
||||
|
||||
namespace internal {
|
||||
template <typename Runnable, typename RunType, typename... BoundArgsType>
|
||||
struct BindState;
|
||||
} // namespace internal
|
||||
|
||||
template <typename R, typename... Args>
|
||||
class Callback<R(Args...)> : public internal::CallbackBase {
|
||||
public:
|
||||
// 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(nullptr) { }
|
||||
|
||||
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...>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args)
|
||||
const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
using PolymorphicInvoke =
|
||||
R(*)(internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<Args>::ForwardType...);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CALLBACK_H_
|
||||
@@ -1,19 +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_CALLBACK_FORWARD_H_
|
||||
#define BASE_CALLBACK_FORWARD_H_
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Sig>
|
||||
class Callback;
|
||||
|
||||
// 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_
|
||||
@@ -1,46 +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.
|
||||
|
||||
#include "base/callback_internal.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
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
|
||||
// object owns us, and we may be deleted after that.
|
||||
bind_state_ = NULL;
|
||||
}
|
||||
|
||||
bool CallbackBase::Equals(const CallbackBase& other) const {
|
||||
return bind_state_.get() == other.bind_state_.get() &&
|
||||
polymorphic_invoke_ == other.polymorphic_invoke_;
|
||||
}
|
||||
|
||||
CallbackBase::CallbackBase(BindStateBase* bind_state)
|
||||
: bind_state_(bind_state),
|
||||
polymorphic_invoke_(NULL) {
|
||||
DCHECK(!bind_state_.get() || bind_state_->ref_count_ == 1);
|
||||
}
|
||||
|
||||
CallbackBase::~CallbackBase() {
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
@@ -1,234 +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.
|
||||
|
||||
// This file contains utility functions and classes that help the
|
||||
// implementation, and management of the Callback objects.
|
||||
|
||||
#ifndef BASE_CALLBACK_INTERNAL_H_
|
||||
#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"
|
||||
#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
|
||||
// behaves as an existential type that is used by a corresponding
|
||||
// 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."
|
||||
// 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:
|
||||
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; }
|
||||
|
||||
// Returns the Callback into an uninitialized state.
|
||||
void Reset();
|
||||
|
||||
protected:
|
||||
// In C++, it is safe to cast function pointers to function pointers of
|
||||
// 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.
|
||||
using InvokeFuncStorage = void(*)();
|
||||
|
||||
// Returns true if this callback equals |other|. |other| may be null.
|
||||
bool Equals(const CallbackBase& other) const;
|
||||
|
||||
// Allow initializing of |bind_state_| via the constructor to avoid default
|
||||
// initialization of the scoped_refptr. We do not also initialize
|
||||
// |polymorphic_invoke_| here because doing a normal assignment in the
|
||||
// derived Callback templates makes for much nicer compiler errors.
|
||||
explicit CallbackBase(BindStateBase* bind_state);
|
||||
|
||||
// Force the destructor to be instantiated inside this translation unit so
|
||||
// that our subclasses will not get inlined versions. Avoids more template
|
||||
// bloat.
|
||||
~CallbackBase();
|
||||
|
||||
scoped_refptr<BindStateBase> bind_state_;
|
||||
InvokeFuncStorage polymorphic_invoke_;
|
||||
};
|
||||
|
||||
// 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 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*);
|
||||
|
||||
template <typename U>
|
||||
static NoType Test(...);
|
||||
|
||||
static const bool value = sizeof((Test<T>(0))) == sizeof(YesType) &&
|
||||
!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.
|
||||
//
|
||||
// In particular, it strips off references, and converts arrays to
|
||||
// pointers for storage; and it avoids accidentally trying to create a
|
||||
// "reference of a reference" if the argument is a reference type.
|
||||
//
|
||||
// This array type becomes an issue for storage because we are passing bound
|
||||
// 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>
|
||||
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
|
||||
// specifies type of the bind parameters. However, in case they do,
|
||||
// this will guard against us accidentally storing a reference parameter.
|
||||
//
|
||||
// The ForwardType should only be used for unbound arguments.
|
||||
template <typename T>
|
||||
struct CallbackParamTraitsForNonMoveOnlyType<T&> {
|
||||
using ForwardType = T&;
|
||||
using StorageType = T;
|
||||
};
|
||||
|
||||
// Note that for array types, we implicitly add a const in the conversion. This
|
||||
// means that it is not possible to bind array arguments to functions that take
|
||||
// a non-const pointer. Trying to specialize the template based on a "const
|
||||
// T[n]" does not seem to match correctly, so we are stuck with this
|
||||
// restriction.
|
||||
template <typename T, size_t n>
|
||||
struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
|
||||
using ForwardType = const T*;
|
||||
using StorageType = const T*;
|
||||
};
|
||||
|
||||
// See comment for CallbackParamTraits<T[n]>.
|
||||
template <typename T>
|
||||
struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
|
||||
using ForwardType = const T*;
|
||||
using StorageType = const T*;
|
||||
};
|
||||
|
||||
// Parameter traits for movable-but-not-copyable scopers.
|
||||
//
|
||||
// Callback<>/Bind() understands movable-but-not-copyable semantics where
|
||||
// the type cannot be copied but can still have its state destructively
|
||||
// transferred (aka. moved) to another instance of the same type by calling a
|
||||
// helper function. When used with Bind(), this signifies transferal of the
|
||||
// object's state to the target function.
|
||||
//
|
||||
// For these types, the ForwardType must not be a const reference, or a
|
||||
// reference. A const reference is inappropriate, and would break const
|
||||
// correctness, because we are implementing a destructive move. A non-const
|
||||
// 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 CallbackParamTraitsForMoveOnlyType {
|
||||
using ForwardType = T;
|
||||
using StorageType = T;
|
||||
};
|
||||
|
||||
// CallbackForward() is a very limited simulation of C++11's std::forward()
|
||||
// used by the Callback/Bind system for a set of movable-but-not-copyable
|
||||
// types. It is needed because forwarding a movable-but-not-copyable
|
||||
// argument to another function requires us to invoke the proper move
|
||||
// operator to create a rvalue version of the type. The supported types are
|
||||
// whitelisted below as overloads of the CallbackForward() function. The
|
||||
// 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 without C++11 due to a lack
|
||||
// of rvalue references.
|
||||
//
|
||||
// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
|
||||
// simulate std::forward() and forward the result of one Callback as a
|
||||
// parameter to another callback. This is to support Callbacks that return
|
||||
// the movable-but-not-copyable types whitelisted above.
|
||||
template <typename T>
|
||||
typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(
|
||||
T& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(
|
||||
T& t) {
|
||||
return std::move(t);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CALLBACK_INTERNAL_H_
|
||||
@@ -1,190 +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_COMPILER_SPECIFIC_H_
|
||||
#define BASE_COMPILER_SPECIFIC_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
|
||||
// For _Printf_format_string_.
|
||||
#include <sal.h>
|
||||
|
||||
// Macros for suppressing and disabling warnings on MSVC.
|
||||
//
|
||||
// Warning numbers are enumerated at:
|
||||
// http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx
|
||||
//
|
||||
// The warning pragma:
|
||||
// http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx
|
||||
//
|
||||
// Using __pragma instead of #pragma inside macros:
|
||||
// http://msdn.microsoft.com/en-us/library/d9x1s805.aspx
|
||||
|
||||
// MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and
|
||||
// for the next line of the source file.
|
||||
#define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n))
|
||||
|
||||
// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled.
|
||||
// The warning remains disabled until popped by MSVC_POP_WARNING.
|
||||
#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
|
||||
__pragma(warning(disable:n))
|
||||
|
||||
// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level. The level
|
||||
// remains in effect until popped by MSVC_POP_WARNING(). Use 0 to disable all
|
||||
// warnings.
|
||||
#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n))
|
||||
|
||||
// Pop effects of innermost MSVC_PUSH_* macro.
|
||||
#define MSVC_POP_WARNING() __pragma(warning(pop))
|
||||
|
||||
#define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off))
|
||||
#define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on))
|
||||
|
||||
// Allows exporting a class that inherits from a non-exported base class.
|
||||
// This uses suppress instead of push/pop because the delimiter after the
|
||||
// declaration (either "," or "{") has to be placed before the pop macro.
|
||||
//
|
||||
// Example usage:
|
||||
// class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) {
|
||||
//
|
||||
// MSVC Compiler warning C4275:
|
||||
// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'.
|
||||
// Note that this is intended to be used only when no access to the base class'
|
||||
// static data is done through derived classes or inline methods. For more info,
|
||||
// see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
|
||||
#define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \
|
||||
code
|
||||
|
||||
#else // Not MSVC
|
||||
|
||||
#define _Printf_format_string_
|
||||
#define MSVC_SUPPRESS_WARNING(n)
|
||||
#define MSVC_PUSH_DISABLE_WARNING(n)
|
||||
#define MSVC_PUSH_WARNING_LEVEL(n)
|
||||
#define MSVC_POP_WARNING()
|
||||
#define MSVC_DISABLE_OPTIMIZE()
|
||||
#define MSVC_ENABLE_OPTIMIZE()
|
||||
#define NON_EXPORTED_BASE(code) code
|
||||
|
||||
#endif // COMPILER_MSVC
|
||||
|
||||
|
||||
// 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.)
|
||||
// Use like:
|
||||
// int x = ...;
|
||||
// ALLOW_UNUSED_LOCAL(x);
|
||||
#define ALLOW_UNUSED_LOCAL(x) false ? (void)x : (void)0
|
||||
|
||||
// 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) || defined(__clang__)
|
||||
#define ALLOW_UNUSED_TYPE __attribute__((unused))
|
||||
#else
|
||||
#define ALLOW_UNUSED_TYPE
|
||||
#endif
|
||||
|
||||
// Annotate a function indicating it should not be inlined.
|
||||
// Use like:
|
||||
// NOINLINE void DoStuff() { ... }
|
||||
#if defined(COMPILER_GCC)
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
#elif defined(COMPILER_MSVC)
|
||||
#define NOINLINE __declspec(noinline)
|
||||
#else
|
||||
#define NOINLINE
|
||||
#endif
|
||||
|
||||
// Specify memory alignment for structs, classes, etc.
|
||||
// Use like:
|
||||
// class ALIGNAS(16) MyClass { ... }
|
||||
// ALIGNAS(16) int array[4];
|
||||
#if defined(COMPILER_MSVC)
|
||||
#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
|
||||
#elif defined(COMPILER_GCC)
|
||||
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
|
||||
#endif
|
||||
|
||||
// Return the byte alignment of the given type (available at compile time).
|
||||
// Use like:
|
||||
// ALIGNOF(int32_t) // this would be 4
|
||||
#if defined(COMPILER_MSVC)
|
||||
#define ALIGNOF(type) __alignof(type)
|
||||
#elif defined(COMPILER_GCC)
|
||||
#define ALIGNOF(type) __alignof__(type)
|
||||
#endif
|
||||
|
||||
// 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/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
|
||||
#endif
|
||||
|
||||
// Tell the compiler a function is using a printf-style format string.
|
||||
// |format_param| is the one-based index of the format string parameter;
|
||||
// |dots_param| is the one-based index of the "..." parameter.
|
||||
// For v*printf functions (which take a va_list), pass 0 for dots_param.
|
||||
// (This is undocumented but matches what the system C headers do.)
|
||||
#if defined(COMPILER_GCC)
|
||||
#define PRINTF_FORMAT(format_param, dots_param) \
|
||||
__attribute__((format(printf, format_param, dots_param)))
|
||||
#else
|
||||
#define PRINTF_FORMAT(format_param, dots_param)
|
||||
#endif
|
||||
|
||||
// WPRINTF_FORMAT is the same, but for wide format strings.
|
||||
// This doesn't appear to yet be implemented in any compiler.
|
||||
// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 .
|
||||
#define WPRINTF_FORMAT(format_param, dots_param)
|
||||
// If available, it would look like:
|
||||
// __attribute__((format(wprintf, format_param, dots_param)))
|
||||
|
||||
// MemorySanitizer annotations.
|
||||
#if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
|
||||
#include <sanitizer/msan_interface.h>
|
||||
|
||||
// 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, 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, size)
|
||||
#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
|
||||
#endif // MEMORY_SANITIZER
|
||||
|
||||
// Macro useful for writing cross-platform function pointers.
|
||||
#if !defined(CDECL)
|
||||
#if defined(OS_WIN)
|
||||
#define CDECL __cdecl
|
||||
#else // defined(OS_WIN)
|
||||
#define CDECL
|
||||
#endif // defined(OS_WIN)
|
||||
#endif // !defined(CDECL)
|
||||
|
||||
// Macro for hinting that an expression is likely to be false.
|
||||
#if !defined(UNLIKELY)
|
||||
#if defined(COMPILER_GCC)
|
||||
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define UNLIKELY(x) (x)
|
||||
#endif // defined(COMPILER_GCC)
|
||||
#endif // !defined(UNLIKELY)
|
||||
|
||||
#endif // BASE_COMPILER_SPECIFIC_H_
|
||||
@@ -1,281 +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.
|
||||
//
|
||||
|
||||
//
|
||||
// Deal with the differences between Microsoft and GNU implemenations
|
||||
// of hash_map. Allows all platforms to use |base::hash_map| and
|
||||
// |base::hash_set|.
|
||||
// eg:
|
||||
// base::hash_map<int> my_map;
|
||||
// base::hash_set<int> my_set;
|
||||
//
|
||||
// NOTE: It is an explicit non-goal of this class to provide a generic hash
|
||||
// function for pointers. If you want to hash a pointers to a particular class,
|
||||
// please define the template specialization elsewhere (for example, in its
|
||||
// header file) and keep it specific to just pointers to that class. This is
|
||||
// because identity hashes are not desirable for all types that might show up
|
||||
// in containers as pointers.
|
||||
|
||||
#ifndef BASE_CONTAINERS_HASH_TABLES_H_
|
||||
#define BASE_CONTAINERS_HASH_TABLES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/strings/string16.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#define BASE_HASH_NAMESPACE std
|
||||
|
||||
#elif defined(COMPILER_GCC)
|
||||
|
||||
#define BASE_HASH_NAMESPACE base_hash
|
||||
|
||||
// This is a hack to disable the gcc 4.4 warning about hash_map and hash_set
|
||||
// being deprecated. We can get rid of this when we upgrade to VS2008 and we
|
||||
// can use <tr1/unordered_map> and <tr1/unordered_set>.
|
||||
#ifdef __DEPRECATED
|
||||
#define CHROME_OLD__DEPRECATED __DEPRECATED
|
||||
#undef __DEPRECATED
|
||||
#endif
|
||||
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
#define BASE_HASH_IMPL_NAMESPACE __gnu_cxx
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef CHROME_OLD__DEPRECATED
|
||||
#define __DEPRECATED CHROME_OLD__DEPRECATED
|
||||
#undef CHROME_OLD__DEPRECATED
|
||||
#endif
|
||||
|
||||
namespace BASE_HASH_NAMESPACE {
|
||||
|
||||
// The pre-standard hash behaves like C++11's std::hash, except around pointers.
|
||||
// const char* is specialized to hash the C string and hash functions for
|
||||
// general T* are missing. Define a BASE_HASH_NAMESPACE::hash which aligns with
|
||||
// the C++11 behavior.
|
||||
|
||||
template<typename T>
|
||||
struct hash {
|
||||
std::size_t operator()(const T& value) const {
|
||||
return BASE_HASH_IMPL_NAMESPACE::hash<T>()(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct hash<T*> {
|
||||
std::size_t operator()(T* value) const {
|
||||
return BASE_HASH_IMPL_NAMESPACE::hash<uintptr_t>()(
|
||||
reinterpret_cast<uintptr_t>(value));
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
// use it for.
|
||||
|
||||
#define DEFINE_TRIVIAL_HASH(integral_type) \
|
||||
template<> \
|
||||
struct hash<integral_type> { \
|
||||
std::size_t operator()(integral_type value) const { \
|
||||
return static_cast<std::size_t>(value); \
|
||||
} \
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_HASH(long long);
|
||||
DEFINE_TRIVIAL_HASH(unsigned long long);
|
||||
|
||||
#undef DEFINE_TRIVIAL_HASH
|
||||
|
||||
// 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
|
||||
// GNU C++ library, in <tr1/functional>. It is duplicated here because GCC
|
||||
// versions prior to 4.3.2 are unable to compile <tr1/functional> when RTTI
|
||||
// is disabled, as it is in our build.
|
||||
|
||||
#define DEFINE_STRING_HASH(string_type) \
|
||||
template<> \
|
||||
struct hash<string_type> { \
|
||||
std::size_t operator()(const string_type& s) const { \
|
||||
std::size_t result = 0; \
|
||||
for (string_type::const_iterator i = s.begin(); i != s.end(); ++i) \
|
||||
result = (result * 131) + *i; \
|
||||
return result; \
|
||||
} \
|
||||
}
|
||||
|
||||
DEFINE_STRING_HASH(std::string);
|
||||
DEFINE_STRING_HASH(base::string16);
|
||||
|
||||
#undef DEFINE_STRING_HASH
|
||||
|
||||
} // namespace BASE_HASH_NAMESPACE
|
||||
|
||||
#else // COMPILER
|
||||
#error define BASE_HASH_NAMESPACE for your compiler
|
||||
#endif // COMPILER
|
||||
|
||||
namespace base {
|
||||
|
||||
// On MSVC, use the C++11 containers.
|
||||
#if defined(COMPILER_MSVC)
|
||||
|
||||
template<class Key, class T,
|
||||
class Hash = std::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<std::pair<const Key, T>>>
|
||||
using hash_map = std::unordered_map<Key, T, Hash, Pred, Alloc>;
|
||||
|
||||
template<class Key, class T,
|
||||
class Hash = std::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<std::pair<const Key, T>>>
|
||||
using hash_multimap = std::unordered_multimap<Key, T, Hash, Pred, Alloc>;
|
||||
|
||||
template<class Key,
|
||||
class Hash = std::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<Key>>
|
||||
using hash_multiset = std::unordered_multiset<Key, Hash, Pred, Alloc>;
|
||||
|
||||
template<class Key,
|
||||
class Hash = std::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<Key>>
|
||||
using hash_set = std::unordered_set<Key, Hash, Pred, Alloc>;
|
||||
|
||||
#else // !COMPILER_MSVC
|
||||
|
||||
// Otherwise, use the pre-standard ones, but override the default hash to match
|
||||
// C++11.
|
||||
template<class Key, class T,
|
||||
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<std::pair<const Key, T>>>
|
||||
using hash_map = BASE_HASH_IMPL_NAMESPACE::hash_map<Key, T, Hash, Pred, Alloc>;
|
||||
|
||||
template<class Key, class T,
|
||||
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<std::pair<const Key, T>>>
|
||||
using hash_multimap =
|
||||
BASE_HASH_IMPL_NAMESPACE::hash_multimap<Key, T, Hash, Pred, Alloc>;
|
||||
|
||||
template<class Key,
|
||||
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<Key>>
|
||||
using hash_multiset =
|
||||
BASE_HASH_IMPL_NAMESPACE::hash_multiset<Key, Hash, Pred, Alloc>;
|
||||
|
||||
template<class Key,
|
||||
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<Key>>
|
||||
using hash_set = BASE_HASH_IMPL_NAMESPACE::hash_set<Key, Hash, Pred, Alloc>;
|
||||
|
||||
#undef BASE_HASH_IMPL_NAMESPACE
|
||||
|
||||
#endif // COMPILER_MSVC
|
||||
|
||||
// Implement hashing for pairs of at-most 32 bit integer values.
|
||||
// When size_t is 32 bits, we turn the 64-bit hash code into 32 bits by using
|
||||
// multiply-add hashing. This algorithm, as described in
|
||||
// Theorem 4.3.3 of the thesis "Über die Komplexität der Multiplikation in
|
||||
// eingeschränkten Branchingprogrammmodellen" by Woelfel, is:
|
||||
//
|
||||
// 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_t value1, uint32_t value2) {
|
||||
uint64_t value1_64 = value1;
|
||||
uint64_t hash64 = (value1_64 << 32) | value2;
|
||||
|
||||
if (sizeof(std::size_t) >= sizeof(uint64_t))
|
||||
return static_cast<std::size_t>(hash64);
|
||||
|
||||
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_t) - sizeof(std::size_t))));
|
||||
return high_bits;
|
||||
}
|
||||
|
||||
// Implement hashing for pairs of up-to 64-bit integer values.
|
||||
// We use the compound integer hash method to produce a 64-bit hash code, by
|
||||
// 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_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_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_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_t hash64 = product1 + product2 + product3 + product4;
|
||||
|
||||
if (sizeof(std::size_t) >= sizeof(uint64_t))
|
||||
return static_cast<std::size_t>(hash64);
|
||||
|
||||
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_t) - sizeof(std::size_t))));
|
||||
return high_bits;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
namespace BASE_HASH_NAMESPACE {
|
||||
|
||||
// Implement methods for hashing a pair of integers, so they can be used as
|
||||
// keys in STL containers.
|
||||
|
||||
template<typename Type1, typename Type2>
|
||||
struct hash<std::pair<Type1, Type2> > {
|
||||
std::size_t operator()(std::pair<Type1, Type2> value) const {
|
||||
return base::HashPair(value.first, value.second);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace BASE_HASH_NAMESPACE
|
||||
|
||||
#undef DEFINE_PAIR_HASH_FUNCTION_START
|
||||
#undef DEFINE_PAIR_HASH_FUNCTION_END
|
||||
|
||||
#endif // BASE_CONTAINERS_HASH_TABLES_H_
|
||||
@@ -1,296 +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.
|
||||
|
||||
#include "base/cpu.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/lazy_instance.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#include <immintrin.h> // For _xgetbv()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
CPU::CPU()
|
||||
: signature_(0),
|
||||
type_(0),
|
||||
family_(0),
|
||||
model_(0),
|
||||
stepping_(0),
|
||||
ext_model_(0),
|
||||
ext_family_(0),
|
||||
has_mmx_(false),
|
||||
has_sse_(false),
|
||||
has_sse2_(false),
|
||||
has_sse3_(false),
|
||||
has_ssse3_(false),
|
||||
has_sse41_(false),
|
||||
has_sse42_(false),
|
||||
has_avx_(false),
|
||||
has_avx2_(false),
|
||||
has_aesni_(false),
|
||||
has_non_stop_time_stamp_counter_(false),
|
||||
has_broken_neon_(false),
|
||||
cpu_vendor_("unknown") {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
#ifndef _MSC_VER
|
||||
|
||||
#if defined(__pic__) && defined(__i386__)
|
||||
|
||||
void __cpuid(int cpu_info[4], int info_type) {
|
||||
__asm__ volatile (
|
||||
"mov %%ebx, %%edi\n"
|
||||
"cpuid\n"
|
||||
"xchg %%edi, %%ebx\n"
|
||||
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
|
||||
: "a"(info_type)
|
||||
);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void __cpuid(int cpu_info[4], int info_type) {
|
||||
__asm__ volatile (
|
||||
"cpuid\n"
|
||||
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
|
||||
: "a"(info_type)
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// _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_t _xgetbv(uint32_t xcr) {
|
||||
uint32_t eax, edx;
|
||||
|
||||
__asm__ volatile (
|
||||
"xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
|
||||
return (static_cast<uint64_t>(edx) << 32) | eax;
|
||||
}
|
||||
|
||||
#endif // !_MSC_VER
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
||||
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
|
||||
class LazyCpuInfoValue {
|
||||
public:
|
||||
LazyCpuInfoValue() : has_broken_neon_(false) {
|
||||
// This function finds the value from /proc/cpuinfo under the key "model
|
||||
// name" or "Processor". "model name" is used in Linux 3.8 and later (3.7
|
||||
// and later for arm64) and is shown once per CPU. "Processor" is used in
|
||||
// earler versions and is shown only once at the top of /proc/cpuinfo
|
||||
// regardless of the number CPUs.
|
||||
const char kModelNamePrefix[] = "model name\t: ";
|
||||
const char kProcessorPrefix[] = "Processor\t: ";
|
||||
|
||||
// This function also calculates whether we believe that this CPU has a
|
||||
// broken NEON unit based on these fields from cpuinfo:
|
||||
unsigned implementer = 0, architecture = 0, variant = 0, part = 0,
|
||||
revision = 0;
|
||||
const struct {
|
||||
const char key[17];
|
||||
unsigned int* result;
|
||||
} kUnsignedValues[] = {
|
||||
{"CPU implementer", &implementer},
|
||||
{"CPU architecture", &architecture},
|
||||
{"CPU variant", &variant},
|
||||
{"CPU part", &part},
|
||||
{"CPU revision", &revision},
|
||||
};
|
||||
|
||||
std::string contents;
|
||||
ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
|
||||
DCHECK(!contents.empty());
|
||||
if (contents.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::istringstream iss(contents);
|
||||
std::string line;
|
||||
while (std::getline(iss, line)) {
|
||||
if (brand_.empty() &&
|
||||
(line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0 ||
|
||||
line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)) {
|
||||
brand_.assign(line.substr(strlen(kModelNamePrefix)));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < arraysize(kUnsignedValues); i++) {
|
||||
const char *key = kUnsignedValues[i].key;
|
||||
const size_t len = strlen(key);
|
||||
|
||||
if (line.compare(0, len, key) == 0 &&
|
||||
line.size() >= len + 1 &&
|
||||
(line[len] == '\t' || line[len] == ' ' || line[len] == ':')) {
|
||||
size_t colon_pos = line.find(':', len);
|
||||
if (colon_pos == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const StringPiece line_sp(line);
|
||||
StringPiece value_sp = line_sp.substr(colon_pos + 1);
|
||||
while (!value_sp.empty() &&
|
||||
(value_sp[0] == ' ' || value_sp[0] == '\t')) {
|
||||
value_sp = value_sp.substr(1);
|
||||
}
|
||||
|
||||
// The string may have leading "0x" or not, so we use strtoul to
|
||||
// handle that.
|
||||
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) {
|
||||
*kUnsignedValues[i].result = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
has_broken_neon_ =
|
||||
implementer == 0x51 &&
|
||||
architecture == 7 &&
|
||||
variant == 1 &&
|
||||
part == 0x4d &&
|
||||
revision == 0;
|
||||
}
|
||||
|
||||
const std::string& brand() const { return brand_; }
|
||||
bool has_broken_neon() const { return has_broken_neon_; }
|
||||
|
||||
private:
|
||||
std::string brand_;
|
||||
bool has_broken_neon_;
|
||||
DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue);
|
||||
};
|
||||
|
||||
base::LazyInstance<LazyCpuInfoValue>::Leaky g_lazy_cpuinfo =
|
||||
LAZY_INSTANCE_INITIALIZER;
|
||||
|
||||
#endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) ||
|
||||
// defined(OS_LINUX))
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void CPU::Initialize() {
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
int cpu_info[4] = {-1};
|
||||
char cpu_string[48];
|
||||
|
||||
// __cpuid with an InfoType argument of 0 returns the number of
|
||||
// valid Ids in CPUInfo[0] and the CPU identification string in
|
||||
// the other three array elements. The CPU identification string is
|
||||
// not in linear order. The code below arranges the information
|
||||
// in a human readable form. The human readable order is CPUInfo[1] |
|
||||
// CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
|
||||
// before using memcpy to copy these three array elements to cpu_string.
|
||||
__cpuid(cpu_info, 0);
|
||||
int num_ids = cpu_info[0];
|
||||
std::swap(cpu_info[2], cpu_info[3]);
|
||||
memcpy(cpu_string, &cpu_info[1], 3 * sizeof(cpu_info[1]));
|
||||
cpu_vendor_.assign(cpu_string, 3 * sizeof(cpu_info[1]));
|
||||
|
||||
// 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);
|
||||
family_ = (cpu_info[0] >> 8) & 0xf;
|
||||
type_ = (cpu_info[0] >> 12) & 0x3;
|
||||
ext_model_ = (cpu_info[0] >> 16) & 0xf;
|
||||
ext_family_ = (cpu_info[0] >> 20) & 0xff;
|
||||
has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
|
||||
has_sse_ = (cpu_info[3] & 0x02000000) != 0;
|
||||
has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
|
||||
has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
|
||||
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
|
||||
has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
|
||||
has_sse42_ = (cpu_info[2] & 0x00100000) != 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
|
||||
// c) XSAVE is enabled by the kernel.
|
||||
// See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
|
||||
//
|
||||
// In addition, we have observed some crashes with the xgetbv instruction
|
||||
// even after following Intel's example code. (See crbug.com/375968.)
|
||||
// Because of that, we also test the XSAVE bit because its description in
|
||||
// the CPUID documentation suggests that it signals xgetbv support.
|
||||
has_avx_ =
|
||||
(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.
|
||||
__cpuid(cpu_info, 0x80000000);
|
||||
const int parameter_end = 0x80000004;
|
||||
int max_parameter = cpu_info[0];
|
||||
|
||||
if (cpu_info[0] >= parameter_end) {
|
||||
char* cpu_string_ptr = cpu_string;
|
||||
|
||||
for (int parameter = 0x80000002; parameter <= parameter_end &&
|
||||
cpu_string_ptr < &cpu_string[sizeof(cpu_string)]; parameter++) {
|
||||
__cpuid(cpu_info, parameter);
|
||||
memcpy(cpu_string_ptr, cpu_info, sizeof(cpu_info));
|
||||
cpu_string_ptr += sizeof(cpu_info);
|
||||
}
|
||||
cpu_brand_.assign(cpu_string, cpu_string_ptr - cpu_string);
|
||||
}
|
||||
|
||||
const int parameter_containing_non_stop_time_stamp_counter = 0x80000007;
|
||||
if (max_parameter >= parameter_containing_non_stop_time_stamp_counter) {
|
||||
__cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter);
|
||||
has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
|
||||
}
|
||||
#elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
|
||||
cpu_brand_.assign(g_lazy_cpuinfo.Get().brand());
|
||||
has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon();
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
if (has_ssse3()) return SSSE3;
|
||||
if (has_sse3()) return SSE3;
|
||||
if (has_sse2()) return SSE2;
|
||||
if (has_sse()) return SSE;
|
||||
return PENTIUM;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
@@ -1,92 +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_CPU_H_
|
||||
#define BASE_CPU_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Query information about the processor.
|
||||
class BASE_EXPORT CPU {
|
||||
public:
|
||||
// Constructor
|
||||
CPU();
|
||||
|
||||
enum IntelMicroArchitecture {
|
||||
PENTIUM,
|
||||
SSE,
|
||||
SSE2,
|
||||
SSE3,
|
||||
SSSE3,
|
||||
SSE41,
|
||||
SSE42,
|
||||
AVX,
|
||||
AVX2,
|
||||
MAX_INTEL_MICRO_ARCHITECTURE
|
||||
};
|
||||
|
||||
// Accessors for CPU information.
|
||||
const std::string& vendor_name() const { return cpu_vendor_; }
|
||||
int signature() const { return signature_; }
|
||||
int stepping() const { return stepping_; }
|
||||
int model() const { return model_; }
|
||||
int family() const { return family_; }
|
||||
int type() const { return type_; }
|
||||
int extended_model() const { return ext_model_; }
|
||||
int extended_family() const { return ext_family_; }
|
||||
bool has_mmx() const { return has_mmx_; }
|
||||
bool has_sse() const { return has_sse_; }
|
||||
bool has_sse2() const { return has_sse2_; }
|
||||
bool has_sse3() const { return has_sse3_; }
|
||||
bool has_ssse3() const { return has_ssse3_; }
|
||||
bool has_sse41() const { return has_sse41_; }
|
||||
bool has_sse42() const { return has_sse42_; }
|
||||
bool has_avx() const { return has_avx_; }
|
||||
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_;
|
||||
}
|
||||
// has_broken_neon is only valid on ARM chips. If true, it indicates that we
|
||||
// believe that the NEON unit on the current CPU is flawed and cannot execute
|
||||
// some code. See https://code.google.com/p/chromium/issues/detail?id=341598
|
||||
bool has_broken_neon() const { return has_broken_neon_; }
|
||||
|
||||
IntelMicroArchitecture GetIntelMicroArchitecture() const;
|
||||
const std::string& cpu_brand() const { return cpu_brand_; }
|
||||
|
||||
private:
|
||||
// Query the processor for CPUID information.
|
||||
void Initialize();
|
||||
|
||||
int signature_; // raw form of type, family, model, and stepping
|
||||
int type_; // process type
|
||||
int family_; // family of the processor
|
||||
int model_; // model of processor
|
||||
int stepping_; // processor revision number
|
||||
int ext_model_;
|
||||
int ext_family_;
|
||||
bool has_mmx_;
|
||||
bool has_sse_;
|
||||
bool has_sse2_;
|
||||
bool has_sse3_;
|
||||
bool has_ssse3_;
|
||||
bool has_sse41_;
|
||||
bool has_sse42_;
|
||||
bool has_avx_;
|
||||
bool has_avx2_;
|
||||
bool has_aesni_;
|
||||
bool has_non_stop_time_stamp_counter_;
|
||||
bool has_broken_neon_;
|
||||
std::string cpu_vendor_;
|
||||
std::string cpu_brand_;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CPU_H_
|
||||
@@ -1,23 +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.
|
||||
|
||||
#include "base/debug/alias.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
|
||||
void Alias(const void* var) {
|
||||
}
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
} // namespace debug
|
||||
} // namespace base
|
||||
@@ -1,21 +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_DEBUG_ALIAS_H_
|
||||
#define BASE_DEBUG_ALIAS_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
// Make the optimizer think that var is aliased. This is to prevent it from
|
||||
// optimizing out variables that that would not otherwise be live at the point
|
||||
// of a potential crash.
|
||||
void BASE_EXPORT Alias(const void* var);
|
||||
|
||||
} // namespace debug
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_DEBUG_ALIAS_H_
|
||||
@@ -1,44 +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 is a cross platform interface for helper functions related to
|
||||
// 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_
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
// Waits wait_seconds seconds for a debugger to attach to the current process.
|
||||
// When silent is false, an exception is thrown when a debugger is detected.
|
||||
BASE_EXPORT bool WaitForDebugger(int wait_seconds, bool silent);
|
||||
|
||||
// Returns true if the given process is being run under a debugger.
|
||||
//
|
||||
// On OS X, the underlying mechanism doesn't work when the sandbox is enabled.
|
||||
// To get around this, this function caches its value.
|
||||
//
|
||||
// WARNING: Because of this, on OS X, a call MUST be made to this function
|
||||
// BEFORE the sandbox is enabled.
|
||||
BASE_EXPORT bool BeingDebugged();
|
||||
|
||||
// Break into the debugger, assumes a debugger is present.
|
||||
BASE_EXPORT void BreakDebugger();
|
||||
|
||||
// Used in test code, this controls whether showing dialogs and breaking into
|
||||
// the debugger is suppressed for debug errors, even in debug mode (normally
|
||||
// release mode doesn't do this stuff -- this is controlled separately).
|
||||
// Normally UI is not suppressed. This is normally used when running automated
|
||||
// tests where we want a crash rather than a dialog or a debugger.
|
||||
BASE_EXPORT void SetSuppressDebugUI(bool suppress);
|
||||
BASE_EXPORT bool IsDebugUISuppressed();
|
||||
|
||||
} // namespace debug
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_DEBUG_DEBUGGER_H_
|
||||
@@ -1,46 +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_DEBUG_LEAK_ANNOTATIONS_H_
|
||||
#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
// This file defines macros which can be used to annotate intentional memory
|
||||
// leaks. Support for annotations is implemented in LeakSanitizer. Annotated
|
||||
// objects will be treated as a source of live pointers, i.e. any heap objects
|
||||
// reachable by following pointers from an annotated object will not be
|
||||
// reported as leaks.
|
||||
//
|
||||
// ANNOTATE_SCOPED_MEMORY_LEAK: all allocations made in the current scope
|
||||
// will be annotated as leaks.
|
||||
// ANNOTATE_LEAKING_OBJECT_PTR(X): the heap object referenced by pointer X will
|
||||
// be annotated as a leak.
|
||||
|
||||
#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
|
||||
|
||||
#include <sanitizer/lsan_interface.h>
|
||||
|
||||
class ScopedLeakSanitizerDisabler {
|
||||
public:
|
||||
ScopedLeakSanitizerDisabler() { __lsan_disable(); }
|
||||
~ScopedLeakSanitizerDisabler() { __lsan_enable(); }
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedLeakSanitizerDisabler);
|
||||
};
|
||||
|
||||
#define ANNOTATE_SCOPED_MEMORY_LEAK \
|
||||
ScopedLeakSanitizerDisabler leak_sanitizer_disabler; static_cast<void>(0)
|
||||
|
||||
#define ANNOTATE_LEAKING_OBJECT_PTR(X) __lsan_ignore_object(X);
|
||||
|
||||
#else
|
||||
|
||||
#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
|
||||
#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BASE_DEBUG_LEAK_ANNOTATIONS_H_
|
||||
@@ -1,221 +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.
|
||||
|
||||
#include "base/debug/profiler.h"
|
||||
|
||||
#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 "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 BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
// TODO(peria): Enable profiling on Windows.
|
||||
#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 = 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());
|
||||
}
|
||||
|
||||
void StopProfiling() {
|
||||
ProfilerFlush();
|
||||
ProfilerStop();
|
||||
}
|
||||
|
||||
void FlushProfiling() {
|
||||
ProfilerFlush();
|
||||
}
|
||||
|
||||
bool BeingProfiled() {
|
||||
return ProfilingIsEnabledForAllThreads();
|
||||
}
|
||||
|
||||
void RestartProfilingAfterFork() {
|
||||
ProfilerRegisterThread();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void StartProfiling(const std::string& name) {
|
||||
}
|
||||
|
||||
void StopProfiling() {
|
||||
}
|
||||
|
||||
void FlushProfiling() {
|
||||
}
|
||||
|
||||
bool BeingProfiled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void RestartProfilingAfterFork() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(OS_WIN)
|
||||
|
||||
bool IsBinaryInstrumented() {
|
||||
return false;
|
||||
}
|
||||
|
||||
ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else // defined(OS_WIN)
|
||||
|
||||
// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
bool IsBinaryInstrumented() {
|
||||
enum InstrumentationCheckState {
|
||||
UNINITIALIZED,
|
||||
INSTRUMENTED_IMAGE,
|
||||
NON_INSTRUMENTED_IMAGE,
|
||||
};
|
||||
|
||||
static InstrumentationCheckState state = UNINITIALIZED;
|
||||
|
||||
if (state == UNINITIALIZED) {
|
||||
HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
|
||||
base::win::PEImage image(this_module);
|
||||
|
||||
// Check to be sure our image is structured as we'd expect.
|
||||
DCHECK(image.VerifyMagic());
|
||||
|
||||
// Syzygy-instrumented binaries contain a PE image section named ".thunks",
|
||||
// and all Syzygy-modified binaries contain the ".syzygy" image section.
|
||||
// This is a very fast check, as it only looks at the image header.
|
||||
if ((image.GetImageSectionHeaderByName(".thunks") != NULL) &&
|
||||
(image.GetImageSectionHeaderByName(".syzygy") != NULL)) {
|
||||
state = INSTRUMENTED_IMAGE;
|
||||
} else {
|
||||
state = NON_INSTRUMENTED_IMAGE;
|
||||
}
|
||||
}
|
||||
DCHECK(state != UNINITIALIZED);
|
||||
|
||||
return state == INSTRUMENTED_IMAGE;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct FunctionSearchContext {
|
||||
const char* name;
|
||||
FARPROC function;
|
||||
};
|
||||
|
||||
// Callback function to PEImage::EnumImportChunks.
|
||||
bool FindResolutionFunctionInImports(
|
||||
const base::win::PEImage &image, const char* module_name,
|
||||
PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
|
||||
PVOID cookie) {
|
||||
FunctionSearchContext* context =
|
||||
reinterpret_cast<FunctionSearchContext*>(cookie);
|
||||
|
||||
DCHECK_NE(static_cast<FunctionSearchContext*>(NULL), context);
|
||||
DCHECK_EQ(static_cast<FARPROC>(NULL), context->function);
|
||||
|
||||
// Our import address table contains pointers to the functions we import
|
||||
// at this point. Let's retrieve the first such function and use it to
|
||||
// find the module this import was resolved to by the loader.
|
||||
const wchar_t* function_in_module =
|
||||
reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
|
||||
|
||||
// Retrieve the module by a function in the module.
|
||||
const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
|
||||
HMODULE module = NULL;
|
||||
if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
|
||||
// This can happen if someone IAT patches us to a thunk.
|
||||
return true;
|
||||
}
|
||||
|
||||
// See whether this module exports the function we're looking for.
|
||||
FARPROC exported_func = ::GetProcAddress(module, context->name);
|
||||
if (exported_func != NULL) {
|
||||
// We found it, return the function and terminate the enumeration.
|
||||
context->function = exported_func;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep going.
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
FunctionType FindFunctionInImports(const char* function_name) {
|
||||
if (!IsBinaryInstrumented())
|
||||
return NULL;
|
||||
|
||||
HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
|
||||
base::win::PEImage image(this_module);
|
||||
|
||||
FunctionSearchContext ctx = { function_name, NULL };
|
||||
image.EnumImportChunks(FindResolutionFunctionInImports, &ctx);
|
||||
|
||||
return reinterpret_cast<FunctionType>(ctx.function);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
|
||||
return FindFunctionInImports<ReturnAddressLocationResolver>(
|
||||
"ResolveReturnAddressLocation");
|
||||
}
|
||||
|
||||
DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
|
||||
return FindFunctionInImports<DynamicFunctionEntryHook>(
|
||||
"OnDynamicFunctionEntry");
|
||||
}
|
||||
|
||||
AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
|
||||
return FindFunctionInImports<AddDynamicSymbol>(
|
||||
"AddDynamicSymbol");
|
||||
}
|
||||
|
||||
MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
|
||||
return FindFunctionInImports<MoveDynamicSymbol>(
|
||||
"MoveDynamicSymbol");
|
||||
}
|
||||
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
} // namespace debug
|
||||
} // namespace base
|
||||
@@ -1,91 +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_DEBUG_PROFILER_H_
|
||||
#define BASE_DEBUG_PROFILER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
// The Profiler functions allow usage of the underlying sampling based
|
||||
// profiler. If the application has not been built with the necessary
|
||||
// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions
|
||||
// are noops.
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
// Start profiling with the supplied name.
|
||||
// {pid} will be replaced by the process' pid and {count} will be replaced
|
||||
// by the count of the profile run (starts at 1 with each process).
|
||||
BASE_EXPORT void StartProfiling(const std::string& name);
|
||||
|
||||
// Stop profiling and write out data.
|
||||
BASE_EXPORT void StopProfiling();
|
||||
|
||||
// Force data to be written to file.
|
||||
BASE_EXPORT void FlushProfiling();
|
||||
|
||||
// Returns true if process is being profiled.
|
||||
BASE_EXPORT bool BeingProfiled();
|
||||
|
||||
// Reset profiling after a fork, which disables timers.
|
||||
BASE_EXPORT void RestartProfilingAfterFork();
|
||||
|
||||
// Returns true iff this executable is instrumented with the Syzygy profiler.
|
||||
BASE_EXPORT bool IsBinaryInstrumented();
|
||||
|
||||
// There's a class of profilers that use "return address swizzling" to get a
|
||||
// hook on function exits. This class of profilers uses some form of entry hook,
|
||||
// like e.g. binary instrumentation, or a compiler flag, that calls a hook each
|
||||
// time a function is invoked. The hook then switches the return address on the
|
||||
// stack for the address of an exit hook function, and pushes the original
|
||||
// return address to a shadow stack of some type. When in due course the CPU
|
||||
// executes a return to the exit hook, the exit hook will do whatever work it
|
||||
// does on function exit, then arrange to return to the original return address.
|
||||
// This class of profiler does not play well with programs that look at the
|
||||
// return address, as does e.g. V8. V8 uses the return address to certain
|
||||
// runtime functions to find the JIT code that called it, and from there finds
|
||||
// the V8 data structures associated to the JS function involved.
|
||||
// A return address resolution function is used to fix this. It allows such
|
||||
// programs to resolve a location on stack where a return address originally
|
||||
// resided, to the shadow stack location where the profiler stashed it.
|
||||
typedef uintptr_t (*ReturnAddressLocationResolver)(
|
||||
uintptr_t return_addr_location);
|
||||
|
||||
// This type declaration must match V8's FunctionEntryHook.
|
||||
typedef void (*DynamicFunctionEntryHook)(uintptr_t function,
|
||||
uintptr_t return_addr_location);
|
||||
|
||||
// The functions below here are to support profiling V8-generated code.
|
||||
// V8 has provisions for generating a call to an entry hook for newly generated
|
||||
// JIT code, and it can push symbol information on code generation and advise
|
||||
// when the garbage collector moves code. The functions declarations below here
|
||||
// make glue between V8's facilities and a profiler.
|
||||
|
||||
// This type declaration must match V8's FunctionEntryHook.
|
||||
typedef void (*DynamicFunctionEntryHook)(uintptr_t function,
|
||||
uintptr_t return_addr_location);
|
||||
|
||||
typedef void (*AddDynamicSymbol)(const void* address,
|
||||
size_t length,
|
||||
const char* name,
|
||||
size_t name_len);
|
||||
typedef void (*MoveDynamicSymbol)(const void* address, const void* new_address);
|
||||
|
||||
|
||||
// If this binary is instrumented and the instrumentation supplies a function
|
||||
// for each of those purposes, find and return the function in question.
|
||||
// Otherwise returns NULL.
|
||||
BASE_EXPORT ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc();
|
||||
BASE_EXPORT DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc();
|
||||
BASE_EXPORT AddDynamicSymbol GetProfilerAddDynamicSymbolFunc();
|
||||
BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc();
|
||||
|
||||
} // namespace debug
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_DEBUG_PROFILER_H_
|
||||
@@ -1,59 +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.
|
||||
|
||||
#ifndef BASE_FILE_DESCRIPTOR_POSIX_H_
|
||||
#define BASE_FILE_DESCRIPTOR_POSIX_H_
|
||||
|
||||
#include "base/files/file.h"
|
||||
#include "base/files/scoped_file.h"
|
||||
|
||||
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.
|
||||
//
|
||||
// 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) {}
|
||||
|
||||
FileDescriptor(int ifd, bool iauto_close) : fd(ifd), auto_close(iauto_close) {
|
||||
}
|
||||
|
||||
FileDescriptor(File file) : fd(file.TakePlatformFile()), auto_close(true) {}
|
||||
explicit FileDescriptor(ScopedFD fd) : fd(fd.release()), auto_close(true) {}
|
||||
|
||||
bool operator==(const FileDescriptor& other) const {
|
||||
return (fd == other.fd && auto_close == other.auto_close);
|
||||
}
|
||||
|
||||
bool operator!=(const FileDescriptor& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
// A comparison operator so that we can use these as keys in a std::map.
|
||||
bool operator<(const FileDescriptor& other) const {
|
||||
return other.fd < fd;
|
||||
}
|
||||
|
||||
int fd;
|
||||
// If true, this file descriptor should be closed after it has been used. For
|
||||
// example an IPC system might interpret this flag as indicating that the
|
||||
// file descriptor it has been given should be closed after use.
|
||||
bool auto_close;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_FILE_DESCRIPTOR_POSIX_H_
|
||||
@@ -1,477 +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.
|
||||
|
||||
// FilePath is a container for pathnames stored in a platform's native string
|
||||
// type, providing containers for manipulation in according with the
|
||||
// platform's conventions for pathnames. It supports the following path
|
||||
// types:
|
||||
//
|
||||
// POSIX Windows
|
||||
// --------------- ----------------------------------
|
||||
// Fundamental type char[] wchar_t[]
|
||||
// Encoding unspecified* UTF-16
|
||||
// Separator / \, tolerant of /
|
||||
// Drive letters no case-insensitive A-Z followed by :
|
||||
// Alternate root // (surprise!) \\, for UNC paths
|
||||
//
|
||||
// * The encoding need not be specified on POSIX systems, although some
|
||||
// POSIX-compliant systems do specify an encoding. Mac OS X uses UTF-8.
|
||||
// Chrome OS also uses UTF-8.
|
||||
// Linux does not specify an encoding, but in practice, the locale's
|
||||
// character set may be used.
|
||||
//
|
||||
// For more arcane bits of path trivia, see below.
|
||||
//
|
||||
// FilePath objects are intended to be used anywhere paths are. An
|
||||
// application may pass FilePath objects around internally, masking the
|
||||
// underlying differences between systems, only differing in implementation
|
||||
// where interfacing directly with the system. For example, a single
|
||||
// OpenFile(const FilePath &) function may be made available, allowing all
|
||||
// callers to operate without regard to the underlying implementation. On
|
||||
// POSIX-like platforms, OpenFile might wrap fopen, and on Windows, it might
|
||||
// wrap _wfopen_s, perhaps both by calling file_path.value().c_str(). This
|
||||
// allows each platform to pass pathnames around without requiring conversions
|
||||
// between encodings, which has an impact on performance, but more imporantly,
|
||||
// has an impact on correctness on platforms that do not have well-defined
|
||||
// encodings for pathnames.
|
||||
//
|
||||
// Several methods are available to perform common operations on a FilePath
|
||||
// object, such as determining the parent directory (DirName), isolating the
|
||||
// final path component (BaseName), and appending a relative pathname string
|
||||
// to an existing FilePath object (Append). These methods are highly
|
||||
// recommended over attempting to split and concatenate strings directly.
|
||||
// These methods are based purely on string manipulation and knowledge of
|
||||
// platform-specific pathname conventions, and do not consult the filesystem
|
||||
// at all, making them safe to use without fear of blocking on I/O operations.
|
||||
// These methods do not function as mutators but instead return distinct
|
||||
// instances of FilePath objects, and are therefore safe to use on const
|
||||
// objects. The objects themselves are safe to share between threads.
|
||||
//
|
||||
// To aid in initialization of FilePath objects from string literals, a
|
||||
// FILE_PATH_LITERAL macro is provided, which accounts for the difference
|
||||
// between char[]-based pathnames on POSIX systems and wchar_t[]-based
|
||||
// pathnames on Windows.
|
||||
//
|
||||
// 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
|
||||
// FILE_PATH_LITERAL. At runtime, a FilePath object can be created from the
|
||||
// character array. Example:
|
||||
//
|
||||
// | const FilePath::CharType kLogFileName[] = FILE_PATH_LITERAL("log.txt");
|
||||
// |
|
||||
// | void Function() {
|
||||
// | FilePath log_file_path(kLogFileName);
|
||||
// | [...]
|
||||
// | }
|
||||
//
|
||||
// WARNING: FilePaths should ALWAYS be displayed with LTR directionality, even
|
||||
// when the UI language is RTL. This means you always need to pass filepaths
|
||||
// through base::i18n::WrapPathWithLTRFormatting() before displaying it in the
|
||||
// RTL UI.
|
||||
//
|
||||
// This is a very common source of bugs, please try to keep this in mind.
|
||||
//
|
||||
// ARCANE BITS OF PATH TRIVIA
|
||||
//
|
||||
// - A double leading slash is actually part of the POSIX standard. Systems
|
||||
// are allowed to treat // as an alternate root, as Windows does for UNC
|
||||
// (network share) paths. Most POSIX systems don't do anything special
|
||||
// with two leading slashes, but FilePath handles this case properly
|
||||
// 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.267 ("Pathname")
|
||||
// and 4.12 ("Pathname Resolution"), available at:
|
||||
// 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
|
||||
// allow older applications that require drive letters to support UNC paths
|
||||
// like \\server\share\path, by permitting c:\\server\share\path as an
|
||||
// equivalent. Since the OS treats these paths specially, FilePath needs
|
||||
// to do the same. Since Windows can use either / or \ as the separator,
|
||||
// FilePath treats c://, c:\\, //, and \\ all equivalently.
|
||||
// Reference:
|
||||
// The Old New Thing, "Why is a drive letter permitted in front of UNC
|
||||
// paths (sometimes)?", available at:
|
||||
// http://blogs.msdn.com/oldnewthing/archive/2005/11/22/495740.aspx
|
||||
|
||||
#ifndef BASE_FILES_FILE_PATH_H_
|
||||
#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"
|
||||
#include "build/build_config.h"
|
||||
|
||||
// Windows-style drive letter support and pathname separator characters can be
|
||||
// enabled and disabled independently, to aid testing. These #defines are
|
||||
// here so that the same setting can be used in both the implementation and
|
||||
// in the unit test.
|
||||
#if defined(OS_WIN)
|
||||
#define FILE_PATH_USES_DRIVE_LETTERS
|
||||
#define FILE_PATH_USES_WIN_SEPARATORS
|
||||
#endif // OS_WIN
|
||||
|
||||
// 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 {
|
||||
public:
|
||||
#if defined(OS_POSIX)
|
||||
// On most platforms, native pathnames are char arrays, and the encoding
|
||||
// may or may not be specified. On Mac OS X, native pathnames are encoded
|
||||
// in UTF-8.
|
||||
typedef std::string StringType;
|
||||
#elif defined(OS_WIN)
|
||||
// On Windows, for Unicode-aware applications, native pathnames are wchar_t
|
||||
// arrays encoded in UTF-16.
|
||||
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
|
||||
// hierarchical paths. Each character in this array is a valid separator,
|
||||
// but kSeparators[0] is treated as the canonical separator and will be used
|
||||
// when composing pathnames.
|
||||
static const CharType kSeparators[];
|
||||
|
||||
// arraysize(kSeparators).
|
||||
static const size_t kSeparatorsLength;
|
||||
|
||||
// A special path component meaning "this directory."
|
||||
static const CharType kCurrentDirectory[];
|
||||
|
||||
// A special path component meaning "the parent directory."
|
||||
static const CharType kParentDirectory[];
|
||||
|
||||
// The character used to identify a file extension.
|
||||
static const CharType kExtensionSeparator;
|
||||
|
||||
FilePath();
|
||||
FilePath(const FilePath& that);
|
||||
explicit FilePath(StringPieceType path);
|
||||
~FilePath();
|
||||
FilePath& operator=(const FilePath& that);
|
||||
|
||||
bool operator==(const FilePath& that) const;
|
||||
|
||||
bool operator!=(const FilePath& that) const;
|
||||
|
||||
// Required for some STL containers and operations
|
||||
bool operator<(const FilePath& that) const {
|
||||
return path_ < that.path_;
|
||||
}
|
||||
|
||||
const StringType& value() const { return path_; }
|
||||
|
||||
bool empty() const { return path_.empty(); }
|
||||
|
||||
void clear() { path_.clear(); }
|
||||
|
||||
// Returns true if |character| is in kSeparators.
|
||||
static bool IsSeparator(CharType character);
|
||||
|
||||
// Returns a vector of all of the components of the provided path. It is
|
||||
// equivalent to calling DirName().value() on the path's root component,
|
||||
// and BaseName().value() on each child component.
|
||||
//
|
||||
// To make sure this is lossless so we can differentiate absolute and
|
||||
// relative paths, the root slash will be included even though no other
|
||||
// slashes will be. The precise behavior is:
|
||||
//
|
||||
// Posix: "/foo/bar" -> [ "/", "foo", "bar" ]
|
||||
// Windows: "C:\foo\bar" -> [ "C:", "\\", "foo", "bar" ]
|
||||
void GetComponents(std::vector<FilePath::StringType>* components) const;
|
||||
|
||||
// Returns true if this FilePath is a strict parent of the |child|. Absolute
|
||||
// and relative paths are accepted i.e. is /foo parent to /foo/bar and
|
||||
// is foo parent to foo/bar. Does not convert paths to absolute, follow
|
||||
// symlinks or directory navigation (e.g. ".."). A path is *NOT* its own
|
||||
// parent.
|
||||
bool IsParent(const FilePath& child) const;
|
||||
|
||||
// If IsParent(child) holds, appends to path (if non-NULL) the
|
||||
// relative path to child and returns true. For example, if parent
|
||||
// holds "/Users/johndoe/Library/Application Support", child holds
|
||||
// "/Users/johndoe/Library/Application Support/Google/Chrome/Default", and
|
||||
// *path holds "/Users/johndoe/Library/Caches", then after
|
||||
// parent.AppendRelativePath(child, path) is called *path will hold
|
||||
// "/Users/johndoe/Library/Caches/Google/Chrome/Default". Otherwise,
|
||||
// returns false.
|
||||
bool AppendRelativePath(const FilePath& child, FilePath* path) const;
|
||||
|
||||
// Returns a FilePath corresponding to the directory containing the path
|
||||
// named by this object, stripping away the file component. If this object
|
||||
// only contains one component, returns a FilePath identifying
|
||||
// kCurrentDirectory. If this object already refers to the root directory,
|
||||
// returns a FilePath identifying the root directory.
|
||||
FilePath DirName() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns a FilePath corresponding to the last path component of this
|
||||
// object, either a file or a directory. If this object already refers to
|
||||
// the root directory, returns a FilePath identifying the root directory;
|
||||
// this is the only situation in which BaseName will return an absolute path.
|
||||
FilePath BaseName() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns ".jpg" for path "C:\pics\jojo.jpg", or an empty string if
|
||||
// the file has no extension. If non-empty, Extension() will always start
|
||||
// with precisely one ".". The following code should always work regardless
|
||||
// of the value of path. For common double-extensions like .tar.gz and
|
||||
// .user.js, this method returns the combined extension. For a single
|
||||
// component, use FinalExtension().
|
||||
// new_path = path.RemoveExtension().value().append(path.Extension());
|
||||
// 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 WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns the path's file extension, as in Extension(), but will
|
||||
// never return a double extension.
|
||||
//
|
||||
// TODO(davidben): Check all our extension-sensitive code to see if
|
||||
// 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 WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
|
||||
// NOTE: this is slightly different from the similar file_util implementation
|
||||
// which returned simply 'jojo'.
|
||||
FilePath RemoveExtension() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Removes the path's file extension, as in RemoveExtension(), but
|
||||
// ignores double extensions.
|
||||
FilePath RemoveFinalExtension() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Inserts |suffix| after the file name portion of |path| but before the
|
||||
// extension. Returns "" if BaseName() == "." or "..".
|
||||
// Examples:
|
||||
// path == "C:\pics\jojo.jpg" suffix == " (1)", returns "C:\pics\jojo (1).jpg"
|
||||
// path == "jojo.jpg" suffix == " (1)", returns "jojo (1).jpg"
|
||||
// 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(
|
||||
StringPieceType suffix) const WARN_UNUSED_RESULT;
|
||||
FilePath InsertBeforeExtensionASCII(
|
||||
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(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(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(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
|
||||
// excessive separators if this object's path already ends with a separator.
|
||||
// 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(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
|
||||
// paths is well defined, it can handle ASCII path components as well.
|
||||
// Mac uses UTF8, and since ASCII is a subset of that, it works there as well.
|
||||
// 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(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
|
||||
// a separator character, or with two separator characters. On POSIX
|
||||
// platforms, an absolute path begins with a separator character.
|
||||
bool IsAbsolute() const;
|
||||
|
||||
// Returns true if the patch ends with a path separator character.
|
||||
bool EndsWithSeparator() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns a copy of this FilePath that ends with a trailing separator. If
|
||||
// the input path is empty, an empty FilePath will be returned.
|
||||
FilePath AsEndingWithSeparator() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns a copy of this FilePath that does not end with a trailing
|
||||
// separator.
|
||||
FilePath StripTrailingSeparators() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns true if this FilePath contains an attempt to reference a parent
|
||||
// directory (e.g. has a path component that is "..").
|
||||
bool ReferencesParent() const;
|
||||
|
||||
// Return a Unicode human-readable version of this path.
|
||||
// Warning: you can *not*, in general, go from a display name back to a real
|
||||
// path. Only use this when displaying paths to users, not just when you
|
||||
// want to stuff a string16 into some other API.
|
||||
string16 LossyDisplayName() const;
|
||||
|
||||
// Return the path as ASCII, or the empty string if the path is not ASCII.
|
||||
// This should only be used for cases where the FilePath is representing a
|
||||
// known-ASCII filename.
|
||||
std::string MaybeAsASCII() const;
|
||||
|
||||
// Return the path as UTF-8.
|
||||
//
|
||||
// This function is *unsafe* as there is no way to tell what encoding is
|
||||
// used in file names on POSIX systems other than Mac and Chrome OS,
|
||||
// although UTF-8 is practically used everywhere these days. To mitigate
|
||||
// the encoding issue, this function internally calls
|
||||
// SysNativeMBToWide() on POSIX systems other than Mac and Chrome OS,
|
||||
// per assumption that the current locale's encoding is used in file
|
||||
// names, but this isn't a perfect solution.
|
||||
//
|
||||
// Once it becomes safe to to stop caring about non-UTF-8 file names,
|
||||
// the SysNativeMBToWide() hack will be removed from the code, along
|
||||
// with "Unsafe" in the function name.
|
||||
std::string AsUTF8Unsafe() const;
|
||||
|
||||
// Similar to AsUTF8Unsafe, but returns UTF-16 instead.
|
||||
string16 AsUTF16Unsafe() const;
|
||||
|
||||
// Returns a FilePath object from a path name in UTF-8. This function
|
||||
// should only be used for cases where you are sure that the input
|
||||
// string is UTF-8.
|
||||
//
|
||||
// Like AsUTF8Unsafe(), this function is unsafe. This function
|
||||
// internally calls SysWideToNativeMB() on POSIX systems other than Mac
|
||||
// and Chrome OS, to mitigate the encoding issue. See the comment at
|
||||
// AsUTF8Unsafe() for details.
|
||||
static FilePath FromUTF8Unsafe(const std::string& utf8);
|
||||
|
||||
// Similar to FromUTF8Unsafe, but accepts UTF-16 instead.
|
||||
static FilePath FromUTF16Unsafe(const string16& utf16);
|
||||
|
||||
void WriteToPickle(Pickle* pickle) const;
|
||||
bool ReadFromPickle(PickleIterator* iter);
|
||||
|
||||
// Normalize all path separators to backslash on Windows
|
||||
// (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
|
||||
FilePath NormalizePathSeparators() const;
|
||||
|
||||
// Normalize all path separattors to given type on Windows
|
||||
// (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
|
||||
FilePath NormalizePathSeparatorsTo(CharType separator) const;
|
||||
|
||||
// Compare two strings in the same way the file system does.
|
||||
// Note that these always ignore case, even on file systems that are case-
|
||||
// sensitive. If case-sensitive comparison is ever needed, add corresponding
|
||||
// methods here.
|
||||
// The methods are written as a static method so that they can also be used
|
||||
// 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(StringPieceType string1,
|
||||
StringPieceType string2);
|
||||
static bool CompareEqualIgnoreCase(StringPieceType string1,
|
||||
StringPieceType string2) {
|
||||
return CompareIgnoreCase(string1, string2) == 0;
|
||||
}
|
||||
static bool CompareLessIgnoreCase(StringPieceType string1,
|
||||
StringPieceType string2) {
|
||||
return CompareIgnoreCase(string1, string2) < 0;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// Returns the string in the special canonical decomposed form as defined for
|
||||
// HFS, which is close to, but not quite, decomposition form D. See
|
||||
// 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(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(StringPieceType string1,
|
||||
StringPieceType string2);
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
// On android, file selection dialog can return a file with content uri
|
||||
// scheme(starting with content://). Content uri needs to be opened with
|
||||
// ContentResolver to guarantee that the app has appropriate permissions
|
||||
// to access it.
|
||||
// Returns true if the path is a content uri, or false otherwise.
|
||||
bool IsContentUri() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Remove trailing separators from this object. If the path is absolute, it
|
||||
// will never be stripped any more than to refer to the absolute root
|
||||
// directory, so "////" will become "/", not "". A leading pair of
|
||||
// separators is never stripped, to support alternate roots. This is used to
|
||||
// support UNC paths on Windows.
|
||||
void StripTrailingSeparatorsInternal();
|
||||
|
||||
StringType path_;
|
||||
};
|
||||
|
||||
// This is required by googletest to print a readable output on test failures.
|
||||
// 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"
|
||||
#elif defined(OS_WIN)
|
||||
#define FILE_PATH_LITERAL(x) L ## x
|
||||
#define PRFilePath "ls"
|
||||
#endif // OS_WIN
|
||||
|
||||
// Provide a hash function so that hash_sets and maps can contain FilePath
|
||||
// objects.
|
||||
namespace BASE_HASH_NAMESPACE {
|
||||
|
||||
template<>
|
||||
struct hash<base::FilePath> {
|
||||
size_t operator()(const base::FilePath& f) const {
|
||||
return hash<base::FilePath::StringType>()(f.value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace BASE_HASH_NAMESPACE
|
||||
|
||||
#endif // BASE_FILES_FILE_PATH_H_
|
||||
@@ -1,33 +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_GUID_H_
|
||||
#define BASE_GUID_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX".
|
||||
// If GUID generation fails an empty string is returned.
|
||||
// The POSIX implementation uses pseudo random number generation to create
|
||||
// the GUID. The Windows implementation uses system services.
|
||||
BASE_EXPORT std::string GenerateGUID();
|
||||
|
||||
// Returns true if the input string conforms to the GUID format.
|
||||
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_t bytes[2]);
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_GUID_H_
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#include "base/hash.h"
|
||||
|
||||
// Definition in base/third_party/superfasthash/superfasthash.c. (Third-party
|
||||
// code did not come with its own header file, so declaring the function here.)
|
||||
// Note: This algorithm is also in Blink under Source/wtf/StringHasher.h.
|
||||
extern "C" uint32_t SuperFastHash(const char* data, int len);
|
||||
|
||||
namespace base {
|
||||
|
||||
uint32_t SuperFastHash(const char* data, int len) {
|
||||
return ::SuperFastHash(data, len);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
@@ -1,40 +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_HASH_H_
|
||||
#define BASE_HASH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
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_t Hash(const char* data, size_t length) {
|
||||
if (length > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
NOTREACHED();
|
||||
return 0;
|
||||
}
|
||||
return SuperFastHash(data, static_cast<int>(length));
|
||||
}
|
||||
|
||||
// Computes a hash of a string |str|.
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
inline uint32_t Hash(const std::string& str) {
|
||||
return Hash(str.data(), str.size());
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_HASH_H_
|
||||
@@ -1,54 +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.
|
||||
|
||||
#include "base/lazy_instance.h"
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/atomicops.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
// TODO(joth): This function could be shared with Singleton, in place of its
|
||||
// WaitForInstance() call.
|
||||
bool NeedsLazyInstance(subtle::AtomicWord* state) {
|
||||
// Try to create the instance, if we're the first, will go from 0 to
|
||||
// kLazyInstanceStateCreating, otherwise we've already been beaten here.
|
||||
// The memory access has no memory ordering as state 0 and
|
||||
// kLazyInstanceStateCreating have no associated data (memory barriers are
|
||||
// all about ordering of memory accesses to *associated* data).
|
||||
if (subtle::NoBarrier_CompareAndSwap(state, 0,
|
||||
kLazyInstanceStateCreating) == 0)
|
||||
// Caller must create instance
|
||||
return true;
|
||||
|
||||
// It's either in the process of being created, or already created. Spin.
|
||||
// The load has acquire memory ordering as a thread which sees
|
||||
// state_ == STATE_CREATED needs to acquire visibility over
|
||||
// the associated data (buf_). Pairing Release_Store is in
|
||||
// CompleteLazyInstance().
|
||||
while (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) {
|
||||
PlatformThread::YieldCurrentThread();
|
||||
}
|
||||
// Someone else created the instance.
|
||||
return false;
|
||||
}
|
||||
|
||||
void CompleteLazyInstance(subtle::AtomicWord* state,
|
||||
subtle::AtomicWord new_instance,
|
||||
void* lazy_instance,
|
||||
void (*dtor)(void*)) {
|
||||
// Instance is created, go from CREATING to CREATED.
|
||||
// Releases visibility over private_buf_ to readers. Pairing Acquire_Load's
|
||||
// are in NeedsInstance() and Pointer().
|
||||
subtle::Release_Store(state, new_instance);
|
||||
|
||||
// Make sure that the lazily instantiated object will get destroyed at exit.
|
||||
if (dtor)
|
||||
AtExitManager::RegisterCallback(dtor, lazy_instance);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
@@ -1,207 +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.
|
||||
|
||||
// The LazyInstance<Type, Traits> class manages a single instance of Type,
|
||||
// which will be lazily created on the first time it's accessed. This class is
|
||||
// useful for places you would normally use a function-level static, but you
|
||||
// need to have guaranteed thread-safety. The Type constructor will only ever
|
||||
// be called once, even if two threads are racing to create the object. Get()
|
||||
// and Pointer() will always return the same, completely initialized instance.
|
||||
// When the instance is constructed it is registered with AtExitManager. The
|
||||
// destructor will be called on program exit.
|
||||
//
|
||||
// LazyInstance is completely thread safe, assuming that you create it safely.
|
||||
// The class was designed to be POD initialized, so it shouldn't require a
|
||||
// static constructor. It really only makes sense to declare a LazyInstance as
|
||||
// a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
|
||||
//
|
||||
// LazyInstance is similar to Singleton, except it does not have the singleton
|
||||
// property. You can have multiple LazyInstance's of the same type, and each
|
||||
// will manage a unique instance. It also preallocates the space for Type, as
|
||||
// to avoid allocating the Type instance on the heap. This may help with the
|
||||
// performance of creating the instance, and reducing heap fragmentation. This
|
||||
// requires that Type be a complete type so we can determine the size.
|
||||
//
|
||||
// Example usage:
|
||||
// static LazyInstance<MyClass> my_instance = LAZY_INSTANCE_INITIALIZER;
|
||||
// void SomeMethod() {
|
||||
// my_instance.Get().SomeMethod(); // MyClass::SomeMethod()
|
||||
//
|
||||
// MyClass* ptr = my_instance.Pointer();
|
||||
// ptr->DoDoDo(); // MyClass::DoDoDo
|
||||
// }
|
||||
|
||||
#ifndef BASE_LAZY_INSTANCE_H_
|
||||
#define BASE_LAZY_INSTANCE_H_
|
||||
|
||||
#include <new> // For placement new.
|
||||
|
||||
#include "base/atomicops.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/debug/leak_annotations.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/aligned_memory.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
|
||||
// LazyInstance uses its own struct initializer-list style static
|
||||
// initialization, as base's LINKER_INITIALIZED requires a constructor and on
|
||||
// some compilers (notably gcc 4.4) this still ends up needing runtime
|
||||
// initialization.
|
||||
#define LAZY_INSTANCE_INITIALIZER {0}
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Type>
|
||||
struct DefaultLazyInstanceTraits {
|
||||
static const bool kRegisterOnExit = true;
|
||||
#ifndef NDEBUG
|
||||
static const bool kAllowedToAccessOnNonjoinableThread = false;
|
||||
#endif
|
||||
|
||||
static Type* New(void* instance) {
|
||||
DCHECK_EQ(reinterpret_cast<uintptr_t>(instance) & (ALIGNOF(Type) - 1), 0u)
|
||||
<< ": Bad boy, the buffer passed to placement new is not aligned!\n"
|
||||
"This may break some stuff like SSE-based optimizations assuming the "
|
||||
"<Type> objects are word aligned.";
|
||||
// Use placement new to initialize our instance in our preallocated space.
|
||||
// The parenthesis is very important here to force POD type initialization.
|
||||
return new (instance) Type();
|
||||
}
|
||||
static void Delete(Type* instance) {
|
||||
// Explicitly call the destructor.
|
||||
instance->~Type();
|
||||
}
|
||||
};
|
||||
|
||||
// We pull out some of the functionality into non-templated functions, so we
|
||||
// can implement the more complicated pieces out of line in the .cc file.
|
||||
namespace internal {
|
||||
|
||||
// Use LazyInstance<T>::Leaky for a less-verbose call-site typedef; e.g.:
|
||||
// base::LazyInstance<T>::Leaky my_leaky_lazy_instance;
|
||||
// instead of:
|
||||
// base::LazyInstance<T, base::internal::LeakyLazyInstanceTraits<T> >
|
||||
// my_leaky_lazy_instance;
|
||||
// (especially when T is MyLongTypeNameImplClientHolderFactory).
|
||||
// Only use this internal::-qualified verbose form to extend this traits class
|
||||
// (depending on its implementation details).
|
||||
template <typename Type>
|
||||
struct LeakyLazyInstanceTraits {
|
||||
static const bool kRegisterOnExit = false;
|
||||
#ifndef NDEBUG
|
||||
static const bool kAllowedToAccessOnNonjoinableThread = true;
|
||||
#endif
|
||||
|
||||
static Type* New(void* instance) {
|
||||
ANNOTATE_SCOPED_MEMORY_LEAK;
|
||||
return DefaultLazyInstanceTraits<Type>::New(instance);
|
||||
}
|
||||
static void Delete(Type* instance) {
|
||||
}
|
||||
};
|
||||
|
||||
// Our AtomicWord doubles as a spinlock, where a value of
|
||||
// kBeingCreatedMarker means the spinlock is being held for creation.
|
||||
static const subtle::AtomicWord kLazyInstanceStateCreating = 1;
|
||||
|
||||
// Check if instance needs to be created. If so return true otherwise
|
||||
// if another thread has beat us, wait for instance to be created and
|
||||
// return false.
|
||||
BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);
|
||||
|
||||
// After creating an instance, call this to register the dtor to be called
|
||||
// at program exit and to update the atomic state to hold the |new_instance|
|
||||
BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,
|
||||
subtle::AtomicWord new_instance,
|
||||
void* lazy_instance,
|
||||
void (*dtor)(void*));
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Type, typename Traits = DefaultLazyInstanceTraits<Type> >
|
||||
class LazyInstance {
|
||||
public:
|
||||
// Do not define a destructor, as doing so makes LazyInstance a
|
||||
// non-POD-struct. We don't want that because then a static initializer will
|
||||
// be created to register the (empty) destructor with atexit() under MSVC, for
|
||||
// example. We handle destruction of the contained Type class explicitly via
|
||||
// the OnExit member function, where needed.
|
||||
// ~LazyInstance() {}
|
||||
|
||||
// Convenience typedef to avoid having to repeat Type for leaky lazy
|
||||
// instances.
|
||||
typedef LazyInstance<Type, internal::LeakyLazyInstanceTraits<Type> > Leaky;
|
||||
|
||||
Type& Get() {
|
||||
return *Pointer();
|
||||
}
|
||||
|
||||
Type* Pointer() {
|
||||
#ifndef NDEBUG
|
||||
// Avoid making TLS lookup on release builds.
|
||||
if (!Traits::kAllowedToAccessOnNonjoinableThread)
|
||||
ThreadRestrictions::AssertSingletonAllowed();
|
||||
#endif
|
||||
// If any bit in the created mask is true, the instance has already been
|
||||
// fully constructed.
|
||||
static const subtle::AtomicWord kLazyInstanceCreatedMask =
|
||||
~internal::kLazyInstanceStateCreating;
|
||||
|
||||
// We will hopefully have fast access when the instance is already created.
|
||||
// Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating
|
||||
// at most once, the load is taken out of NeedsInstance() as a fast-path.
|
||||
// The load has acquire memory ordering as a thread which sees
|
||||
// private_instance_ > creating needs to acquire visibility over
|
||||
// the associated data (private_buf_). Pairing Release_Store is in
|
||||
// CompleteLazyInstance().
|
||||
subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_);
|
||||
if (!(value & kLazyInstanceCreatedMask) &&
|
||||
internal::NeedsLazyInstance(&private_instance_)) {
|
||||
// Create the instance in the space provided by |private_buf_|.
|
||||
value = reinterpret_cast<subtle::AtomicWord>(
|
||||
Traits::New(private_buf_.void_data()));
|
||||
internal::CompleteLazyInstance(&private_instance_, value, this,
|
||||
Traits::kRegisterOnExit ? OnExit : NULL);
|
||||
}
|
||||
return instance();
|
||||
}
|
||||
|
||||
bool operator==(Type* p) {
|
||||
switch (subtle::NoBarrier_Load(&private_instance_)) {
|
||||
case 0:
|
||||
return p == NULL;
|
||||
case internal::kLazyInstanceStateCreating:
|
||||
return static_cast<void*>(p) == private_buf_.void_data();
|
||||
default:
|
||||
return p == instance();
|
||||
}
|
||||
}
|
||||
|
||||
// Effectively private: member data is only public to allow the linker to
|
||||
// statically initialize it and to maintain a POD class. DO NOT USE FROM
|
||||
// OUTSIDE THIS CLASS.
|
||||
|
||||
subtle::AtomicWord private_instance_;
|
||||
// Preallocated space for the Type instance.
|
||||
base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> private_buf_;
|
||||
|
||||
private:
|
||||
Type* instance() {
|
||||
return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_));
|
||||
}
|
||||
|
||||
// Adapter function for use with AtExit. This should be called single
|
||||
// threaded, so don't synchronize across threads.
|
||||
// Calling OnExit while the instance is in use by other threads is a mistake.
|
||||
static void OnExit(void* lazy_instance) {
|
||||
LazyInstance<Type, Traits>* me =
|
||||
reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);
|
||||
Traits::Delete(me->instance());
|
||||
subtle::NoBarrier_Store(&me->private_instance_, 0);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_LAZY_INSTANCE_H_
|
||||
@@ -1,106 +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.
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include "base/location.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
|
||||
namespace tracked_objects {
|
||||
|
||||
Location::Location(const char* function_name,
|
||||
const char* file_name,
|
||||
int line_number,
|
||||
const void* program_counter)
|
||||
: function_name_(function_name),
|
||||
file_name_(file_name),
|
||||
line_number_(line_number),
|
||||
program_counter_(program_counter) {
|
||||
}
|
||||
|
||||
Location::Location()
|
||||
: function_name_("Unknown"),
|
||||
file_name_("Unknown"),
|
||||
line_number_(-1),
|
||||
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_);
|
||||
}
|
||||
|
||||
void Location::Write(bool display_filename, bool display_function_name,
|
||||
std::string* output) const {
|
||||
base::StringAppendF(output, "%s[%d] ",
|
||||
display_filename ? file_name_ : "line",
|
||||
line_number_);
|
||||
|
||||
if (display_function_name) {
|
||||
WriteFunctionName(output);
|
||||
output->push_back(' ');
|
||||
}
|
||||
}
|
||||
|
||||
void Location::WriteFunctionName(std::string* output) const {
|
||||
// Translate "<" to "<" for HTML safety.
|
||||
// TODO(jar): Support ASCII or html for logging in ASCII.
|
||||
for (const char *p = function_name_; *p; p++) {
|
||||
switch (*p) {
|
||||
case '<':
|
||||
output->append("<");
|
||||
break;
|
||||
|
||||
case '>':
|
||||
output->append(">");
|
||||
break;
|
||||
|
||||
default:
|
||||
output->push_back(*p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
LocationSnapshot::LocationSnapshot() : line_number(-1) {
|
||||
}
|
||||
|
||||
LocationSnapshot::LocationSnapshot(
|
||||
const tracked_objects::Location& location)
|
||||
: file_name(location.file_name()),
|
||||
function_name(location.function_name()),
|
||||
line_number(location.line_number()) {
|
||||
}
|
||||
|
||||
LocationSnapshot::~LocationSnapshot() {
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
#if defined(COMPILER_MSVC)
|
||||
__declspec(noinline)
|
||||
#endif
|
||||
BASE_EXPORT const void* GetProgramCounter() {
|
||||
#if defined(COMPILER_MSVC)
|
||||
return _ReturnAddress();
|
||||
#elif defined(COMPILER_GCC) && !defined(OS_NACL)
|
||||
return __builtin_extract_return_addr(__builtin_return_address(0));
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace tracked_objects
|
||||
@@ -1,110 +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_LOCATION_H_
|
||||
#define BASE_LOCATION_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/containers/hash_tables.h"
|
||||
|
||||
namespace tracked_objects {
|
||||
|
||||
// Location provides basic info where of an object was constructed, or was
|
||||
// significantly brought to life.
|
||||
class BASE_EXPORT Location {
|
||||
public:
|
||||
// Constructor should be called with a long-lived char*, such as __FILE__.
|
||||
// It assumes the provided value will persist as a global constant, and it
|
||||
// will not make a copy of it.
|
||||
Location(const char* function_name,
|
||||
const char* file_name,
|
||||
int line_number,
|
||||
const void* program_counter);
|
||||
|
||||
// Provide a default constructor for easy of debugging.
|
||||
Location();
|
||||
|
||||
// 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_; }
|
||||
const char* file_name() const { return file_name_; }
|
||||
int line_number() const { return line_number_; }
|
||||
const void* program_counter() const { return program_counter_; }
|
||||
|
||||
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
|
||||
// optional, and controlled by the boolean arguments.
|
||||
void Write(bool display_filename, bool display_function_name,
|
||||
std::string* output) const;
|
||||
|
||||
// Write function_name_ in HTML with '<' and '>' properly encoded.
|
||||
void WriteFunctionName(std::string* output) const;
|
||||
|
||||
private:
|
||||
const char* function_name_;
|
||||
const char* file_name_;
|
||||
int line_number_;
|
||||
const void* program_counter_;
|
||||
};
|
||||
|
||||
// A "snapshotted" representation of the Location class that can safely be
|
||||
// passed across process boundaries.
|
||||
struct BASE_EXPORT LocationSnapshot {
|
||||
// The default constructor is exposed to support the IPC serialization macros.
|
||||
LocationSnapshot();
|
||||
explicit LocationSnapshot(const tracked_objects::Location& location);
|
||||
~LocationSnapshot();
|
||||
|
||||
std::string file_name;
|
||||
std::string function_name;
|
||||
int line_number;
|
||||
};
|
||||
|
||||
BASE_EXPORT const void* GetProgramCounter();
|
||||
|
||||
// Define a macro to record the current source location.
|
||||
#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__FUNCTION__)
|
||||
|
||||
#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name) \
|
||||
::tracked_objects::Location(function_name, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
::tracked_objects::GetProgramCounter())
|
||||
|
||||
} // namespace tracked_objects
|
||||
|
||||
#endif // BASE_LOCATION_H_
|
||||
@@ -1,976 +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_LOGGING_H_
|
||||
#define BASE_LOGGING_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/debug/debugger.h"
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
//
|
||||
// Optional message capabilities
|
||||
// -----------------------------
|
||||
// Assertion failed messages and fatal errors are displayed in a dialog box
|
||||
// before the application exits. However, running this UI creates a message
|
||||
// loop, which causes application messages to be processed and potentially
|
||||
// dispatched to existing application windows. Since the application is in a
|
||||
// bad state when this assertion dialog is displayed, these messages may not
|
||||
// get processed and hang the dialog, or the application might go crazy.
|
||||
//
|
||||
// Therefore, it can be beneficial to display the error dialog in a separate
|
||||
// process from the main application. When the logging system needs to display
|
||||
// a fatal error dialog box, it will look for a program called
|
||||
// "DebugMessage.exe" in the same directory as the application executable. It
|
||||
// will run this application with the message as the command line, and will
|
||||
// not include the name of the application as is traditional for easier
|
||||
// parsing.
|
||||
//
|
||||
// The code for DebugMessage.exe is only one line. In WinMain, do:
|
||||
// MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
|
||||
//
|
||||
// If DebugMessage.exe is not found, the logging code will use a normal
|
||||
// MessageBox, potentially causing the problems discussed above.
|
||||
|
||||
|
||||
// Instructions
|
||||
// ------------
|
||||
//
|
||||
// Make a bunch of macros for logging. The way to log things is to stream
|
||||
// things to LOG(<a particular severity level>). E.g.,
|
||||
//
|
||||
// LOG(INFO) << "Found " << num_cookies << " cookies";
|
||||
//
|
||||
// You can also do conditional logging:
|
||||
//
|
||||
// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
|
||||
//
|
||||
// The CHECK(condition) macro is active in both debug and release builds and
|
||||
// effectively performs a LOG(FATAL) which terminates the process and
|
||||
// generates a crashdump unless a debugger is attached.
|
||||
//
|
||||
// There are also "debug mode" logging macros like the ones above:
|
||||
//
|
||||
// DLOG(INFO) << "Found cookies";
|
||||
//
|
||||
// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
|
||||
//
|
||||
// All "debug mode" logging is compiled away to nothing for non-debug mode
|
||||
// compiles. LOG_IF and development flags also work well together
|
||||
// because the code can be compiled away sometimes.
|
||||
//
|
||||
// We also have
|
||||
//
|
||||
// LOG_ASSERT(assertion);
|
||||
// DLOG_ASSERT(assertion);
|
||||
//
|
||||
// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
|
||||
//
|
||||
// There are "verbose level" logging macros. They look like
|
||||
//
|
||||
// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
|
||||
// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
|
||||
//
|
||||
// These always log at the INFO log level (when they log at all).
|
||||
// The verbose logging can also be turned on module-by-module. For instance,
|
||||
// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0
|
||||
// will cause:
|
||||
// a. VLOG(2) and lower messages to be printed from profile.{h,cc}
|
||||
// b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
|
||||
// c. VLOG(3) and lower messages to be printed from files prefixed with
|
||||
// "browser"
|
||||
// d. VLOG(4) and lower messages to be printed from files under a
|
||||
// "chromeos" directory.
|
||||
// e. VLOG(0) and lower messages to be printed from elsewhere
|
||||
//
|
||||
// The wildcarding functionality shown by (c) supports both '*' (match
|
||||
// 0 or more characters) and '?' (match any single character)
|
||||
// wildcards. Any pattern containing a forward or backward slash will
|
||||
// be tested against the whole pathname and not just the module.
|
||||
// E.g., "*/foo/bar/*=2" would change the logging level for all code
|
||||
// in source files under a "foo/bar" directory.
|
||||
//
|
||||
// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
|
||||
//
|
||||
// if (VLOG_IS_ON(2)) {
|
||||
// // do some logging preparation and logging
|
||||
// // that can't be accomplished with just VLOG(2) << ...;
|
||||
// }
|
||||
//
|
||||
// There is also a VLOG_IF "verbose level" condition macro for sample
|
||||
// cases, when some extra computation and preparation for logs is not
|
||||
// needed.
|
||||
//
|
||||
// VLOG_IF(1, (size > 1024))
|
||||
// << "I'm printed when size is more than 1024 and when you run the "
|
||||
// "program with --v=1 or more";
|
||||
//
|
||||
// We also override the standard 'assert' to use 'DLOG_ASSERT'.
|
||||
//
|
||||
// Lastly, there is:
|
||||
//
|
||||
// PLOG(ERROR) << "Couldn't do foo";
|
||||
// DPLOG(ERROR) << "Couldn't do foo";
|
||||
// PLOG_IF(ERROR, cond) << "Couldn't do foo";
|
||||
// DPLOG_IF(ERROR, cond) << "Couldn't do foo";
|
||||
// PCHECK(condition) << "Couldn't do foo";
|
||||
// DPCHECK(condition) << "Couldn't do foo";
|
||||
//
|
||||
// which append the last system error to the message in string form (taken from
|
||||
// GetLastError() on Windows and errno on POSIX).
|
||||
//
|
||||
// The supported severity levels for macros that allow you to specify one
|
||||
// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
|
||||
//
|
||||
// Very important: logging a message at the FATAL severity level causes
|
||||
// the program to terminate (after the message is logged).
|
||||
//
|
||||
// There is the special severity of DFATAL, which logs FATAL in debug mode,
|
||||
// ERROR in normal mode.
|
||||
|
||||
namespace logging {
|
||||
|
||||
// TODO(avi): do we want to do a unification of character types here?
|
||||
#if defined(OS_WIN)
|
||||
typedef wchar_t PathChar;
|
||||
#else
|
||||
typedef char PathChar;
|
||||
#endif
|
||||
|
||||
// Where to record logging output? A flat file and/or system debug log
|
||||
// via OutputDebugString.
|
||||
enum LoggingDestination {
|
||||
LOG_NONE = 0,
|
||||
LOG_TO_FILE = 1 << 0,
|
||||
LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1,
|
||||
|
||||
LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG,
|
||||
|
||||
// On Windows, use a file next to the exe; on POSIX platforms, where
|
||||
// it may not even be possible to locate the executable on disk, use
|
||||
// stderr.
|
||||
#if defined(OS_WIN)
|
||||
LOG_DEFAULT = LOG_TO_FILE,
|
||||
#elif defined(OS_POSIX)
|
||||
LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG,
|
||||
#endif
|
||||
};
|
||||
|
||||
// Indicates that the log file should be locked when being written to.
|
||||
// Unless there is only one single-threaded process that is logging to
|
||||
// the log file, the file should be locked during writes to make each
|
||||
// log output atomic. Other writers will block.
|
||||
//
|
||||
// All processes writing to the log file must have their locking set for it to
|
||||
// work properly. Defaults to LOCK_LOG_FILE.
|
||||
enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
|
||||
|
||||
// On startup, should we delete or append to an existing log file (if any)?
|
||||
// Defaults to APPEND_TO_OLD_LOG_FILE.
|
||||
enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
|
||||
|
||||
struct BASE_EXPORT LoggingSettings {
|
||||
// The defaults values are:
|
||||
//
|
||||
// logging_dest: LOG_DEFAULT
|
||||
// log_file: NULL
|
||||
// lock_log: LOCK_LOG_FILE
|
||||
// delete_old: APPEND_TO_OLD_LOG_FILE
|
||||
LoggingSettings();
|
||||
|
||||
LoggingDestination logging_dest;
|
||||
|
||||
// The three settings below have an effect only when LOG_TO_FILE is
|
||||
// set in |logging_dest|.
|
||||
const PathChar* log_file;
|
||||
LogLockingState lock_log;
|
||||
OldFileDeletionState delete_old;
|
||||
};
|
||||
|
||||
// Define different names for the BaseInitLoggingImpl() function depending on
|
||||
// whether NDEBUG is defined or not so that we'll fail to link if someone tries
|
||||
// to compile logging.cc with NDEBUG but includes logging.h without defining it,
|
||||
// or vice versa.
|
||||
#if NDEBUG
|
||||
#define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG
|
||||
#else
|
||||
#define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG
|
||||
#endif
|
||||
|
||||
// Implementation of the InitLogging() method declared below. We use a
|
||||
// more-specific name so we can #define it above without affecting other code
|
||||
// that has named stuff "InitLogging".
|
||||
BASE_EXPORT bool BaseInitLoggingImpl(const LoggingSettings& settings);
|
||||
|
||||
// Sets the log file name and other global logging state. Calling this function
|
||||
// is recommended, and is normally done at the beginning of application init.
|
||||
// If you don't call it, all the flags will be initialized to their default
|
||||
// values, and there is a race condition that may leak a critical section
|
||||
// object if two threads try to do the first log at the same time.
|
||||
// See the definition of the enums above for descriptions and default values.
|
||||
//
|
||||
// The default log file is initialized to "debug.log" in the application
|
||||
// directory. You probably don't want this, especially since the program
|
||||
// directory may not be writable on an enduser's system.
|
||||
//
|
||||
// This function may be called a second time to re-direct logging (e.g after
|
||||
// loging in to a user partition), however it should never be called more than
|
||||
// twice.
|
||||
inline bool InitLogging(const LoggingSettings& settings) {
|
||||
return BaseInitLoggingImpl(settings);
|
||||
}
|
||||
|
||||
// Sets the log level. Anything at or above this level will be written to the
|
||||
// log file/displayed to the user (if applicable). Anything below this level
|
||||
// will be silently ignored. The log level defaults to 0 (everything is logged
|
||||
// up to level INFO) if this function is not called.
|
||||
// Note that log messages for VLOG(x) are logged at level -x, so setting
|
||||
// the min log level to negative values enables verbose logging.
|
||||
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();
|
||||
|
||||
// Gets the current vlog level for the given file (usually taken from
|
||||
// __FILE__).
|
||||
|
||||
// Note that |N| is the size *with* the null terminator.
|
||||
BASE_EXPORT int GetVlogLevelHelper(const char* file_start, size_t N);
|
||||
|
||||
template <size_t N>
|
||||
int GetVlogLevel(const char (&file)[N]) {
|
||||
return GetVlogLevelHelper(file, N);
|
||||
}
|
||||
|
||||
// Sets the common items you want to be prepended to each log message.
|
||||
// process and thread IDs default to off, the timestamp defaults to on.
|
||||
// If this function is not called, logging defaults to writing the timestamp
|
||||
// only.
|
||||
BASE_EXPORT void SetLogItems(bool enable_process_id, bool enable_thread_id,
|
||||
bool enable_timestamp, bool enable_tickcount);
|
||||
|
||||
// Sets whether or not you'd like to see fatal debug messages popped up in
|
||||
// a dialog box or not.
|
||||
// Dialogs are not shown by default.
|
||||
BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs);
|
||||
|
||||
// Sets the Log Assert Handler that will be used to notify of check failures.
|
||||
// The default handler shows a dialog box and then terminate the process,
|
||||
// however clients can use this function to override with their own handling
|
||||
// (e.g. a silent one for Unit Tests)
|
||||
typedef void (*LogAssertHandlerFunction)(const std::string& str);
|
||||
BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler);
|
||||
|
||||
// Sets the Log Message Handler that gets passed every log message before
|
||||
// it's sent to other log destinations (if any).
|
||||
// Returns true to signal that it handled the message and the message
|
||||
// should not be sent to other log destinations.
|
||||
typedef bool (*LogMessageHandlerFunction)(int severity,
|
||||
const char* file, int line, size_t message_start, const std::string& str);
|
||||
BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler);
|
||||
BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler();
|
||||
|
||||
typedef int LogSeverity;
|
||||
const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity
|
||||
// Note: the log severities are used to index into the array of names,
|
||||
// see log_severity_names.
|
||||
const LogSeverity LOG_INFO = 0;
|
||||
const LogSeverity LOG_WARNING = 1;
|
||||
const LogSeverity LOG_ERROR = 2;
|
||||
const LogSeverity LOG_FATAL = 3;
|
||||
const LogSeverity LOG_NUM_SEVERITIES = 4;
|
||||
|
||||
// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode
|
||||
#ifdef NDEBUG
|
||||
const LogSeverity LOG_DFATAL = LOG_ERROR;
|
||||
#else
|
||||
const LogSeverity LOG_DFATAL = LOG_FATAL;
|
||||
#endif
|
||||
|
||||
// A few definitions of macros that don't generate much code. These are used
|
||||
// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
|
||||
// better to have compact code for these operations.
|
||||
#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
|
||||
logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__)
|
||||
#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
|
||||
logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__)
|
||||
#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
|
||||
logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__)
|
||||
#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
|
||||
logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__)
|
||||
#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
|
||||
logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__)
|
||||
|
||||
#define COMPACT_GOOGLE_LOG_INFO \
|
||||
COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
|
||||
#define COMPACT_GOOGLE_LOG_WARNING \
|
||||
COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
|
||||
#define COMPACT_GOOGLE_LOG_ERROR \
|
||||
COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
|
||||
#define COMPACT_GOOGLE_LOG_FATAL \
|
||||
COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
|
||||
#define COMPACT_GOOGLE_LOG_DFATAL \
|
||||
COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
|
||||
// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
|
||||
// to keep using this syntax, we define this macro to do the same thing
|
||||
// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
|
||||
// the Windows SDK does for consistency.
|
||||
#define ERROR 0
|
||||
#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \
|
||||
COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__)
|
||||
#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
|
||||
// Needed for LOG_IS_ON(ERROR).
|
||||
const LogSeverity LOG_0 = LOG_ERROR;
|
||||
#endif
|
||||
|
||||
// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also,
|
||||
// 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::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
|
||||
// that using the v-logging functions in conjunction with --vmodule
|
||||
// may be slow.
|
||||
#define VLOG_IS_ON(verboselevel) \
|
||||
((verboselevel) <= ::logging::GetVlogLevel(__FILE__))
|
||||
|
||||
// Helper macro which avoids evaluating the arguments to a stream if
|
||||
// the condition doesn't hold. Condition is evaluated once and only once.
|
||||
#define LAZY_STREAM(stream, condition) \
|
||||
!(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)
|
||||
|
||||
// We use the preprocessor's merging operator, "##", so that, e.g.,
|
||||
// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny
|
||||
// subtle difference between ostream member streaming functions (e.g.,
|
||||
// ostream::operator<<(int) and ostream non-member streaming functions
|
||||
// (e.g., ::operator<<(ostream&, string&): it turns out that it's
|
||||
// impossible to stream something like a string directly to an unnamed
|
||||
// ostream. We employ a neat hack by calling the stream() member
|
||||
// function of LogMessage which seems to avoid the problem.
|
||||
#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
|
||||
|
||||
#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))
|
||||
#define LOG_IF(severity, condition) \
|
||||
LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
|
||||
|
||||
#define SYSLOG(severity) LOG(severity)
|
||||
#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
|
||||
|
||||
// The VLOG macros log with negative verbosities.
|
||||
#define VLOG_STREAM(verbose_level) \
|
||||
logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
|
||||
|
||||
#define VLOG(verbose_level) \
|
||||
LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
|
||||
|
||||
#define VLOG_IF(verbose_level, condition) \
|
||||
LAZY_STREAM(VLOG_STREAM(verbose_level), \
|
||||
VLOG_IS_ON(verbose_level) && (condition))
|
||||
|
||||
#if defined (OS_WIN)
|
||||
#define VPLOG_STREAM(verbose_level) \
|
||||
logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
|
||||
::logging::GetLastSystemErrorCode()).stream()
|
||||
#elif defined(OS_POSIX)
|
||||
#define VPLOG_STREAM(verbose_level) \
|
||||
logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
|
||||
::logging::GetLastSystemErrorCode()).stream()
|
||||
#endif
|
||||
|
||||
#define VPLOG(verbose_level) \
|
||||
LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
|
||||
|
||||
#define VPLOG_IF(verbose_level, condition) \
|
||||
LAZY_STREAM(VPLOG_STREAM(verbose_level), \
|
||||
VLOG_IS_ON(verbose_level) && (condition))
|
||||
|
||||
// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
|
||||
|
||||
#define LOG_ASSERT(condition) \
|
||||
LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
|
||||
#define SYSLOG_ASSERT(condition) \
|
||||
SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#define PLOG_STREAM(severity) \
|
||||
COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
|
||||
::logging::GetLastSystemErrorCode()).stream()
|
||||
#elif defined(OS_POSIX)
|
||||
#define PLOG_STREAM(severity) \
|
||||
COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \
|
||||
::logging::GetLastSystemErrorCode()).stream()
|
||||
#endif
|
||||
|
||||
#define PLOG(severity) \
|
||||
LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity))
|
||||
|
||||
#define PLOG_IF(severity, condition) \
|
||||
LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
|
||||
|
||||
// The actual stream used isn't important.
|
||||
#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.
|
||||
//
|
||||
// We make sure CHECK et al. always evaluates their arguments, as
|
||||
// doing CHECK(FunctionWithSideEffect()) is a common idiom.
|
||||
|
||||
#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 (except Android).
|
||||
|
||||
// TODO(akalin): This would be more valuable if there were some way to
|
||||
// remove BreakDebugger() from the backtrace, perhaps by turning it
|
||||
// into a macro (like __debugbreak() on Windows).
|
||||
#define CHECK(condition) \
|
||||
!(condition) ? ::base::debug::BreakDebugger() : EAT_STREAM_PARAMETERS
|
||||
|
||||
#define PCHECK(condition) CHECK(condition)
|
||||
|
||||
#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
|
||||
|
||||
#else
|
||||
|
||||
#if defined(_PREFAST_) && defined(OS_WIN)
|
||||
// Use __analysis_assume to tell the VC++ static analysis engine that
|
||||
// assert conditions are true, to suppress warnings. The LAZY_STREAM
|
||||
// parameter doesn't reference 'condition' in /analyze builds because
|
||||
// this evaluation confuses /analyze. The !! before condition is because
|
||||
// __analysis_assume gets confused on some conditions:
|
||||
// http://randomascii.wordpress.com/2011/09/13/analyze-for-visual-studio-the-ugly-part-5/
|
||||
|
||||
#define CHECK(condition) \
|
||||
__analysis_assume(!!(condition)), \
|
||||
LAZY_STREAM(LOG_STREAM(FATAL), false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#define PCHECK(condition) \
|
||||
__analysis_assume(!!(condition)), \
|
||||
LAZY_STREAM(PLOG_STREAM(FATAL), false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#else // _PREFAST_
|
||||
|
||||
// Do as much work as possible out of line to reduce inline code size.
|
||||
#define CHECK(condition) \
|
||||
LAZY_STREAM(logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
|
||||
!(condition))
|
||||
|
||||
#define PCHECK(condition) \
|
||||
LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#endif // _PREFAST_
|
||||
|
||||
// Helper macro for binary operators.
|
||||
// Don't use this macro directly in your code, use CHECK_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)
|
||||
// CHECK_EQ(2, a);
|
||||
#define CHECK_OP(name, op, val1, val2) \
|
||||
switch (0) case 0: default: \
|
||||
if (logging::CheckOpResult true_if_passed = \
|
||||
logging::Check##name##Impl((val1), (val2), \
|
||||
#val1 " " #op " " #val2)) \
|
||||
; \
|
||||
else \
|
||||
logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
|
||||
|
||||
#endif
|
||||
|
||||
// Build the error message string. This is separate from the "Impl"
|
||||
// function template because it is not performance critical and so can
|
||||
// be out of line, while the "Impl" code should be inline. Caller
|
||||
// takes ownership of the returned string.
|
||||
template<class t1, class t2>
|
||||
std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
|
||||
std::ostringstream ss;
|
||||
ss << names << " (" << v1 << " vs. " << v2 << ")";
|
||||
std::string* msg = new std::string(ss.str());
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
|
||||
// in logging.cc.
|
||||
extern template BASE_EXPORT std::string* MakeCheckOpString<int, int>(
|
||||
const int&, const int&, const char* names);
|
||||
extern template BASE_EXPORT
|
||||
std::string* MakeCheckOpString<unsigned long, unsigned long>(
|
||||
const unsigned long&, const unsigned long&, const char* names);
|
||||
extern template BASE_EXPORT
|
||||
std::string* MakeCheckOpString<unsigned long, unsigned int>(
|
||||
const unsigned long&, const unsigned int&, const char* names);
|
||||
extern template BASE_EXPORT
|
||||
std::string* MakeCheckOpString<unsigned int, unsigned long>(
|
||||
const unsigned int&, const unsigned long&, const char* names);
|
||||
extern template BASE_EXPORT
|
||||
std::string* MakeCheckOpString<std::string, std::string>(
|
||||
const std::string&, const std::string&, const char* name);
|
||||
|
||||
// Helper functions for CHECK_OP macro.
|
||||
// The (int, int) specialization works around the issue that the compiler
|
||||
// will not instantiate the template version of the function on values of
|
||||
// unnamed enum type - see comment below.
|
||||
#define DEFINE_CHECK_OP_IMPL(name, op) \
|
||||
template <class t1, class t2> \
|
||||
inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
|
||||
const char* names) { \
|
||||
if (v1 op v2) return NULL; \
|
||||
else return MakeCheckOpString(v1, v2, names); \
|
||||
} \
|
||||
inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
|
||||
if (v1 op v2) return NULL; \
|
||||
else return MakeCheckOpString(v1, v2, names); \
|
||||
}
|
||||
DEFINE_CHECK_OP_IMPL(EQ, ==)
|
||||
DEFINE_CHECK_OP_IMPL(NE, !=)
|
||||
DEFINE_CHECK_OP_IMPL(LE, <=)
|
||||
DEFINE_CHECK_OP_IMPL(LT, < )
|
||||
DEFINE_CHECK_OP_IMPL(GE, >=)
|
||||
DEFINE_CHECK_OP_IMPL(GT, > )
|
||||
#undef DEFINE_CHECK_OP_IMPL
|
||||
|
||||
#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
|
||||
#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
|
||||
#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
|
||||
#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)
|
||||
|
||||
#if defined(NDEBUG)
|
||||
#define ENABLE_DLOG 0
|
||||
#else
|
||||
#define ENABLE_DLOG 1
|
||||
#endif
|
||||
|
||||
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
|
||||
#define DCHECK_IS_ON() 0
|
||||
#else
|
||||
#define DCHECK_IS_ON() 1
|
||||
#endif
|
||||
|
||||
// Definitions for DLOG et al.
|
||||
|
||||
#if ENABLE_DLOG
|
||||
|
||||
#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
|
||||
#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
|
||||
#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
|
||||
#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition)
|
||||
#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition)
|
||||
#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition)
|
||||
|
||||
#else // ENABLE_DLOG
|
||||
|
||||
// If ENABLE_DLOG is off, we want to avoid emitting any references to
|
||||
// |condition| (which may reference a variable defined only if NDEBUG
|
||||
// is not defined). Contrast this with DCHECK et al., which has
|
||||
// different behavior.
|
||||
|
||||
#define DLOG_IS_ON(severity) false
|
||||
#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
|
||||
#define DLOG_ASSERT(condition) EAT_STREAM_PARAMETERS
|
||||
#define DPLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
|
||||
#define DVLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
|
||||
#define DVPLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
|
||||
|
||||
#endif // ENABLE_DLOG
|
||||
|
||||
// DEBUG_MODE is for uses like
|
||||
// if (DEBUG_MODE) foo.CheckThatFoo();
|
||||
// instead of
|
||||
// #ifndef NDEBUG
|
||||
// foo.CheckThatFoo();
|
||||
// #endif
|
||||
//
|
||||
// We tie its state to ENABLE_DLOG.
|
||||
enum { DEBUG_MODE = ENABLE_DLOG };
|
||||
|
||||
#undef ENABLE_DLOG
|
||||
|
||||
#define DLOG(severity) \
|
||||
LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
|
||||
|
||||
#define DPLOG(severity) \
|
||||
LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity))
|
||||
|
||||
#define DVLOG(verboselevel) DVLOG_IF(verboselevel, VLOG_IS_ON(verboselevel))
|
||||
|
||||
#define DVPLOG(verboselevel) DVPLOG_IF(verboselevel, VLOG_IS_ON(verboselevel))
|
||||
|
||||
// Definitions for DCHECK et al.
|
||||
|
||||
#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()
|
||||
|
||||
// These are just dummy values.
|
||||
#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
|
||||
COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__)
|
||||
#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO
|
||||
const LogSeverity LOG_DCHECK = LOG_INFO;
|
||||
|
||||
#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
|
||||
// variable warnings if the only use of a variable is in a DCHECK.
|
||||
// This behavior is different from DLOG_IF et al.
|
||||
|
||||
#if defined(_PREFAST_) && defined(OS_WIN)
|
||||
// See comments on the previous use of __analysis_assume.
|
||||
|
||||
#define DCHECK(condition) \
|
||||
__analysis_assume(!!(condition)), \
|
||||
LAZY_STREAM(LOG_STREAM(DCHECK), false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#define DPCHECK(condition) \
|
||||
__analysis_assume(!!(condition)), \
|
||||
LAZY_STREAM(PLOG_STREAM(DCHECK), false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#else // _PREFAST_
|
||||
|
||||
#define DCHECK(condition) \
|
||||
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) \
|
||||
<< "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) \
|
||||
switch (0) case 0: default: \
|
||||
if (logging::CheckOpResult true_if_passed = \
|
||||
DCHECK_IS_ON() ? \
|
||||
logging::Check##name##Impl((val1), (val2), \
|
||||
#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
|
||||
// as expected. The values must have operator<<(ostream, ...)
|
||||
// defined.
|
||||
//
|
||||
// You may append to the error message like so:
|
||||
// DCHECK_NE(1, 2) << ": The world must be ending!";
|
||||
//
|
||||
// We are very careful to ensure that each argument is evaluated exactly
|
||||
// once, and that anything which is legal to pass as a function argument is
|
||||
// legal here. In particular, the arguments may be temporary expressions
|
||||
// which will end up being destroyed at the end of the apparent statement,
|
||||
// for example:
|
||||
// DCHECK_EQ(string("abc")[1], 'b');
|
||||
//
|
||||
// WARNING: These may not compile correctly if one of the arguments is a pointer
|
||||
// and the other is NULL. To work around this, simply static_cast NULL to the
|
||||
// type of the desired pointer.
|
||||
|
||||
#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
|
||||
#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
|
||||
#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
|
||||
#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)
|
||||
|
||||
#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
|
||||
|
||||
// Redefine the standard assert to use our nice log files
|
||||
#undef assert
|
||||
#define assert(x) DLOG_ASSERT(x)
|
||||
|
||||
// This class more or less represents a particular log message. You
|
||||
// create an instance of LogMessage and then stream stuff to it.
|
||||
// When you finish streaming to it, ~LogMessage is called and the
|
||||
// full message gets streamed to the appropriate destination.
|
||||
//
|
||||
// You shouldn't actually use LogMessage's constructor to log things,
|
||||
// though. You should use the LOG() macro (and variants thereof)
|
||||
// above.
|
||||
class BASE_EXPORT LogMessage {
|
||||
public:
|
||||
// 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);
|
||||
|
||||
// Used for DCHECK_EQ(), etc. Takes ownership of the given string.
|
||||
LogMessage(const char* file, int line, LogSeverity severity,
|
||||
std::string* result);
|
||||
|
||||
~LogMessage();
|
||||
|
||||
std::ostream& stream() { return stream_; }
|
||||
|
||||
private:
|
||||
void Init(const char* file, int line);
|
||||
|
||||
LogSeverity severity_;
|
||||
std::ostringstream stream_;
|
||||
size_t message_start_; // Offset of the start of the message (past prefix
|
||||
// info).
|
||||
// The file and line information passed in to the constructor.
|
||||
const char* file_;
|
||||
const int line_;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Stores the current value of GetLastError in the constructor and restores
|
||||
// it in the destructor by calling SetLastError.
|
||||
// This is useful since the LogMessage class uses a lot of Win32 calls
|
||||
// that will lose the value of GLE and the code that called the log function
|
||||
// will have lost the thread error value when the log call returns.
|
||||
class SaveLastError {
|
||||
public:
|
||||
SaveLastError();
|
||||
~SaveLastError();
|
||||
|
||||
unsigned long get_error() const { return last_error_; }
|
||||
|
||||
protected:
|
||||
unsigned long last_error_;
|
||||
};
|
||||
|
||||
SaveLastError last_error_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LogMessage);
|
||||
};
|
||||
|
||||
// A non-macro interface to the log facility; (useful
|
||||
// when the logging level is not a compile-time constant).
|
||||
inline void LogAtLevel(int log_level, const std::string& msg) {
|
||||
LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
|
||||
}
|
||||
|
||||
// This class is used to explicitly ignore values in the conditional
|
||||
// logging macros. This avoids compiler warnings like "value computed
|
||||
// is not used" and "statement has no effect".
|
||||
class LogMessageVoidify {
|
||||
public:
|
||||
LogMessageVoidify() { }
|
||||
// This has to be an operator with a precedence lower than << but
|
||||
// higher than ?:
|
||||
void operator&(std::ostream&) { }
|
||||
};
|
||||
|
||||
#if defined(OS_WIN)
|
||||
typedef unsigned long SystemErrorCode;
|
||||
#elif defined(OS_POSIX)
|
||||
typedef int SystemErrorCode;
|
||||
#endif
|
||||
|
||||
// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
|
||||
// pull in windows.h just for GetLastError() and DWORD.
|
||||
BASE_EXPORT SystemErrorCode GetLastSystemErrorCode();
|
||||
BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Appends a formatted system message of the GetLastError() type.
|
||||
class BASE_EXPORT Win32ErrorLogMessage {
|
||||
public:
|
||||
Win32ErrorLogMessage(const char* file,
|
||||
int line,
|
||||
LogSeverity severity,
|
||||
SystemErrorCode err);
|
||||
|
||||
// Appends the error message before destructing the encapsulated class.
|
||||
~Win32ErrorLogMessage();
|
||||
|
||||
std::ostream& stream() { return log_message_.stream(); }
|
||||
|
||||
private:
|
||||
SystemErrorCode err_;
|
||||
LogMessage log_message_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage);
|
||||
};
|
||||
#elif defined(OS_POSIX)
|
||||
// Appends a formatted system message of the errno type
|
||||
class BASE_EXPORT ErrnoLogMessage {
|
||||
public:
|
||||
ErrnoLogMessage(const char* file,
|
||||
int line,
|
||||
LogSeverity severity,
|
||||
SystemErrorCode err);
|
||||
|
||||
// Appends the error message before destructing the encapsulated class.
|
||||
~ErrnoLogMessage();
|
||||
|
||||
std::ostream& stream() { return log_message_.stream(); }
|
||||
|
||||
private:
|
||||
SystemErrorCode err_;
|
||||
LogMessage log_message_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage);
|
||||
};
|
||||
#endif // OS_WIN
|
||||
|
||||
// Closes the log file explicitly if open.
|
||||
// NOTE: Since the log file is opened as necessary by the action of logging
|
||||
// statements, there's no guarantee that it will stay closed
|
||||
// after this call.
|
||||
BASE_EXPORT void CloseLogFile();
|
||||
|
||||
// Async signal safe logging mechanism.
|
||||
BASE_EXPORT void RawLog(int level, const char* message);
|
||||
|
||||
#define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message)
|
||||
|
||||
#define RAW_CHECK(condition) \
|
||||
do { \
|
||||
if (!(condition)) \
|
||||
logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n"); \
|
||||
} 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
|
||||
|
||||
} // namespace logging
|
||||
|
||||
// Note that "The behavior of a C++ program is undefined if it adds declarations
|
||||
// or definitions to namespace std or to a namespace within namespace std unless
|
||||
// otherwise specified." --C++11[namespace.std]
|
||||
//
|
||||
// We've checked that this particular definition has the intended behavior on
|
||||
// our implementations, but it's prone to breaking in the future, and please
|
||||
// don't imitate this in your own definitions without checking with some
|
||||
// standard library experts.
|
||||
namespace std {
|
||||
// These functions are provided as a convenience for logging, which is where we
|
||||
// use streams (it is against Google style to use streams in other places). It
|
||||
// is designed to allow you to emit non-ASCII Unicode strings to the log file,
|
||||
// which is normally ASCII. It is relatively slow, so try not to use it for
|
||||
// common cases. Non-ASCII characters will be converted to UTF-8 by these
|
||||
// operators.
|
||||
BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
|
||||
inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
|
||||
return out << wstr.c_str();
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
// The NOTIMPLEMENTED() macro annotates codepaths which have
|
||||
// not been implemented yet.
|
||||
//
|
||||
// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY:
|
||||
// 0 -- Do nothing (stripped by compiler)
|
||||
// 1 -- Warn at compile time
|
||||
// 2 -- Fail at compile time
|
||||
// 3 -- Fail at runtime (DCHECK)
|
||||
// 4 -- [default] LOG(ERROR) at runtime
|
||||
// 5 -- LOG(ERROR) at runtime, only once per call-site
|
||||
|
||||
#ifndef NOTIMPLEMENTED_POLICY
|
||||
#if defined(OS_ANDROID) && defined(OFFICIAL_BUILD)
|
||||
#define NOTIMPLEMENTED_POLICY 0
|
||||
#else
|
||||
// Select default policy: LOG(ERROR)
|
||||
#define NOTIMPLEMENTED_POLICY 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(COMPILER_GCC)
|
||||
// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name
|
||||
// of the current function in the NOTIMPLEMENTED message.
|
||||
#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED"
|
||||
#endif
|
||||
|
||||
#if NOTIMPLEMENTED_POLICY == 0
|
||||
#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
|
||||
#elif NOTIMPLEMENTED_POLICY == 1
|
||||
// TODO, figure out how to generate a warning
|
||||
#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
|
||||
#elif NOTIMPLEMENTED_POLICY == 2
|
||||
#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
|
||||
#elif NOTIMPLEMENTED_POLICY == 3
|
||||
#define NOTIMPLEMENTED() NOTREACHED()
|
||||
#elif NOTIMPLEMENTED_POLICY == 4
|
||||
#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG
|
||||
#elif NOTIMPLEMENTED_POLICY == 5
|
||||
#define NOTIMPLEMENTED() do {\
|
||||
static bool logged_once = false;\
|
||||
LOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG;\
|
||||
logged_once = true;\
|
||||
} while(0);\
|
||||
EAT_STREAM_PARAMETERS
|
||||
#endif
|
||||
|
||||
#endif // BASE_LOGGING_H_
|
||||
@@ -1,87 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// This file contains macros and macro-like constructs (e.g., templates) that
|
||||
// are commonly used throughout Chromium source. (It may also contain things
|
||||
// that are closely related to things that are commonly used that belong in this
|
||||
// file.)
|
||||
|
||||
#ifndef BASE_MACROS_H_
|
||||
#define BASE_MACROS_H_
|
||||
|
||||
#include <stddef.h> // For size_t.
|
||||
|
||||
// Put this in the declarations for a class to be uncopyable.
|
||||
#define DISALLOW_COPY(TypeName) \
|
||||
TypeName(const TypeName&) = delete
|
||||
|
||||
// Put this in the declarations for a class to be unassignable.
|
||||
#define DISALLOW_ASSIGN(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
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
// A macro to disallow all the implicit constructors, namely the
|
||||
// default constructor, copy constructor and operator= functions.
|
||||
//
|
||||
// This should be used in the private: declarations for a class
|
||||
// that wants to prevent anyone from instantiating it. This is
|
||||
// especially useful for classes containing only static methods.
|
||||
#define DISALLOW_IMPLICIT_CONSTRUCTORS(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. 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];
|
||||
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
|
||||
|
||||
// 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:
|
||||
//
|
||||
// scoped_ptr<MyType> my_var = ...;
|
||||
// if (TakeOwnership(my_var.get()) == SUCCESS)
|
||||
// ignore_result(my_var.release());
|
||||
//
|
||||
template<typename T>
|
||||
inline void ignore_result(const T&) {
|
||||
}
|
||||
|
||||
// The following enum should be used only as a constructor argument to indicate
|
||||
// that the variable has static storage class, and that the constructor should
|
||||
// do nothing to its state. It indicates to the reader that it is legal to
|
||||
// declare a static instance of the class, provided the constructor is given
|
||||
// the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declare a
|
||||
// static variable that has a constructor or a destructor because invocation
|
||||
// order is undefined. However, IF the type can be initialized by filling with
|
||||
// zeroes (which the loader does for static variables), AND the destructor also
|
||||
// does nothing to the storage, AND there are no virtual methods, then a
|
||||
// constructor declared as
|
||||
// explicit MyClass(base::LinkerInitialized x) {}
|
||||
// and invoked as
|
||||
// static MyClass my_variable_name(base::LINKER_INITIALIZED);
|
||||
namespace base {
|
||||
enum LinkerInitialized { LINKER_INITIALIZED };
|
||||
|
||||
// Use these to declare and define a static local variable (static T;) so that
|
||||
// it is leaked so that its destructors are not called at exit. If you need
|
||||
// thread-safe initialization, use base/lazy_instance.h instead.
|
||||
#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \
|
||||
static type& name = *new type arguments
|
||||
|
||||
} // base
|
||||
|
||||
#endif // BASE_MACROS_H_
|
||||
@@ -1,117 +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.
|
||||
|
||||
// AlignedMemory is a POD type that gives you a portable way to specify static
|
||||
// or local stack data of a given alignment and size. For example, if you need
|
||||
// static storage for a class, but you want manual control over when the object
|
||||
// is constructed and destructed (you don't want static initialization and
|
||||
// destruction), use AlignedMemory:
|
||||
//
|
||||
// static AlignedMemory<sizeof(MyClass), ALIGNOF(MyClass)> my_class;
|
||||
//
|
||||
// // ... at runtime:
|
||||
// new(my_class.void_data()) MyClass();
|
||||
//
|
||||
// // ... use it:
|
||||
// MyClass* mc = my_class.data_as<MyClass>();
|
||||
//
|
||||
// // ... later, to destruct my_class:
|
||||
// my_class.data_as<MyClass>()->MyClass::~MyClass();
|
||||
//
|
||||
// Alternatively, a runtime sized aligned allocation can be created:
|
||||
//
|
||||
// float* my_array = static_cast<float*>(AlignedAlloc(size, alignment));
|
||||
//
|
||||
// // ... later, to release the memory:
|
||||
// AlignedFree(my_array);
|
||||
//
|
||||
// Or using scoped_ptr:
|
||||
//
|
||||
// scoped_ptr<float, AlignedFreeDeleter> my_array(
|
||||
// static_cast<float*>(AlignedAlloc(size, alignment)));
|
||||
|
||||
#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/compiler_specific.h"
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
// AlignedMemory is specialized for all supported alignments.
|
||||
// Make sure we get a compiler error if someone uses an unsupported alignment.
|
||||
template <size_t Size, size_t ByteAlignment>
|
||||
struct AlignedMemory {};
|
||||
|
||||
#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \
|
||||
template <size_t Size> \
|
||||
class AlignedMemory<Size, byte_alignment> { \
|
||||
public: \
|
||||
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_); } \
|
||||
template <typename Type> \
|
||||
Type* data_as() { \
|
||||
return static_cast<Type*>(void_data()); \
|
||||
} \
|
||||
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*); \
|
||||
}
|
||||
|
||||
// Specialization for all alignments is required because MSVC (as of VS 2008)
|
||||
// does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param).
|
||||
// Greater than 4096 alignment is not supported by some compilers, so 4096 is
|
||||
// the maximum specified here.
|
||||
BASE_DECL_ALIGNED_MEMORY(1);
|
||||
BASE_DECL_ALIGNED_MEMORY(2);
|
||||
BASE_DECL_ALIGNED_MEMORY(4);
|
||||
BASE_DECL_ALIGNED_MEMORY(8);
|
||||
BASE_DECL_ALIGNED_MEMORY(16);
|
||||
BASE_DECL_ALIGNED_MEMORY(32);
|
||||
BASE_DECL_ALIGNED_MEMORY(64);
|
||||
BASE_DECL_ALIGNED_MEMORY(128);
|
||||
BASE_DECL_ALIGNED_MEMORY(256);
|
||||
BASE_DECL_ALIGNED_MEMORY(512);
|
||||
BASE_DECL_ALIGNED_MEMORY(1024);
|
||||
BASE_DECL_ALIGNED_MEMORY(2048);
|
||||
BASE_DECL_ALIGNED_MEMORY(4096);
|
||||
|
||||
#undef BASE_DECL_ALIGNED_MEMORY
|
||||
|
||||
BASE_EXPORT void* AlignedAlloc(size_t size, size_t alignment);
|
||||
|
||||
inline void AlignedFree(void* ptr) {
|
||||
#if defined(COMPILER_MSVC)
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deleter for use with scoped_ptr. E.g., use as
|
||||
// scoped_ptr<Foo, base::AlignedFreeDeleter> foo;
|
||||
struct AlignedFreeDeleter {
|
||||
inline void operator()(void* ptr) const {
|
||||
AlignedFree(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_ALIGNED_MEMORY_H_
|
||||
@@ -1,64 +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_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
|
||||
#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/template_util.h"
|
||||
#include "base/tuple.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
// It is dangerous to post a task with a T* argument where T is a subtype of
|
||||
// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the
|
||||
// object may already have been deleted since it was not held with a
|
||||
// scoped_refptr. Example: http://crbug.com/27191
|
||||
// The following set of traits are designed to generate a compile error
|
||||
// whenever this antipattern is attempted.
|
||||
|
||||
namespace base {
|
||||
|
||||
// This is a base internal implementation file used by task.h and callback.h.
|
||||
// Not for public consumption, so we wrap it in namespace internal.
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
struct NeedsScopedRefptrButGetsRawPtr {
|
||||
#if defined(OS_WIN)
|
||||
enum {
|
||||
value = base::false_type::value
|
||||
};
|
||||
#else
|
||||
enum {
|
||||
// Human readable translation: you needed to be a scoped_refptr if you are a
|
||||
// raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase)
|
||||
// type.
|
||||
value = (is_pointer<T>::value &&
|
||||
(is_convertible<T, subtle::RefCountedBase*>::value ||
|
||||
is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename Params>
|
||||
struct ParamsUseScopedRefptrCorrectly {
|
||||
enum { value = 0 };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
|
||||
enum { value = 1 };
|
||||
};
|
||||
|
||||
template <typename Head, typename... Tail>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple<Head, Tail...>> {
|
||||
enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
|
||||
ParamsUseScopedRefptrCorrectly<Tuple<Tail...>>::value };
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
|
||||
@@ -1,53 +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.
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/threading/thread_collision_warner.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace subtle {
|
||||
|
||||
bool RefCountedThreadSafeBase::HasOneRef() const {
|
||||
return AtomicRefCountIsOne(
|
||||
&const_cast<RefCountedThreadSafeBase*>(this)->ref_count_);
|
||||
}
|
||||
|
||||
RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {
|
||||
#ifndef NDEBUG
|
||||
in_dtor_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
|
||||
#ifndef NDEBUG
|
||||
DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
|
||||
"calling Release()";
|
||||
#endif
|
||||
}
|
||||
|
||||
void RefCountedThreadSafeBase::AddRef() const {
|
||||
#ifndef NDEBUG
|
||||
DCHECK(!in_dtor_);
|
||||
#endif
|
||||
AtomicRefCountInc(&ref_count_);
|
||||
}
|
||||
|
||||
bool RefCountedThreadSafeBase::Release() const {
|
||||
#ifndef NDEBUG
|
||||
DCHECK(!in_dtor_);
|
||||
DCHECK(!AtomicRefCountIsZero(&ref_count_));
|
||||
#endif
|
||||
if (!AtomicRefCountDec(&ref_count_)) {
|
||||
#ifndef NDEBUG
|
||||
in_dtor_ = true;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace subtle
|
||||
|
||||
} // namespace base
|
||||
@@ -1,446 +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_MEMORY_REF_COUNTED_H_
|
||||
#define BASE_MEMORY_REF_COUNTED_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <iosfwd>
|
||||
|
||||
#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"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace subtle {
|
||||
|
||||
class BASE_EXPORT RefCountedBase {
|
||||
public:
|
||||
bool HasOneRef() const { return ref_count_ == 1; }
|
||||
|
||||
protected:
|
||||
RefCountedBase()
|
||||
: ref_count_(0)
|
||||
#ifndef NDEBUG
|
||||
, in_dtor_(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
~RefCountedBase() {
|
||||
#ifndef NDEBUG
|
||||
DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AddRef() const {
|
||||
// TODO(maruel): Add back once it doesn't assert 500 times/sec.
|
||||
// Current thread books the critical section "AddRelease"
|
||||
// without release it.
|
||||
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
|
||||
#ifndef NDEBUG
|
||||
DCHECK(!in_dtor_);
|
||||
#endif
|
||||
++ref_count_;
|
||||
}
|
||||
|
||||
// Returns true if the object should self-delete.
|
||||
bool Release() const {
|
||||
// TODO(maruel): Add back once it doesn't assert 500 times/sec.
|
||||
// Current thread books the critical section "AddRelease"
|
||||
// without release it.
|
||||
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
|
||||
#ifndef NDEBUG
|
||||
DCHECK(!in_dtor_);
|
||||
#endif
|
||||
if (--ref_count_ == 0) {
|
||||
#ifndef NDEBUG
|
||||
in_dtor_ = true;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable int ref_count_;
|
||||
#ifndef NDEBUG
|
||||
mutable bool in_dtor_;
|
||||
#endif
|
||||
|
||||
DFAKE_MUTEX(add_release_);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
|
||||
};
|
||||
|
||||
class BASE_EXPORT RefCountedThreadSafeBase {
|
||||
public:
|
||||
bool HasOneRef() const;
|
||||
|
||||
protected:
|
||||
RefCountedThreadSafeBase();
|
||||
~RefCountedThreadSafeBase();
|
||||
|
||||
void AddRef() const;
|
||||
|
||||
// Returns true if the object should self-delete.
|
||||
bool Release() const;
|
||||
|
||||
private:
|
||||
mutable AtomicRefCount ref_count_;
|
||||
#ifndef NDEBUG
|
||||
mutable bool in_dtor_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
|
||||
};
|
||||
|
||||
} // namespace subtle
|
||||
|
||||
//
|
||||
// A base class for reference counted classes. Otherwise, known as a cheap
|
||||
// knock-off of WebKit's RefCounted<T> class. To use this guy just extend your
|
||||
// class from it like so:
|
||||
//
|
||||
// class MyFoo : public base::RefCounted<MyFoo> {
|
||||
// ...
|
||||
// private:
|
||||
// friend class base::RefCounted<MyFoo>;
|
||||
// ~MyFoo();
|
||||
// };
|
||||
//
|
||||
// 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 {
|
||||
public:
|
||||
RefCounted() {}
|
||||
|
||||
void AddRef() const {
|
||||
subtle::RefCountedBase::AddRef();
|
||||
}
|
||||
|
||||
void Release() const {
|
||||
if (subtle::RefCountedBase::Release()) {
|
||||
delete static_cast<const T*>(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
~RefCounted() {}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
|
||||
};
|
||||
|
||||
// Forward declaration.
|
||||
template <class T, typename Traits> class RefCountedThreadSafe;
|
||||
|
||||
// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref
|
||||
// count reaches 0. Overload to delete it on a different thread etc.
|
||||
template<typename T>
|
||||
struct DefaultRefCountedThreadSafeTraits {
|
||||
static void Destruct(const T* x) {
|
||||
// Delete through RefCountedThreadSafe to make child classes only need to be
|
||||
// friend with RefCountedThreadSafe instead of this struct, which is an
|
||||
// implementation detail.
|
||||
RefCountedThreadSafe<T,
|
||||
DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// A thread-safe variant of RefCounted<T>
|
||||
//
|
||||
// class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// If you're using the default trait, then you should add compile time
|
||||
// asserts that no one else is deleting your object. i.e.
|
||||
// private:
|
||||
// friend class base::RefCountedThreadSafe<MyFoo>;
|
||||
// ~MyFoo();
|
||||
template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
|
||||
class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
|
||||
public:
|
||||
RefCountedThreadSafe() {}
|
||||
|
||||
void AddRef() const {
|
||||
subtle::RefCountedThreadSafeBase::AddRef();
|
||||
}
|
||||
|
||||
void Release() const {
|
||||
if (subtle::RefCountedThreadSafeBase::Release()) {
|
||||
Traits::Destruct(static_cast<const T*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
~RefCountedThreadSafe() {}
|
||||
|
||||
private:
|
||||
friend struct DefaultRefCountedThreadSafeTraits<T>;
|
||||
static void DeleteInternal(const T* x) { delete x; }
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
|
||||
};
|
||||
|
||||
//
|
||||
// A thread-safe wrapper for some piece of data so we can place other
|
||||
// things in scoped_refptrs<>.
|
||||
//
|
||||
template<typename T>
|
||||
class RefCountedData
|
||||
: public base::RefCountedThreadSafe< base::RefCountedData<T> > {
|
||||
public:
|
||||
RefCountedData() : data() {}
|
||||
RefCountedData(const T& in_value) : data(in_value) {}
|
||||
|
||||
T data;
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<base::RefCountedData<T> >;
|
||||
~RefCountedData() {}
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
//
|
||||
// A smart pointer class for reference counted objects. Use this class instead
|
||||
// of calling AddRef and Release manually on a reference counted object to
|
||||
// avoid common memory leaks caused by forgetting to Release an object
|
||||
// reference. Sample usage:
|
||||
//
|
||||
// class MyFoo : public RefCounted<MyFoo> {
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// void some_function() {
|
||||
// scoped_refptr<MyFoo> foo = new MyFoo();
|
||||
// foo->Method(param);
|
||||
// // |foo| is released when this function returns
|
||||
// }
|
||||
//
|
||||
// void some_other_function() {
|
||||
// scoped_refptr<MyFoo> foo = new MyFoo();
|
||||
// ...
|
||||
// foo = NULL; // explicitly releases |foo|
|
||||
// ...
|
||||
// if (foo)
|
||||
// foo->Method(param);
|
||||
// }
|
||||
//
|
||||
// The above examples show how scoped_refptr<T> acts like a pointer to T.
|
||||
// Given two scoped_refptr<T> classes, it is also possible to exchange
|
||||
// references between the two objects, like so:
|
||||
//
|
||||
// {
|
||||
// scoped_refptr<MyFoo> a = new MyFoo();
|
||||
// scoped_refptr<MyFoo> b;
|
||||
//
|
||||
// b.swap(a);
|
||||
// // now, |b| references the MyFoo object, and |a| references NULL.
|
||||
// }
|
||||
//
|
||||
// To make both |a| and |b| in the above example reference the same MyFoo
|
||||
// object, simply use the assignment operator:
|
||||
//
|
||||
// {
|
||||
// scoped_refptr<MyFoo> a = new MyFoo();
|
||||
// scoped_refptr<MyFoo> b;
|
||||
//
|
||||
// b = a;
|
||||
// // now, |a| and |b| each own a reference to the same MyFoo object.
|
||||
// }
|
||||
//
|
||||
template <class T>
|
||||
class scoped_refptr {
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
scoped_refptr() : ptr_(NULL) {
|
||||
}
|
||||
|
||||
scoped_refptr(T* p) : ptr_(p) {
|
||||
if (ptr_)
|
||||
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_);
|
||||
}
|
||||
|
||||
T* get() const { return ptr_; }
|
||||
|
||||
T& operator*() const {
|
||||
assert(ptr_ != NULL);
|
||||
return *ptr_;
|
||||
}
|
||||
|
||||
T* operator->() const {
|
||||
assert(ptr_ != NULL);
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
scoped_refptr<T>& operator=(T* p) {
|
||||
// AddRef first so that self assignment should work
|
||||
if (p)
|
||||
AddRef(p);
|
||||
T* old_ptr = ptr_;
|
||||
ptr_ = p;
|
||||
if (old_ptr)
|
||||
Release(old_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
|
||||
return *this = r.ptr_;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
|
||||
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;
|
||||
*pp = p;
|
||||
}
|
||||
|
||||
void swap(scoped_refptr<T>& r) {
|
||||
swap(&r.ptr_);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
bool operator!=(const scoped_refptr<U>& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
bool operator<(const scoped_refptr<U>& rhs) const {
|
||||
return ptr_ < rhs.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
T* ptr_;
|
||||
|
||||
private:
|
||||
// Non-inline helpers to allow:
|
||||
// class Opaque;
|
||||
// extern template class scoped_refptr<Opaque>;
|
||||
// Otherwise the compiler will complain that Opaque is an incomplete type.
|
||||
static void AddRef(T* ptr);
|
||||
static void Release(T* ptr);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void scoped_refptr<T>::AddRef(T* ptr) {
|
||||
ptr->AddRef();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void scoped_refptr<T>::Release(T* ptr) {
|
||||
ptr->Release();
|
||||
}
|
||||
|
||||
// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without
|
||||
// having to retype all the template arguments
|
||||
template <typename T>
|
||||
scoped_refptr<T> make_scoped_refptr(T* t) {
|
||||
return scoped_refptr<T>(t);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
|
||||
return lhs == rhs.get();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
|
||||
return out << p.get();
|
||||
}
|
||||
|
||||
#endif // BASE_MEMORY_REF_COUNTED_H_
|
||||
@@ -1,607 +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.
|
||||
|
||||
// Scopers help you manage ownership of a pointer, helping you easily manage a
|
||||
// pointer within a scope, and automatically destroying the pointer at the end
|
||||
// of a scope. There are two main classes you will use, which correspond to the
|
||||
// operators new/delete and new[]/delete[].
|
||||
//
|
||||
// Example usage (scoped_ptr<T>):
|
||||
// {
|
||||
// scoped_ptr<Foo> foo(new Foo("wee"));
|
||||
// } // foo goes out of scope, releasing the pointer with it.
|
||||
//
|
||||
// {
|
||||
// scoped_ptr<Foo> foo; // No pointer managed.
|
||||
// foo.reset(new Foo("wee")); // Now a pointer is managed.
|
||||
// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed.
|
||||
// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed.
|
||||
// foo->Method(); // Foo::Method() called.
|
||||
// foo.get()->Method(); // Foo::Method() called.
|
||||
// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer
|
||||
// // manages a pointer.
|
||||
// foo.reset(new Foo("wee4")); // foo manages a pointer again.
|
||||
// foo.reset(); // Foo("wee4") destroyed, foo no longer
|
||||
// // manages a pointer.
|
||||
// } // foo wasn't managing a pointer, so nothing was destroyed.
|
||||
//
|
||||
// Example usage (scoped_ptr<T[]>):
|
||||
// {
|
||||
// scoped_ptr<Foo[]> foo(new Foo[100]);
|
||||
// foo.get()->Method(); // Foo::Method on the 0th element.
|
||||
// foo[10].Method(); // Foo::Method on the 10th element.
|
||||
// }
|
||||
//
|
||||
// These scopers also implement part of the functionality of C++11 unique_ptr
|
||||
// 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 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.
|
||||
// }
|
||||
// scoped_ptr<Foo> CreateFoo() {
|
||||
// // 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;
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages 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(std::move(ptr2)); // ptr2 is correspondingly nullptr.
|
||||
// }
|
||||
//
|
||||
// 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 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().
|
||||
//
|
||||
// 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(std::move(foo));
|
||||
|
||||
#ifndef BASE_MEMORY_SCOPED_PTR_H_
|
||||
#define BASE_MEMORY_SCOPED_PTR_H_
|
||||
|
||||
// This is an implementation designed to match the anticipated future TR2
|
||||
// implementation of the scoped_ptr class.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/move.h"
|
||||
#include "base/template_util.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace subtle {
|
||||
class RefCountedBase;
|
||||
class RefCountedThreadSafeBase;
|
||||
} // namespace subtle
|
||||
|
||||
// Function object which invokes 'free' on its parameter, which must be
|
||||
// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
|
||||
//
|
||||
// scoped_ptr<int, base::FreeDeleter> foo_ptr(
|
||||
// static_cast<int*>(malloc(sizeof(int))));
|
||||
struct FreeDeleter {
|
||||
inline void operator()(void* ptr) const {
|
||||
free(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename T> struct IsNotRefCounted {
|
||||
enum {
|
||||
value = !base::is_convertible<T*, base::subtle::RefCountedBase*>::value &&
|
||||
!base::is_convertible<T*, base::subtle::RefCountedThreadSafeBase*>::
|
||||
value
|
||||
};
|
||||
};
|
||||
|
||||
// Minimal implementation of the core logic of scoped_ptr, suitable for
|
||||
// reuse in both scoped_ptr and its specializations.
|
||||
template <class T, class D>
|
||||
class scoped_ptr_impl {
|
||||
public:
|
||||
explicit scoped_ptr_impl(T* p) : data_(p) {}
|
||||
|
||||
// Initializer for deleters that have data parameters.
|
||||
scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
|
||||
|
||||
// Templated constructor that destructively takes the value from another
|
||||
// scoped_ptr_impl.
|
||||
template <typename U, typename V>
|
||||
scoped_ptr_impl(scoped_ptr_impl<U, V>* other)
|
||||
: data_(other->release(), other->get_deleter()) {
|
||||
// We do not support move-only deleters. We could modify our move
|
||||
// emulation to have base::subtle::move() and base::subtle::forward()
|
||||
// functions that are imperfect emulations of their C++11 equivalents,
|
||||
// but until there's a requirement, just assume deleters are copyable.
|
||||
}
|
||||
|
||||
template <typename U, typename V>
|
||||
void TakeState(scoped_ptr_impl<U, V>* other) {
|
||||
// See comment in templated constructor above regarding lack of support
|
||||
// for move-only deleters.
|
||||
reset(other->release());
|
||||
get_deleter() = other->get_deleter();
|
||||
}
|
||||
|
||||
~scoped_ptr_impl() {
|
||||
// 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) {
|
||||
// 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 = p;
|
||||
if (old != nullptr)
|
||||
static_cast<D&>(data_)(old);
|
||||
}
|
||||
|
||||
T* get() const { return data_.ptr; }
|
||||
|
||||
D& get_deleter() { return data_; }
|
||||
const D& get_deleter() const { return data_; }
|
||||
|
||||
void swap(scoped_ptr_impl& p2) {
|
||||
// Standard swap idiom: 'using std::swap' ensures that std::swap is
|
||||
// present in the overload set, but we call swap unqualified so that
|
||||
// any more-specific overloads can be used, if available.
|
||||
using std::swap;
|
||||
swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
|
||||
swap(data_.ptr, p2.data_.ptr);
|
||||
}
|
||||
|
||||
T* release() {
|
||||
T* old_ptr = data_.ptr;
|
||||
data_.ptr = nullptr;
|
||||
return old_ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// Needed to allow type-converting constructor.
|
||||
template <typename U, typename V> friend class scoped_ptr_impl;
|
||||
|
||||
// Use the empty base class optimization to allow us to have a D
|
||||
// member, while avoiding any space overhead for it when D is an
|
||||
// empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good
|
||||
// discussion of this technique.
|
||||
struct Data : public D {
|
||||
explicit Data(T* ptr_in) : ptr(ptr_in) {}
|
||||
Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
|
||||
T* ptr;
|
||||
};
|
||||
|
||||
Data data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace base
|
||||
|
||||
// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
|
||||
// automatically deletes the pointer it holds (if any).
|
||||
// That is, scoped_ptr<T> owns the T object that it points to.
|
||||
// Like a T*, a scoped_ptr<T> may hold either nullptr or a pointer to a T
|
||||
// object. Also like T*, scoped_ptr<T> is thread-compatible, and once you
|
||||
// dereference it, you get the thread safety guarantees of T.
|
||||
//
|
||||
// The size of scoped_ptr is small. On most compilers, when using the
|
||||
// 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 = std::default_delete<T>>
|
||||
class scoped_ptr {
|
||||
DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
|
||||
|
||||
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.
|
||||
using element_type = T;
|
||||
using deleter_type = D;
|
||||
|
||||
// Constructor. Defaults to initializing with nullptr.
|
||||
scoped_ptr() : impl_(nullptr) {}
|
||||
|
||||
// Constructor. Takes ownership of p.
|
||||
explicit scoped_ptr(element_type* p) : impl_(p) {}
|
||||
|
||||
// Constructor. Allows initialization of a stateful deleter.
|
||||
scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
|
||||
|
||||
// Constructor. Allows construction from a nullptr.
|
||||
scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
|
||||
|
||||
// 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++ 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. 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=(std::nullptr_t) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Reset. Deletes the currently owned object, if any.
|
||||
// Then takes ownership of a new object, if given.
|
||||
void reset(element_type* p = nullptr) { impl_.reset(p); }
|
||||
|
||||
// Accessors to get the owned object.
|
||||
// operator* and operator-> will assert() if there is no current object.
|
||||
element_type& operator*() const {
|
||||
assert(impl_.get() != nullptr);
|
||||
return *impl_.get();
|
||||
}
|
||||
element_type* operator->() const {
|
||||
assert(impl_.get() != nullptr);
|
||||
return impl_.get();
|
||||
}
|
||||
element_type* get() const { return impl_.get(); }
|
||||
|
||||
// Access to the deleter.
|
||||
deleter_type& get_deleter() { return impl_.get_deleter(); }
|
||||
const deleter_type& get_deleter() const { return impl_.get_deleter(); }
|
||||
|
||||
// Allow scoped_ptr<element_type> 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 "scoped_ptr1 ==
|
||||
// scoped_ptr2" will compile but do the wrong thing (i.e., convert
|
||||
// to Testable and then do the comparison).
|
||||
private:
|
||||
typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
|
||||
scoped_ptr::*Testable;
|
||||
|
||||
public:
|
||||
operator Testable() const {
|
||||
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
|
||||
}
|
||||
|
||||
// Swap two scoped pointers.
|
||||
void swap(scoped_ptr& p2) {
|
||||
impl_.swap(p2.impl_);
|
||||
}
|
||||
|
||||
// Release a pointer.
|
||||
// The return value is the current pointer held by this object. If this object
|
||||
// holds a nullptr, the return value is nullptr. After this operation, this
|
||||
// object will hold a nullptr, and will not own the object any more.
|
||||
element_type* release() WARN_UNUSED_RESULT {
|
||||
return impl_.release();
|
||||
}
|
||||
|
||||
private:
|
||||
// Needed to reach into |impl_| in the constructor.
|
||||
template <typename U, typename V> friend class scoped_ptr;
|
||||
base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
|
||||
|
||||
// Forbidden for API compatibility with std::unique_ptr.
|
||||
explicit scoped_ptr(int disallow_construction_from_null);
|
||||
};
|
||||
|
||||
template <class T, class D>
|
||||
class scoped_ptr<T[], D> {
|
||||
DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
|
||||
|
||||
public:
|
||||
// The element and deleter types.
|
||||
using element_type = T;
|
||||
using deleter_type = D;
|
||||
|
||||
// Constructor. Defaults to initializing with nullptr.
|
||||
scoped_ptr() : impl_(nullptr) {}
|
||||
|
||||
// Constructor. Stores the given array. Note that the argument's type
|
||||
// must exactly match T*. In particular:
|
||||
// - it cannot be a pointer to a type derived from T, because it is
|
||||
// inherently unsafe in the general case to access an array through a
|
||||
// pointer whose dynamic type does not match its static type (eg., if
|
||||
// T and the derived types had different sizes access would be
|
||||
// incorrectly calculated). Deletion is also always undefined
|
||||
// (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 const_cast<const T*>().
|
||||
explicit scoped_ptr(element_type* array) : impl_(array) {}
|
||||
|
||||
// Constructor. Allows construction from a nullptr.
|
||||
scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
|
||||
|
||||
// Constructor. Allows construction from a scoped_ptr rvalue.
|
||||
scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
|
||||
|
||||
// operator=. Allows assignment from a scoped_ptr rvalue.
|
||||
scoped_ptr& operator=(scoped_ptr&& rhs) {
|
||||
impl_.TakeState(&rhs.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// operator=. Allows assignment from a nullptr. Deletes the currently owned
|
||||
// array, if any.
|
||||
scoped_ptr& operator=(std::nullptr_t) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Reset. Deletes the currently owned array, if any.
|
||||
// Then takes ownership of a new object, if given.
|
||||
void reset(element_type* array = nullptr) { impl_.reset(array); }
|
||||
|
||||
// Accessors to get the owned array.
|
||||
element_type& operator[](size_t i) const {
|
||||
assert(impl_.get() != nullptr);
|
||||
return impl_.get()[i];
|
||||
}
|
||||
element_type* get() const { return impl_.get(); }
|
||||
|
||||
// Access to the deleter.
|
||||
deleter_type& get_deleter() { return impl_.get_deleter(); }
|
||||
const deleter_type& get_deleter() const { return impl_.get_deleter(); }
|
||||
|
||||
// Allow scoped_ptr<element_type> to be used in boolean expressions, but not
|
||||
// implicitly convertible to a real bool (which is dangerous).
|
||||
private:
|
||||
typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
|
||||
scoped_ptr::*Testable;
|
||||
|
||||
public:
|
||||
operator Testable() const {
|
||||
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
|
||||
}
|
||||
|
||||
// Swap two scoped pointers.
|
||||
void swap(scoped_ptr& p2) {
|
||||
impl_.swap(p2.impl_);
|
||||
}
|
||||
|
||||
// Release a pointer.
|
||||
// The return value is the current pointer held by this object. If this object
|
||||
// holds a nullptr, the return value is nullptr. After this operation, this
|
||||
// object will hold a nullptr, and will not own the object any more.
|
||||
element_type* release() WARN_UNUSED_RESULT {
|
||||
return impl_.release();
|
||||
}
|
||||
|
||||
private:
|
||||
// Force element_type to be a complete type.
|
||||
enum { type_must_be_complete = sizeof(element_type) };
|
||||
|
||||
// Actually hold the data.
|
||||
base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
|
||||
|
||||
// Disable initialization from any type other than element_type*, by
|
||||
// providing a constructor that matches such an initialization, but is
|
||||
// private and has no definition. This is disabled because it is not safe to
|
||||
// call delete[] on an array whose static type does not match its dynamic
|
||||
// type.
|
||||
template <typename U> explicit scoped_ptr(U* array);
|
||||
explicit scoped_ptr(int disallow_construction_from_null);
|
||||
|
||||
// Disable reset() from any type other than element_type*, for the same
|
||||
// reasons as the constructor above.
|
||||
template <typename U> void reset(U* array);
|
||||
void reset(int disallow_reset_from_null);
|
||||
};
|
||||
|
||||
// Free functions
|
||||
template <class T, class D>
|
||||
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==(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!=(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>
|
||||
// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
|
||||
// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
|
||||
template <typename T>
|
||||
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_
|
||||
@@ -1,34 +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.
|
||||
|
||||
#include "base/memory/singleton.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance) {
|
||||
// Handle the race. Another thread beat us and either:
|
||||
// - Has the object in BeingCreated state
|
||||
// - Already has the object created...
|
||||
// We know value != NULL. It could be kBeingCreatedMarker, or a valid ptr.
|
||||
// Unless your constructor can be very time consuming, it is very unlikely
|
||||
// to hit this race. When it does, we just spin and yield the thread until
|
||||
// the object has been created.
|
||||
subtle::AtomicWord value;
|
||||
while (true) {
|
||||
// The load has acquire memory ordering as the thread which reads the
|
||||
// instance pointer must acquire visibility over the associated data.
|
||||
// The pairing Release_Store operation is in Singleton::get().
|
||||
value = subtle::Acquire_Load(instance);
|
||||
if (value != kBeingCreatedMarker)
|
||||
break;
|
||||
PlatformThread::YieldCurrentThread();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
@@ -1,284 +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.
|
||||
|
||||
// PLEASE READ: Do you really need a singleton?
|
||||
//
|
||||
// Singletons make it hard to determine the lifetime of an object, which can
|
||||
// lead to buggy code and spurious crashes.
|
||||
//
|
||||
// Instead of adding another singleton into the mix, try to identify either:
|
||||
// a) An existing singleton that can manage your object's lifetime
|
||||
// b) Locations where you can deterministically create the object and pass
|
||||
// into other objects
|
||||
//
|
||||
// If you absolutely need a singleton, please keep them as trivial as possible
|
||||
// and ideally a leaf dependency. Singletons get problematic when they attempt
|
||||
// to do too much in their destructor or have circular dependencies.
|
||||
|
||||
#ifndef BASE_MEMORY_SINGLETON_H_
|
||||
#define BASE_MEMORY_SINGLETON_H_
|
||||
|
||||
#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/threading/thread_restrictions.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
// Our AtomicWord doubles as a spinlock, where a value of
|
||||
// kBeingCreatedMarker means the spinlock is being held for creation.
|
||||
static const subtle::AtomicWord kBeingCreatedMarker = 1;
|
||||
|
||||
// We pull out some of the functionality into a non-templated function, so that
|
||||
// we can implement the more complicated pieces out of line in the .cc file.
|
||||
BASE_EXPORT subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance);
|
||||
|
||||
class DeleteTraceLogForTesting;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
|
||||
// Default traits for Singleton<Type>. Calls operator new and operator delete on
|
||||
// the object. Registers automatic deletion at process exit.
|
||||
// Overload if you need arguments or another memory allocation function.
|
||||
template<typename Type>
|
||||
struct DefaultSingletonTraits {
|
||||
// Allocates the object.
|
||||
static Type* New() {
|
||||
// The parenthesis is very important here; it forces POD type
|
||||
// initialization.
|
||||
return new Type();
|
||||
}
|
||||
|
||||
// Destroys the object.
|
||||
static void Delete(Type* x) {
|
||||
delete x;
|
||||
}
|
||||
|
||||
// Set to true to automatically register deletion of the object on process
|
||||
// exit. See below for the required call that makes this happen.
|
||||
static const bool kRegisterAtExit = true;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Set to false to disallow access on a non-joinable thread. This is
|
||||
// different from kRegisterAtExit because StaticMemorySingletonTraits allows
|
||||
// access on non-joinable threads, and gracefully handles this.
|
||||
static const bool kAllowedToAccessOnNonjoinableThread = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// Alternate traits for use with the Singleton<Type>. Identical to
|
||||
// DefaultSingletonTraits except that the Singleton will not be cleaned up
|
||||
// at exit.
|
||||
template<typename Type>
|
||||
struct LeakySingletonTraits : public DefaultSingletonTraits<Type> {
|
||||
static const bool kRegisterAtExit = false;
|
||||
#ifndef NDEBUG
|
||||
static const bool kAllowedToAccessOnNonjoinableThread = true;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// Alternate traits for use with the Singleton<Type>. Allocates memory
|
||||
// for the singleton instance from a static buffer. The singleton will
|
||||
// be cleaned up at exit, but can't be revived after destruction unless
|
||||
// the Resurrect() method is called.
|
||||
//
|
||||
// This is useful for a certain category of things, notably logging and
|
||||
// tracing, where the singleton instance is of a type carefully constructed to
|
||||
// be safe to access post-destruction.
|
||||
// In logging and tracing you'll typically get stray calls at odd times, like
|
||||
// during static destruction, thread teardown and the like, and there's a
|
||||
// termination race on the heap-based singleton - e.g. if one thread calls
|
||||
// get(), but then another thread initiates AtExit processing, the first thread
|
||||
// may call into an object residing in unallocated memory. If the instance is
|
||||
// allocated from the data segment, then this is survivable.
|
||||
//
|
||||
// The destructor is to deallocate system resources, in this case to unregister
|
||||
// a callback the system will invoke when logging levels change. Note that
|
||||
// this is also used in e.g. Chrome Frame, where you have to allow for the
|
||||
// possibility of loading briefly into someone else's process space, and
|
||||
// so leaking is not an option, as that would sabotage the state of your host
|
||||
// process once you've unloaded.
|
||||
template <typename Type>
|
||||
struct StaticMemorySingletonTraits {
|
||||
// WARNING: User has to deal with get() in the singleton class
|
||||
// this is traits for returning NULL.
|
||||
static Type* New() {
|
||||
// Only constructs once and returns pointer; otherwise returns NULL.
|
||||
if (subtle::NoBarrier_AtomicExchange(&dead_, 1))
|
||||
return NULL;
|
||||
|
||||
return new(buffer_.void_data()) Type();
|
||||
}
|
||||
|
||||
static void Delete(Type* p) {
|
||||
if (p != NULL)
|
||||
p->Type::~Type();
|
||||
}
|
||||
|
||||
static const bool kRegisterAtExit = true;
|
||||
static const bool kAllowedToAccessOnNonjoinableThread = true;
|
||||
|
||||
// Exposed for unittesting.
|
||||
static void Resurrect() { subtle::NoBarrier_Store(&dead_, 0); }
|
||||
|
||||
private:
|
||||
static AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
|
||||
// Signal the object was already deleted, so it is not revived.
|
||||
static subtle::Atomic32 dead_;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
AlignedMemory<sizeof(Type), ALIGNOF(Type)>
|
||||
StaticMemorySingletonTraits<Type>::buffer_;
|
||||
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
|
||||
// normal process exit). The Trait::Delete function will not be called on
|
||||
// abnormal process exit.
|
||||
//
|
||||
// DifferentiatingType is used as a key to differentiate two different
|
||||
// singletons having the same memory allocation functions but serving a
|
||||
// different purpose. This is mainly used for Locks serving different purposes.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// In your header:
|
||||
// template <typename T> struct DefaultSingletonTraits;
|
||||
// class FooClass {
|
||||
// public:
|
||||
// static FooClass* GetInstance(); <-- See comment below on this.
|
||||
// void Bar() { ... }
|
||||
// private:
|
||||
// FooClass() { ... }
|
||||
// friend struct DefaultSingletonTraits<FooClass>;
|
||||
//
|
||||
// DISALLOW_COPY_AND_ASSIGN(FooClass);
|
||||
// };
|
||||
//
|
||||
// In your source file:
|
||||
// #include "base/memory/singleton.h"
|
||||
// FooClass* FooClass::GetInstance() {
|
||||
// return Singleton<FooClass>::get();
|
||||
// }
|
||||
//
|
||||
// And to call methods on FooClass:
|
||||
// FooClass::GetInstance()->Bar();
|
||||
//
|
||||
// NOTE: The method accessing Singleton<T>::get() has to be named as GetInstance
|
||||
// and it is important that FooClass::GetInstance() is not inlined in the
|
||||
// header. This makes sure that when source files from multiple targets include
|
||||
// this header they don't end up with different copies of the inlined code
|
||||
// creating multiple copies of the singleton.
|
||||
//
|
||||
// Singleton<> has no non-static members and doesn't need to actually be
|
||||
// instantiated.
|
||||
//
|
||||
// This class is itself thread-safe. The underlying Type must of course be
|
||||
// thread-safe if you want to use it concurrently. Two parameters may be tuned
|
||||
// depending on the user's requirements.
|
||||
//
|
||||
// Glossary:
|
||||
// RAE = kRegisterAtExit
|
||||
//
|
||||
// On every platform, if Traits::RAE is true, the singleton will be destroyed at
|
||||
// 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.
|
||||
//
|
||||
// If Traits::RAE is false, the singleton will not be freed at process exit,
|
||||
// thus the singleton will be leaked if it is ever accessed. Traits::RAE
|
||||
// shouldn't be false unless absolutely necessary. Remember that the heap where
|
||||
// the object is allocated may be destroyed by the CRT anyway.
|
||||
//
|
||||
// Caveats:
|
||||
// (a) Every call to get(), operator->() and operator*() incurs some overhead
|
||||
// (16ns on my P4/2.8GHz) to check whether the object has already been
|
||||
// initialized. You may wish to cache the result of get(); it will not
|
||||
// change.
|
||||
//
|
||||
// (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>
|
||||
class Singleton {
|
||||
private:
|
||||
// Classes using the Singleton<T> pattern should declare a GetInstance()
|
||||
// method and call Singleton::get() from within that.
|
||||
friend Type* Type::GetInstance();
|
||||
|
||||
// Allow TraceLog tests to test tracing after OnExit.
|
||||
friend class internal::DeleteTraceLogForTesting;
|
||||
|
||||
// This class is safe to be constructed and copy-constructed since it has no
|
||||
// member.
|
||||
|
||||
// Return a pointer to the one true instance of the class.
|
||||
static Type* get() {
|
||||
#ifndef NDEBUG
|
||||
// Avoid making TLS lookup on release builds.
|
||||
if (!Traits::kAllowedToAccessOnNonjoinableThread)
|
||||
ThreadRestrictions::AssertSingletonAllowed();
|
||||
#endif
|
||||
|
||||
// The load has acquire memory ordering as the thread which reads the
|
||||
// instance_ pointer must acquire visibility over the singleton data.
|
||||
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 (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();
|
||||
|
||||
// Releases the visibility over instance_ to the readers.
|
||||
subtle::Release_Store(&instance_,
|
||||
reinterpret_cast<subtle::AtomicWord>(newval));
|
||||
|
||||
if (newval != NULL && Traits::kRegisterAtExit)
|
||||
AtExitManager::RegisterCallback(OnExit, NULL);
|
||||
|
||||
return newval;
|
||||
}
|
||||
|
||||
// We hit a race. Wait for the other thread to complete it.
|
||||
value = internal::WaitForInstance(&instance_);
|
||||
|
||||
return reinterpret_cast<Type*>(value);
|
||||
}
|
||||
|
||||
// Adapter function for use with AtExit(). This should be called single
|
||||
// threaded, so don't use atomic operations.
|
||||
// Calling OnExit while singleton is in use by other threads is a mistake.
|
||||
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*>(subtle::NoBarrier_Load(&instance_)));
|
||||
instance_ = 0;
|
||||
}
|
||||
static subtle::AtomicWord instance_;
|
||||
};
|
||||
|
||||
template <typename Type, typename Traits, typename DifferentiatingType>
|
||||
subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::instance_ = 0;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_SINGLETON_H_
|
||||
@@ -1,345 +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.
|
||||
|
||||
// Weak pointers are pointers to an object that do not affect its lifetime,
|
||||
// and which may be invalidated (i.e. reset to NULL) by the object, or its
|
||||
// owner, at any time, most commonly when the object is about to be deleted.
|
||||
|
||||
// Weak pointers are useful when an object needs to be accessed safely by one
|
||||
// or more objects other than its owner, and those callers can cope with the
|
||||
// object vanishing and e.g. tasks posted to it being silently dropped.
|
||||
// Reference-counting such an object would complicate the ownership graph and
|
||||
// make it harder to reason about the object's lifetime.
|
||||
|
||||
// EXAMPLE:
|
||||
//
|
||||
// class Controller {
|
||||
// public:
|
||||
// Controller() : weak_factory_(this) {}
|
||||
// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
|
||||
// void WorkComplete(const Result& result) { ... }
|
||||
// private:
|
||||
// // Member variables should appear before the WeakPtrFactory, to ensure
|
||||
// // that any WeakPtrs to Controller are invalidated before its members
|
||||
// // variable's destructors are executed, rendering them invalid.
|
||||
// WeakPtrFactory<Controller> weak_factory_;
|
||||
// };
|
||||
//
|
||||
// class Worker {
|
||||
// public:
|
||||
// static void StartNew(const WeakPtr<Controller>& controller) {
|
||||
// Worker* worker = new Worker(controller);
|
||||
// // Kick off asynchronous processing...
|
||||
// }
|
||||
// private:
|
||||
// Worker(const WeakPtr<Controller>& controller)
|
||||
// : controller_(controller) {}
|
||||
// void DidCompleteAsynchronousProcessing(const Result& result) {
|
||||
// if (controller_)
|
||||
// controller_->WorkComplete(result);
|
||||
// }
|
||||
// WeakPtr<Controller> controller_;
|
||||
// };
|
||||
//
|
||||
// With this implementation a caller may use SpawnWorker() to dispatch multiple
|
||||
// Workers and subsequently delete the Controller, without waiting for all
|
||||
// Workers to have completed.
|
||||
|
||||
// ------------------------- IMPORTANT: Thread-safety -------------------------
|
||||
|
||||
// Weak pointers may be passed safely between threads, but must always be
|
||||
// dereferenced and invalidated on the same SequencedTaskRunner otherwise
|
||||
// checking the pointer would be racey.
|
||||
//
|
||||
// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory
|
||||
// is dereferenced, the factory and its WeakPtrs become bound to the calling
|
||||
// thread or current SequencedWorkerPool token, and cannot be dereferenced or
|
||||
// invalidated on any other task runner. Bound WeakPtrs can still be handed
|
||||
// off to other task runners, e.g. to use to post tasks back to object on the
|
||||
// bound sequence.
|
||||
//
|
||||
// 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/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"
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename T> class SupportsWeakPtr;
|
||||
template <typename T> class WeakPtr;
|
||||
|
||||
namespace internal {
|
||||
// These classes are part of the WeakPtr implementation.
|
||||
// DO NOT USE THESE CLASSES DIRECTLY YOURSELF.
|
||||
|
||||
class BASE_EXPORT WeakReference {
|
||||
public:
|
||||
// Although Flag is bound to a specific SequencedTaskRunner, it may be
|
||||
// deleted from another via base::WeakPtr::~WeakPtr().
|
||||
class BASE_EXPORT Flag : public RefCountedThreadSafe<Flag> {
|
||||
public:
|
||||
Flag();
|
||||
|
||||
void Invalidate();
|
||||
bool IsValid() const;
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<Flag>;
|
||||
|
||||
~Flag();
|
||||
|
||||
SequenceChecker sequence_checker_;
|
||||
bool is_valid_;
|
||||
};
|
||||
|
||||
WeakReference();
|
||||
explicit WeakReference(const Flag* flag);
|
||||
~WeakReference();
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
private:
|
||||
scoped_refptr<const Flag> flag_;
|
||||
};
|
||||
|
||||
class BASE_EXPORT WeakReferenceOwner {
|
||||
public:
|
||||
WeakReferenceOwner();
|
||||
~WeakReferenceOwner();
|
||||
|
||||
WeakReference GetRef() const;
|
||||
|
||||
bool HasRefs() const {
|
||||
return flag_.get() && !flag_->HasOneRef();
|
||||
}
|
||||
|
||||
void Invalidate();
|
||||
|
||||
private:
|
||||
mutable scoped_refptr<WeakReference::Flag> flag_;
|
||||
};
|
||||
|
||||
// This class simplifies the implementation of WeakPtr's type conversion
|
||||
// constructor by avoiding the need for a public accessor for ref_. A
|
||||
// WeakPtr<T> cannot access the private members of WeakPtr<U>, so this
|
||||
// base class gives us a way to access ref_ in a protected fashion.
|
||||
class BASE_EXPORT WeakPtrBase {
|
||||
public:
|
||||
WeakPtrBase();
|
||||
~WeakPtrBase();
|
||||
|
||||
protected:
|
||||
explicit WeakPtrBase(const WeakReference& ref);
|
||||
|
||||
WeakReference ref_;
|
||||
};
|
||||
|
||||
// This class provides a common implementation of common functions that would
|
||||
// otherwise get instantiated separately for each distinct instantiation of
|
||||
// SupportsWeakPtr<>.
|
||||
class SupportsWeakPtrBase {
|
||||
public:
|
||||
// A safe static downcast of a WeakPtr<Base> to WeakPtr<Derived>. This
|
||||
// conversion will only compile if there is exists a Base which inherits
|
||||
// from SupportsWeakPtr<Base>. See base::AsWeakPtr() below for a helper
|
||||
// function that makes calling this easier.
|
||||
template<typename Derived>
|
||||
static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
|
||||
typedef
|
||||
is_convertible<Derived, internal::SupportsWeakPtrBase&> convertible;
|
||||
static_assert(convertible::value,
|
||||
"AsWeakPtr argument must inherit from SupportsWeakPtr");
|
||||
return AsWeakPtrImpl<Derived>(t, *t);
|
||||
}
|
||||
|
||||
private:
|
||||
// This template function uses type inference to find a Base of Derived
|
||||
// which is an instance of SupportsWeakPtr<Base>. We can then safely
|
||||
// static_cast the Base* to a Derived*.
|
||||
template <typename Derived, typename Base>
|
||||
static WeakPtr<Derived> AsWeakPtrImpl(
|
||||
Derived* t, const SupportsWeakPtr<Base>&) {
|
||||
WeakPtr<Base> ptr = t->Base::AsWeakPtr();
|
||||
return WeakPtr<Derived>(ptr.ref_, static_cast<Derived*>(ptr.ptr_));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T> class WeakPtrFactory;
|
||||
|
||||
// The WeakPtr class holds a weak reference to |T*|.
|
||||
//
|
||||
// This class is designed to be used like a normal pointer. You should always
|
||||
// null-test an object of this class before using it or invoking a method that
|
||||
// may result in the underlying object being destroyed.
|
||||
//
|
||||
// EXAMPLE:
|
||||
//
|
||||
// class Foo { ... };
|
||||
// WeakPtr<Foo> foo;
|
||||
// if (foo)
|
||||
// foo->method();
|
||||
//
|
||||
template <typename T>
|
||||
class WeakPtr : public internal::WeakPtrBase {
|
||||
public:
|
||||
WeakPtr() : ptr_(NULL) {
|
||||
}
|
||||
|
||||
// Allow conversion from U to T provided U "is a" T. Note that this
|
||||
// is separate from the (implicit) copy constructor.
|
||||
template <typename U>
|
||||
WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) {
|
||||
}
|
||||
|
||||
T* get() const { return ref_.is_valid() ? ptr_ : NULL; }
|
||||
|
||||
T& operator*() const {
|
||||
DCHECK(get() != NULL);
|
||||
return *get();
|
||||
}
|
||||
T* operator->() const {
|
||||
DCHECK(get() != NULL);
|
||||
return get();
|
||||
}
|
||||
|
||||
// Allow WeakPtr<element_type> 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 "weak_ptr1 == weak_ptr2"
|
||||
// will compile but do the wrong thing (i.e., convert to Testable
|
||||
// and then do the comparison).
|
||||
private:
|
||||
typedef T* WeakPtr::*Testable;
|
||||
|
||||
public:
|
||||
operator Testable() const { return get() ? &WeakPtr::ptr_ : NULL; }
|
||||
|
||||
void reset() {
|
||||
ref_ = internal::WeakReference();
|
||||
ptr_ = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
// Explicitly declare comparison operators as required by the bool
|
||||
// trick, but keep them private.
|
||||
template <class U> bool operator==(WeakPtr<U> const&) const;
|
||||
template <class U> bool operator!=(WeakPtr<U> const&) const;
|
||||
|
||||
friend class internal::SupportsWeakPtrBase;
|
||||
template <typename U> friend class WeakPtr;
|
||||
friend class SupportsWeakPtr<T>;
|
||||
friend class WeakPtrFactory<T>;
|
||||
|
||||
WeakPtr(const internal::WeakReference& ref, T* ptr)
|
||||
: WeakPtrBase(ref),
|
||||
ptr_(ptr) {
|
||||
}
|
||||
|
||||
// This pointer is only valid when ref_.is_valid() is true. Otherwise, its
|
||||
// value is undefined (as opposed to NULL).
|
||||
T* ptr_;
|
||||
};
|
||||
|
||||
// A class may be composed of a WeakPtrFactory and thereby
|
||||
// control how it exposes weak pointers to itself. This is helpful if you only
|
||||
// need weak pointers within the implementation of a class. This class is also
|
||||
// useful when working with primitive types. For example, you could have a
|
||||
// WeakPtrFactory<bool> that is used to pass around a weak reference to a bool.
|
||||
template <class T>
|
||||
class WeakPtrFactory {
|
||||
public:
|
||||
explicit WeakPtrFactory(T* ptr) : ptr_(ptr) {
|
||||
}
|
||||
|
||||
~WeakPtrFactory() {
|
||||
ptr_ = NULL;
|
||||
}
|
||||
|
||||
WeakPtr<T> GetWeakPtr() {
|
||||
DCHECK(ptr_);
|
||||
return WeakPtr<T>(weak_reference_owner_.GetRef(), ptr_);
|
||||
}
|
||||
|
||||
// Call this method to invalidate all existing weak pointers.
|
||||
void InvalidateWeakPtrs() {
|
||||
DCHECK(ptr_);
|
||||
weak_reference_owner_.Invalidate();
|
||||
}
|
||||
|
||||
// Call this method to determine if any weak pointers exist.
|
||||
bool HasWeakPtrs() const {
|
||||
DCHECK(ptr_);
|
||||
return weak_reference_owner_.HasRefs();
|
||||
}
|
||||
|
||||
private:
|
||||
internal::WeakReferenceOwner weak_reference_owner_;
|
||||
T* ptr_;
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(WeakPtrFactory);
|
||||
};
|
||||
|
||||
// A class may extend from SupportsWeakPtr to let others take weak pointers to
|
||||
// it. This avoids the class itself implementing boilerplate to dispense weak
|
||||
// pointers. However, since SupportsWeakPtr's destructor won't invalidate
|
||||
// weak pointers to the class until after the derived class' members have been
|
||||
// destroyed, its use can lead to subtle use-after-destroy issues.
|
||||
template <class T>
|
||||
class SupportsWeakPtr : public internal::SupportsWeakPtrBase {
|
||||
public:
|
||||
SupportsWeakPtr() {}
|
||||
|
||||
WeakPtr<T> AsWeakPtr() {
|
||||
return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T*>(this));
|
||||
}
|
||||
|
||||
protected:
|
||||
~SupportsWeakPtr() {}
|
||||
|
||||
private:
|
||||
internal::WeakReferenceOwner weak_reference_owner_;
|
||||
DISALLOW_COPY_AND_ASSIGN(SupportsWeakPtr);
|
||||
};
|
||||
|
||||
// Helper function that uses type deduction to safely return a WeakPtr<Derived>
|
||||
// when Derived doesn't directly extend SupportsWeakPtr<Derived>, instead it
|
||||
// extends a Base that extends SupportsWeakPtr<Base>.
|
||||
//
|
||||
// EXAMPLE:
|
||||
// class Base : public base::SupportsWeakPtr<Producer> {};
|
||||
// class Derived : public Base {};
|
||||
//
|
||||
// Derived derived;
|
||||
// base::WeakPtr<Derived> ptr = base::AsWeakPtr(&derived);
|
||||
//
|
||||
// Note that the following doesn't work (invalid type conversion) since
|
||||
// Derived::AsWeakPtr() is WeakPtr<Base> SupportsWeakPtr<Base>::AsWeakPtr(),
|
||||
// and there's no way to safely cast WeakPtr<Base> to WeakPtr<Derived> at
|
||||
// the caller.
|
||||
//
|
||||
// base::WeakPtr<Derived> ptr = derived.AsWeakPtr(); // Fails.
|
||||
|
||||
template <typename Derived>
|
||||
WeakPtr<Derived> AsWeakPtr(Derived* t) {
|
||||
return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_WEAK_PTR_H_
|
||||
@@ -1,57 +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_MOVE_H_
|
||||
#define BASE_MOVE_H_
|
||||
|
||||
#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.
|
||||
//
|
||||
// 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 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.
|
||||
// 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: \
|
||||
type(const type&) = delete; \
|
||||
void operator=(const type&) = delete; \
|
||||
\
|
||||
public: \
|
||||
typedef void MoveOnlyTypeForCPP03; \
|
||||
\
|
||||
private:
|
||||
#else
|
||||
#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
|
||||
private: \
|
||||
type(const type&) = delete; \
|
||||
void operator=(const type&) = delete; \
|
||||
\
|
||||
public: \
|
||||
type&& Pass() WARN_UNUSED_RESULT { return std::move(*this); } \
|
||||
typedef void MoveOnlyTypeForCPP03; \
|
||||
\
|
||||
private:
|
||||
#endif
|
||||
|
||||
#endif // BASE_MOVE_H_
|
||||
@@ -1,165 +0,0 @@
|
||||
// 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_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"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Convenience function that returns true if the supplied value is in range
|
||||
// for the destination type.
|
||||
template <typename Dst, typename Src>
|
||||
inline bool IsValueInRangeForNumericType(Src value) {
|
||||
return internal::DstRangeRelationToSrcRange<Dst>(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.
|
||||
template <typename Dst, typename Src>
|
||||
inline Dst checked_cast(Src value) {
|
||||
CHECK(IsValueInRangeForNumericType<Dst>(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 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)
|
||||
return static_cast<Dst>(value);
|
||||
|
||||
switch (internal::DstRangeRelationToSrcRange<Dst>(value)) {
|
||||
case internal::RANGE_VALID:
|
||||
return static_cast<Dst>(value);
|
||||
|
||||
case internal::RANGE_UNDERFLOW:
|
||||
return std::numeric_limits<Dst>::min();
|
||||
|
||||
case internal::RANGE_OVERFLOW:
|
||||
return std::numeric_limits<Dst>::max();
|
||||
|
||||
// Should fail only on attempting to assign NaN to a saturated integer.
|
||||
case internal::RANGE_INVALID:
|
||||
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_NUMERICS_SAFE_CONVERSIONS_H_
|
||||
@@ -1,264 +0,0 @@
|
||||
// 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_CONVERSIONS_IMPL_H_
|
||||
#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base/template_util.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
// The std library doesn't provide a binary max_exponent for integers, however
|
||||
// we can compute one by adding one to the number of non-sign bits. This allows
|
||||
// for accurate range comparisons between floating point and integer types.
|
||||
template <typename NumericType>
|
||||
struct MaxExponent {
|
||||
static const int value = std::numeric_limits<NumericType>::is_iec559
|
||||
? std::numeric_limits<NumericType>::max_exponent
|
||||
: (sizeof(NumericType) * 8 + 1 -
|
||||
std::numeric_limits<NumericType>::is_signed);
|
||||
};
|
||||
|
||||
enum IntegerRepresentation {
|
||||
INTEGER_REPRESENTATION_UNSIGNED,
|
||||
INTEGER_REPRESENTATION_SIGNED
|
||||
};
|
||||
|
||||
// A range for a given nunmeric Src type is contained for a given numeric Dst
|
||||
// type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
|
||||
// numeric_limits<Src>::min() >= numeric_limits<Dst>::min() are true.
|
||||
// We implement this as template specializations rather than simple static
|
||||
// comparisons to ensure type correctness in our comparisons.
|
||||
enum NumericRangeRepresentation {
|
||||
NUMERIC_RANGE_NOT_CONTAINED,
|
||||
NUMERIC_RANGE_CONTAINED
|
||||
};
|
||||
|
||||
// Helper templates to statically determine if our destination type can contain
|
||||
// maximum and minimum values represented by the source type.
|
||||
|
||||
template <
|
||||
typename Dst,
|
||||
typename Src,
|
||||
IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed
|
||||
? INTEGER_REPRESENTATION_SIGNED
|
||||
: INTEGER_REPRESENTATION_UNSIGNED,
|
||||
IntegerRepresentation SrcSign =
|
||||
std::numeric_limits<Src>::is_signed
|
||||
? INTEGER_REPRESENTATION_SIGNED
|
||||
: INTEGER_REPRESENTATION_UNSIGNED >
|
||||
struct StaticDstRangeRelationToSrcRange;
|
||||
|
||||
// Same sign: Dst is guaranteed to contain Src only if its range is equal or
|
||||
// larger.
|
||||
template <typename Dst, typename Src, IntegerRepresentation Sign>
|
||||
struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> {
|
||||
static const NumericRangeRepresentation value =
|
||||
MaxExponent<Dst>::value >= MaxExponent<Src>::value
|
||||
? NUMERIC_RANGE_CONTAINED
|
||||
: NUMERIC_RANGE_NOT_CONTAINED;
|
||||
};
|
||||
|
||||
// Unsigned to signed: Dst is guaranteed to contain source only if its range is
|
||||
// larger.
|
||||
template <typename Dst, typename Src>
|
||||
struct StaticDstRangeRelationToSrcRange<Dst,
|
||||
Src,
|
||||
INTEGER_REPRESENTATION_SIGNED,
|
||||
INTEGER_REPRESENTATION_UNSIGNED> {
|
||||
static const NumericRangeRepresentation value =
|
||||
MaxExponent<Dst>::value > MaxExponent<Src>::value
|
||||
? NUMERIC_RANGE_CONTAINED
|
||||
: NUMERIC_RANGE_NOT_CONTAINED;
|
||||
};
|
||||
|
||||
// Signed to unsigned: Dst cannot be statically determined to contain Src.
|
||||
template <typename Dst, typename Src>
|
||||
struct StaticDstRangeRelationToSrcRange<Dst,
|
||||
Src,
|
||||
INTEGER_REPRESENTATION_UNSIGNED,
|
||||
INTEGER_REPRESENTATION_SIGNED> {
|
||||
static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
|
||||
};
|
||||
|
||||
enum RangeConstraint {
|
||||
RANGE_VALID = 0x0, // Value can be represented by the destination type.
|
||||
RANGE_UNDERFLOW = 0x1, // Value would overflow.
|
||||
RANGE_OVERFLOW = 0x2, // Value would underflow.
|
||||
RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN).
|
||||
};
|
||||
|
||||
// Helper function for coercing an int back to a RangeContraint.
|
||||
inline RangeConstraint GetRangeConstraint(int integer_range_constraint) {
|
||||
DCHECK(integer_range_constraint >= RANGE_VALID &&
|
||||
integer_range_constraint <= RANGE_INVALID);
|
||||
return static_cast<RangeConstraint>(integer_range_constraint);
|
||||
}
|
||||
|
||||
// This function creates a RangeConstraint from an upper and lower bound
|
||||
// check by taking advantage of the fact that only NaN can be out of range in
|
||||
// both directions at once.
|
||||
inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound,
|
||||
bool is_in_lower_bound) {
|
||||
return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) |
|
||||
(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,
|
||||
IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed
|
||||
? INTEGER_REPRESENTATION_SIGNED
|
||||
: INTEGER_REPRESENTATION_UNSIGNED,
|
||||
IntegerRepresentation SrcSign = std::numeric_limits<Src>::is_signed
|
||||
? INTEGER_REPRESENTATION_SIGNED
|
||||
: INTEGER_REPRESENTATION_UNSIGNED,
|
||||
NumericRangeRepresentation DstRange =
|
||||
StaticDstRangeRelationToSrcRange<Dst, Src>::value >
|
||||
struct DstRangeRelationToSrcRangeImpl;
|
||||
|
||||
// The following templates are for ranges that must be verified at runtime. We
|
||||
// split it into checks based on signedness to avoid confusing casts and
|
||||
// compiler warnings on signed an unsigned comparisons.
|
||||
|
||||
// Dst range is statically determined to contain Src: Nothing to check.
|
||||
template <typename Dst,
|
||||
typename Src,
|
||||
IntegerRepresentation DstSign,
|
||||
IntegerRepresentation SrcSign>
|
||||
struct DstRangeRelationToSrcRangeImpl<Dst,
|
||||
Src,
|
||||
DstSign,
|
||||
SrcSign,
|
||||
NUMERIC_RANGE_CONTAINED> {
|
||||
static RangeConstraint Check(Src value) { return RANGE_VALID; }
|
||||
};
|
||||
|
||||
// Signed to signed narrowing: Both the upper and lower boundaries may be
|
||||
// exceeded.
|
||||
template <typename Dst, typename Src>
|
||||
struct DstRangeRelationToSrcRangeImpl<Dst,
|
||||
Src,
|
||||
INTEGER_REPRESENTATION_SIGNED,
|
||||
INTEGER_REPRESENTATION_SIGNED,
|
||||
NUMERIC_RANGE_NOT_CONTAINED> {
|
||||
static RangeConstraint Check(Src value) {
|
||||
return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()),
|
||||
(value >= NarrowingRange<Dst, Src>::min()));
|
||||
}
|
||||
};
|
||||
|
||||
// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded.
|
||||
template <typename Dst, typename Src>
|
||||
struct DstRangeRelationToSrcRangeImpl<Dst,
|
||||
Src,
|
||||
INTEGER_REPRESENTATION_UNSIGNED,
|
||||
INTEGER_REPRESENTATION_UNSIGNED,
|
||||
NUMERIC_RANGE_NOT_CONTAINED> {
|
||||
static RangeConstraint Check(Src value) {
|
||||
return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::max(), true);
|
||||
}
|
||||
};
|
||||
|
||||
// Unsigned to signed: The upper boundary may be exceeded.
|
||||
template <typename Dst, typename Src>
|
||||
struct DstRangeRelationToSrcRangeImpl<Dst,
|
||||
Src,
|
||||
INTEGER_REPRESENTATION_SIGNED,
|
||||
INTEGER_REPRESENTATION_UNSIGNED,
|
||||
NUMERIC_RANGE_NOT_CONTAINED> {
|
||||
static RangeConstraint Check(Src value) {
|
||||
return sizeof(Dst) > sizeof(Src)
|
||||
? RANGE_VALID
|
||||
: GetRangeConstraint(
|
||||
value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
|
||||
true);
|
||||
}
|
||||
};
|
||||
|
||||
// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
|
||||
// and any negative value exceeds the lower boundary.
|
||||
template <typename Dst, typename Src>
|
||||
struct DstRangeRelationToSrcRangeImpl<Dst,
|
||||
Src,
|
||||
INTEGER_REPRESENTATION_UNSIGNED,
|
||||
INTEGER_REPRESENTATION_SIGNED,
|
||||
NUMERIC_RANGE_NOT_CONTAINED> {
|
||||
static RangeConstraint Check(Src value) {
|
||||
return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
|
||||
? GetRangeConstraint(true, value >= static_cast<Src>(0))
|
||||
: GetRangeConstraint(
|
||||
value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
|
||||
value >= static_cast<Src>(0));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Dst, typename Src>
|
||||
inline RangeConstraint DstRangeRelationToSrcRange(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.");
|
||||
return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
|
||||
@@ -1,299 +0,0 @@
|
||||
// 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_
|
||||
@@ -1,545 +0,0 @@
|
||||
// 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_
|
||||
@@ -1,28 +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_OS_COMPAT_ANDROID_H_
|
||||
#define BASE_OS_COMPAT_ANDROID_H_
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <utime.h>
|
||||
|
||||
// Not implemented in Bionic.
|
||||
extern "C" int futimes(int fd, const struct timeval tv[2]);
|
||||
|
||||
// Not exposed or implemented in Bionic.
|
||||
extern "C" char* mkdtemp(char* path);
|
||||
|
||||
// Android has no timegm().
|
||||
extern "C" time_t timegm(struct tm* const t);
|
||||
|
||||
// The lockf() function is not available on Android; we translate to flock().
|
||||
#define F_LOCK LOCK_EX
|
||||
#define F_ULOCK LOCK_UN
|
||||
inline int lockf(int fd, int cmd, off_t ignored_len) {
|
||||
return flock(fd, cmd);
|
||||
}
|
||||
|
||||
#endif // BASE_OS_COMPAT_ANDROID_H_
|
||||
@@ -1,97 +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_PATH_SERVICE_H_
|
||||
#define BASE_PATH_SERVICE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/base_paths.h"
|
||||
#include "base/gtest_prod_util.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class FilePath;
|
||||
class ScopedPathOverride;
|
||||
|
||||
// The path service is a global table mapping keys to file system paths. It is
|
||||
// OK to use this service from multiple threads.
|
||||
//
|
||||
class BASE_EXPORT PathService {
|
||||
public:
|
||||
// Retrieves a path to a special directory or file and places it into the
|
||||
// string pointed to by 'path'. If you ask for a directory it is guaranteed
|
||||
// to NOT have a path separator at the end. For example, "c:\windows\temp"
|
||||
// Directories are also guaranteed to exist when this function succeeds.
|
||||
//
|
||||
// Returns true if the directory or file was successfully retrieved. On
|
||||
// failure, 'path' will not be changed.
|
||||
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
|
||||
// path specifies a directory that does not exist, the directory will be
|
||||
// created by this method. This method returns true if successful.
|
||||
//
|
||||
// If the given path is relative, then it will be resolved against
|
||||
// DIR_CURRENT.
|
||||
//
|
||||
// WARNING: Consumers of PathService::Get may expect paths to be constant
|
||||
// over the lifetime of the app, so this method should be used with caution.
|
||||
//
|
||||
// Unit tests generally should use ScopedPathOverride instead. Overrides from
|
||||
// one test should not carry over to another.
|
||||
static bool Override(int key, const FilePath& path);
|
||||
|
||||
// This function does the same as PathService::Override but it takes extra
|
||||
// parameters:
|
||||
// - |is_absolute| indicates that |path| has already been expanded into an
|
||||
// absolute path, otherwise MakeAbsoluteFilePath() will be used. This is
|
||||
// useful to override paths that may not exist yet, since MakeAbsoluteFilePath
|
||||
// fails for those. Note that MakeAbsoluteFilePath also expands symbolic
|
||||
// links, even if path.IsAbsolute() is already true.
|
||||
// - |create| guides whether the directory to be overriden must
|
||||
// be created in case it doesn't exist already.
|
||||
static bool OverrideAndCreateIfNeeded(int key,
|
||||
const FilePath& path,
|
||||
bool is_absolute,
|
||||
bool create);
|
||||
|
||||
// To extend the set of supported keys, you can register a path provider,
|
||||
// which is just a function mirroring PathService::Get. The ProviderFunc
|
||||
// returns false if it cannot provide a non-empty path for the given key.
|
||||
// Otherwise, true is returned.
|
||||
//
|
||||
// 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, FilePath*);
|
||||
|
||||
// Call to register a path provider. You must specify the range "[key_start,
|
||||
// key_end)" of supported path keys.
|
||||
static void RegisterProvider(ProviderFunc provider,
|
||||
int key_start,
|
||||
int key_end);
|
||||
|
||||
// Disable internal cache.
|
||||
static void DisableCache();
|
||||
|
||||
private:
|
||||
friend class ScopedPathOverride;
|
||||
FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride);
|
||||
|
||||
// Removes an override for a special directory or file. Returns true if there
|
||||
// was an override to remove or false if none was present.
|
||||
// NOTE: This function is intended to be used by tests only!
|
||||
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,67 +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.
|
||||
|
||||
// This provides a wrapper around system calls which may be interrupted by a
|
||||
// signal and return EINTR. See man 7 signal.
|
||||
// To prevent long-lasting loops (which would likely be a bug, such as a signal
|
||||
// that should be masked) to go unnoticed, there is a limit after which the
|
||||
// caller will nonetheless see an EINTR in Debug builds.
|
||||
//
|
||||
// On Windows, this wrapper macro does nothing.
|
||||
//
|
||||
// Don't wrap close calls in HANDLE_EINTR. Use IGNORE_EINTR if the return
|
||||
// value of close is significant. See http://crbug.com/269623.
|
||||
|
||||
#ifndef BASE_POSIX_EINTR_WRAPPER_H_
|
||||
#define BASE_POSIX_EINTR_WRAPPER_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(NDEBUG)
|
||||
|
||||
#define HANDLE_EINTR(x) ({ \
|
||||
decltype(x) eintr_wrapper_result; \
|
||||
do { \
|
||||
eintr_wrapper_result = (x); \
|
||||
} while (eintr_wrapper_result == -1 && errno == EINTR); \
|
||||
eintr_wrapper_result; \
|
||||
})
|
||||
|
||||
#else
|
||||
|
||||
#define HANDLE_EINTR(x) ({ \
|
||||
int eintr_wrapper_counter = 0; \
|
||||
decltype(x) eintr_wrapper_result; \
|
||||
do { \
|
||||
eintr_wrapper_result = (x); \
|
||||
} while (eintr_wrapper_result == -1 && errno == EINTR && \
|
||||
eintr_wrapper_counter++ < 100); \
|
||||
eintr_wrapper_result; \
|
||||
})
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
#define IGNORE_EINTR(x) ({ \
|
||||
decltype(x) eintr_wrapper_result; \
|
||||
do { \
|
||||
eintr_wrapper_result = (x); \
|
||||
if (eintr_wrapper_result == -1 && errno == EINTR) { \
|
||||
eintr_wrapper_result = 0; \
|
||||
} \
|
||||
} while (0); \
|
||||
eintr_wrapper_result; \
|
||||
})
|
||||
|
||||
#else
|
||||
|
||||
#define HANDLE_EINTR(x) (x)
|
||||
#define IGNORE_EINTR(x) (x)
|
||||
|
||||
#endif // OS_POSIX
|
||||
|
||||
#endif // BASE_POSIX_EINTR_WRAPPER_H_
|
||||
@@ -1,81 +0,0 @@
|
||||
// Copyright (c) 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.
|
||||
|
||||
#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/files/file_path.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
// ProcessHandle is a platform specific type which represents the underlying OS
|
||||
// handle to a process.
|
||||
// ProcessId is a number which identifies the process in the OS.
|
||||
#if defined(OS_WIN)
|
||||
typedef HANDLE ProcessHandle;
|
||||
typedef DWORD ProcessId;
|
||||
typedef HANDLE UserTokenHandle;
|
||||
const ProcessHandle kNullProcessHandle = NULL;
|
||||
const ProcessId kNullProcessId = 0;
|
||||
#elif defined(OS_POSIX)
|
||||
// On POSIX, our ProcessHandle will just be the PID.
|
||||
typedef pid_t ProcessHandle;
|
||||
typedef pid_t ProcessId;
|
||||
const ProcessHandle kNullProcessHandle = 0;
|
||||
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();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_PROCESS_PROCESS_HANDLE_H_
|
||||
@@ -1,62 +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_RAND_UTIL_H_
|
||||
#define BASE_RAND_UTIL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// 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);
|
||||
|
||||
// Returns a random number in range [0, range). Thread-safe.
|
||||
//
|
||||
// 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_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_t bits);
|
||||
|
||||
// Fills |output_length| bytes of |output| with random data.
|
||||
//
|
||||
// WARNING:
|
||||
// Do not use for security-sensitive purposes.
|
||||
// See crypto/ for cryptographically secure random number generation APIs.
|
||||
BASE_EXPORT void RandBytes(void* output, size_t output_length);
|
||||
|
||||
// Fills a string of length |length| with random data and returns it.
|
||||
// |length| should be nonzero.
|
||||
//
|
||||
// Note that this is a variation of |RandBytes| with a different return type.
|
||||
// The returned string is likely not ASCII/UTF-8. Use with care.
|
||||
//
|
||||
// WARNING:
|
||||
// Do not use for security-sensitive purposes.
|
||||
// See crypto/ for cryptographically secure random number generation APIs.
|
||||
BASE_EXPORT std::string RandBytesAsString(size_t length);
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
BASE_EXPORT int GetUrandomFD();
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_RAND_UTIL_H_
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright (c) 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.
|
||||
|
||||
#ifndef BASE_SCOPED_CLEAR_ERRNO_H_
|
||||
#define BASE_SCOPED_CLEAR_ERRNO_H_
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "base/macros.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Simple scoper that saves the current value of errno, resets it to 0, and on
|
||||
// destruction puts the old value back.
|
||||
class ScopedClearErrno {
|
||||
public:
|
||||
ScopedClearErrno() : old_errno_(errno) {
|
||||
errno = 0;
|
||||
}
|
||||
~ScopedClearErrno() {
|
||||
if (errno == 0)
|
||||
errno = old_errno_;
|
||||
}
|
||||
|
||||
private:
|
||||
const int old_errno_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SCOPED_CLEAR_ERRNO_H_
|
||||
@@ -1,62 +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_SEQUENCE_CHECKER_H_
|
||||
#define BASE_SEQUENCE_CHECKER_H_
|
||||
|
||||
// See comments for the similar block in thread_checker.h.
|
||||
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
|
||||
#define ENABLE_SEQUENCE_CHECKER 1
|
||||
#else
|
||||
#define ENABLE_SEQUENCE_CHECKER 0
|
||||
#endif
|
||||
|
||||
#include "base/sequence_checker_impl.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Do nothing implementation, for use in release mode.
|
||||
//
|
||||
// Note: You should almost always use the SequenceChecker class to get
|
||||
// the right version for your build configuration.
|
||||
class SequenceCheckerDoNothing {
|
||||
public:
|
||||
bool CalledOnValidSequencedThread() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DetachFromSequence() {}
|
||||
};
|
||||
|
||||
// SequenceChecker is a helper class used to help verify that some
|
||||
// methods of a class are called in sequence -- that is, called from
|
||||
// the same SequencedTaskRunner. It is a generalization of
|
||||
// ThreadChecker; see comments in sequence_checker_impl.h for details.
|
||||
//
|
||||
// Example:
|
||||
// class MyClass {
|
||||
// public:
|
||||
// void Foo() {
|
||||
// DCHECK(sequence_checker_.CalledOnValidSequencedThread());
|
||||
// ... (do stuff) ...
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// SequenceChecker sequence_checker_;
|
||||
// }
|
||||
//
|
||||
// In Release mode, CalledOnValidSequencedThread() will always return true.
|
||||
#if ENABLE_SEQUENCE_CHECKER
|
||||
class SequenceChecker : public SequenceCheckerImpl {
|
||||
};
|
||||
#else
|
||||
class SequenceChecker : public SequenceCheckerDoNothing {
|
||||
};
|
||||
#endif // ENABLE_SEQUENCE_CHECKER
|
||||
|
||||
#undef ENABLE_SEQUENCE_CHECKER
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SEQUENCE_CHECKER_H_
|
||||
@@ -1,52 +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_SEQUENCE_CHECKER_IMPL_H_
|
||||
#define BASE_SEQUENCE_CHECKER_IMPL_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "base/threading/thread_checker_impl.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// SequenceCheckerImpl is used to help verify that some methods of a
|
||||
// class are called in sequence -- that is, called from the same
|
||||
// SequencedTaskRunner. It is a generalization of ThreadChecker; in
|
||||
// particular, it behaves exactly like ThreadChecker if constructed
|
||||
// on a thread that is not part of a SequencedWorkerPool.
|
||||
class BASE_EXPORT SequenceCheckerImpl {
|
||||
public:
|
||||
SequenceCheckerImpl();
|
||||
~SequenceCheckerImpl();
|
||||
|
||||
// Returns whether the we are being called on the same sequence token
|
||||
// as previous calls. If there is no associated sequence, then returns
|
||||
// whether we are being called on the underlying ThreadChecker's thread.
|
||||
bool CalledOnValidSequencedThread() const;
|
||||
|
||||
// Unbinds the checker from the currently associated sequence. The
|
||||
// checker will be re-bound on the next call to CalledOnValidSequence().
|
||||
void DetachFromSequence();
|
||||
|
||||
private:
|
||||
void EnsureSequenceTokenAssigned() const;
|
||||
|
||||
// Guards all variables below.
|
||||
mutable Lock lock_;
|
||||
|
||||
// Used if |sequence_token_| is not valid.
|
||||
ThreadCheckerImpl thread_checker_;
|
||||
mutable bool sequence_token_assigned_;
|
||||
|
||||
mutable SequencedWorkerPool::SequenceToken sequence_token_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SequenceCheckerImpl);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SEQUENCE_CHECKER_IMPL_H_
|
||||
@@ -1,159 +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_SEQUENCED_TASK_RUNNER_H_
|
||||
#define BASE_SEQUENCED_TASK_RUNNER_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/sequenced_task_runner_helpers.h"
|
||||
#include "base/task_runner.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// A SequencedTaskRunner is a subclass of TaskRunner that provides
|
||||
// additional guarantees on the order that tasks are started, as well
|
||||
// as guarantees on when tasks are in sequence, i.e. one task finishes
|
||||
// before the other one starts.
|
||||
//
|
||||
// Summary
|
||||
// -------
|
||||
// Non-nested tasks with the same delay will run one by one in FIFO
|
||||
// order.
|
||||
//
|
||||
// Detailed guarantees
|
||||
// -------------------
|
||||
//
|
||||
// SequencedTaskRunner also adds additional methods for posting
|
||||
// non-nestable tasks. In general, an implementation of TaskRunner
|
||||
// may expose task-running methods which are themselves callable from
|
||||
// within tasks. A non-nestable task is one that is guaranteed to not
|
||||
// be run from within an already-running task. Conversely, a nestable
|
||||
// task (the default) is a task that can be run from within an
|
||||
// already-running task.
|
||||
//
|
||||
// The guarantees of SequencedTaskRunner are as follows:
|
||||
//
|
||||
// - Given two tasks T2 and T1, T2 will start after T1 starts if:
|
||||
//
|
||||
// * T2 is posted after T1; and
|
||||
// * T2 has equal or higher delay than T1; and
|
||||
// * T2 is non-nestable or T1 is nestable.
|
||||
//
|
||||
// - If T2 will start after T1 starts by the above guarantee, then
|
||||
// T2 will start after T1 finishes and is destroyed if:
|
||||
//
|
||||
// * T2 is non-nestable, or
|
||||
// * T1 doesn't call any task-running methods.
|
||||
//
|
||||
// - If T2 will start after T1 finishes by the above guarantee, then
|
||||
// all memory changes in T1 and T1's destruction will be visible
|
||||
// to T2.
|
||||
//
|
||||
// - If T2 runs nested within T1 via a call to the task-running
|
||||
// method M, then all memory changes in T1 up to the call to M
|
||||
// will be visible to T2, and all memory changes in T2 will be
|
||||
// visible to T1 from the return from M.
|
||||
//
|
||||
// Note that SequencedTaskRunner does not guarantee that tasks are run
|
||||
// on a single dedicated thread, although the above guarantees provide
|
||||
// most (but not all) of the same guarantees. If you do need to
|
||||
// guarantee that tasks are run on a single dedicated thread, see
|
||||
// SingleThreadTaskRunner (in single_thread_task_runner.h).
|
||||
//
|
||||
// Some corollaries to the above guarantees, assuming the tasks in
|
||||
// question don't call any task-running methods:
|
||||
//
|
||||
// - Tasks posted via PostTask are run in FIFO order.
|
||||
//
|
||||
// - Tasks posted via PostNonNestableTask are run in FIFO order.
|
||||
//
|
||||
// - Tasks posted with the same delay and the same nestable state
|
||||
// are run in FIFO order.
|
||||
//
|
||||
// - A list of tasks with the same nestable state posted in order of
|
||||
// non-decreasing delay is run in FIFO order.
|
||||
//
|
||||
// - A list of tasks posted in order of non-decreasing delay with at
|
||||
// most a single change in nestable state from nestable to
|
||||
// non-nestable is run in FIFO order. (This is equivalent to the
|
||||
// statement of the first guarantee above.)
|
||||
//
|
||||
// Some theoretical implementations of SequencedTaskRunner:
|
||||
//
|
||||
// - A SequencedTaskRunner that wraps a regular TaskRunner but makes
|
||||
// sure that only one task at a time is posted to the TaskRunner,
|
||||
// with appropriate memory barriers in between tasks.
|
||||
//
|
||||
// - A SequencedTaskRunner that, for each task, spawns a joinable
|
||||
// thread to run that task and immediately quit, and then
|
||||
// immediately joins that thread.
|
||||
//
|
||||
// - A SequencedTaskRunner that stores the list of posted tasks and
|
||||
// has a method Run() that runs each runnable task in FIFO order
|
||||
// that can be called from any thread, but only if another
|
||||
// (non-nested) Run() call isn't already happening.
|
||||
class BASE_EXPORT SequencedTaskRunner : public TaskRunner {
|
||||
public:
|
||||
// The two PostNonNestable*Task methods below are like their
|
||||
// nestable equivalents in TaskRunner, but they guarantee that the
|
||||
// posted task will not run nested within an already-running task.
|
||||
//
|
||||
// A simple corollary is that posting a task as non-nestable can
|
||||
// only delay when the task gets run. That is, posting a task as
|
||||
// non-nestable may not affect when the task gets run, or it could
|
||||
// make it run later than it normally would, but it won't make it
|
||||
// run earlier than it normally would.
|
||||
|
||||
// TODO(akalin): Get rid of the boolean return value for the methods
|
||||
// below.
|
||||
|
||||
bool PostNonNestableTask(const tracked_objects::Location& from_here,
|
||||
const Closure& task);
|
||||
|
||||
virtual bool PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const Closure& task,
|
||||
base::TimeDelta delay) = 0;
|
||||
|
||||
// Submits a non-nestable task to delete the given object. Returns
|
||||
// true if the object may be deleted at some point in the future,
|
||||
// and false if the object definitely will not be deleted.
|
||||
template <class T>
|
||||
bool DeleteSoon(const tracked_objects::Location& from_here,
|
||||
const T* object) {
|
||||
return
|
||||
subtle::DeleteHelperInternal<T, bool>::DeleteViaSequencedTaskRunner(
|
||||
this, from_here, object);
|
||||
}
|
||||
|
||||
// Submits a non-nestable task to release the given object. Returns
|
||||
// true if the object may be released at some point in the future,
|
||||
// and false if the object definitely will not be released.
|
||||
template <class T>
|
||||
bool ReleaseSoon(const tracked_objects::Location& from_here,
|
||||
T* object) {
|
||||
return
|
||||
subtle::ReleaseHelperInternal<T, bool>::ReleaseViaSequencedTaskRunner(
|
||||
this, from_here, object);
|
||||
}
|
||||
|
||||
protected:
|
||||
~SequencedTaskRunner() override {}
|
||||
|
||||
private:
|
||||
template <class T, class R> friend class subtle::DeleteHelperInternal;
|
||||
template <class T, class R> friend class subtle::ReleaseHelperInternal;
|
||||
|
||||
bool DeleteSoonInternal(const tracked_objects::Location& from_here,
|
||||
void(*deleter)(const void*),
|
||||
const void* object);
|
||||
|
||||
bool ReleaseSoonInternal(const tracked_objects::Location& from_here,
|
||||
void(*releaser)(const void*),
|
||||
const void* object);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SEQUENCED_TASK_RUNNER_H_
|
||||
@@ -1,113 +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_SEQUENCED_TASK_RUNNER_HELPERS_H_
|
||||
#define BASE_SEQUENCED_TASK_RUNNER_HELPERS_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).
|
||||
// Then we can just move these to sequenced_task_runner.h.
|
||||
|
||||
namespace tracked_objects {
|
||||
class Location;
|
||||
}
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace subtle {
|
||||
template <class T, class R> class DeleteHelperInternal;
|
||||
template <class T, class R> class ReleaseHelperInternal;
|
||||
}
|
||||
|
||||
// Template helpers which use function indirection to erase T from the
|
||||
// function signature while still remembering it so we can call the
|
||||
// correct destructor/release function.
|
||||
//
|
||||
// We use this trick so we don't need to include bind.h in a header
|
||||
// file like sequenced_task_runner.h. We also wrap the helpers in a
|
||||
// templated class to make it easier for users of DeleteSoon to
|
||||
// declare the helper as a friend.
|
||||
template <class T>
|
||||
class DeleteHelper {
|
||||
private:
|
||||
template <class T2, class R> friend class subtle::DeleteHelperInternal;
|
||||
|
||||
static void DoDelete(const void* object) {
|
||||
delete reinterpret_cast<const T*>(object);
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DeleteHelper);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ReleaseHelper {
|
||||
private:
|
||||
template <class T2, class R> friend class subtle::ReleaseHelperInternal;
|
||||
|
||||
static void DoRelease(const void* object) {
|
||||
reinterpret_cast<const T*>(object)->Release();
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ReleaseHelper);
|
||||
};
|
||||
|
||||
namespace subtle {
|
||||
|
||||
// An internal SequencedTaskRunner-like class helper for DeleteHelper
|
||||
// and ReleaseHelper. We don't want to expose the Do*() functions
|
||||
// directly directly since the void* argument makes it possible to
|
||||
// pass/ an object of the wrong type to delete. Instead, we force
|
||||
// callers to go through these internal helpers for type
|
||||
// safety. SequencedTaskRunner-like classes which expose DeleteSoon or
|
||||
// ReleaseSoon methods should friend the appropriate helper and
|
||||
// implement a corresponding *Internal method with the following
|
||||
// signature:
|
||||
//
|
||||
// bool(const tracked_objects::Location&,
|
||||
// void(*function)(const void*),
|
||||
// void* object)
|
||||
//
|
||||
// An implementation of this function should simply create a
|
||||
// base::Closure from (function, object) and return the result of
|
||||
// posting the task.
|
||||
template <class T, class ReturnType>
|
||||
class DeleteHelperInternal {
|
||||
public:
|
||||
template <class SequencedTaskRunnerType>
|
||||
static ReturnType DeleteViaSequencedTaskRunner(
|
||||
SequencedTaskRunnerType* sequenced_task_runner,
|
||||
const tracked_objects::Location& from_here,
|
||||
const T* object) {
|
||||
return sequenced_task_runner->DeleteSoonInternal(
|
||||
from_here, &DeleteHelper<T>::DoDelete, object);
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(DeleteHelperInternal);
|
||||
};
|
||||
|
||||
template <class T, class ReturnType>
|
||||
class ReleaseHelperInternal {
|
||||
public:
|
||||
template <class SequencedTaskRunnerType>
|
||||
static ReturnType ReleaseViaSequencedTaskRunner(
|
||||
SequencedTaskRunnerType* sequenced_task_runner,
|
||||
const tracked_objects::Location& from_here,
|
||||
const T* object) {
|
||||
return sequenced_task_runner->ReleaseSoonInternal(
|
||||
from_here, &ReleaseHelper<T>::DoRelease, object);
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ReleaseHelperInternal);
|
||||
};
|
||||
|
||||
} // namespace subtle
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
|
||||
@@ -1,38 +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_SINGLE_THREAD_TASK_RUNNER_H_
|
||||
#define BASE_SINGLE_THREAD_TASK_RUNNER_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/sequenced_task_runner.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// A SingleThreadTaskRunner is a SequencedTaskRunner with one more
|
||||
// guarantee; namely, that all tasks are run on a single dedicated
|
||||
// thread. Most use cases require only a SequencedTaskRunner, unless
|
||||
// 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
|
||||
// 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
|
||||
// running other kinds of message loop, e.g. Jingle threads.
|
||||
class BASE_EXPORT SingleThreadTaskRunner : public SequencedTaskRunner {
|
||||
public:
|
||||
// A more explicit alias to RunsTasksOnCurrentThread().
|
||||
bool BelongsToCurrentThread() const {
|
||||
return RunsTasksOnCurrentThread();
|
||||
}
|
||||
|
||||
protected:
|
||||
~SingleThreadTaskRunner() override {}
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SINGLE_THREAD_TASK_RUNNER_H_
|
||||
@@ -1,262 +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.
|
||||
|
||||
// Derived from google3/util/gtl/stl_util.h
|
||||
|
||||
#ifndef BASE_STL_UTIL_H_
|
||||
#define BASE_STL_UTIL_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
// Clears internal memory of an STL object.
|
||||
// STL clear()/reserve(0) does not always free internal memory allocated
|
||||
// This function uses swap/destructor to ensure the internal memory is freed.
|
||||
template<class T>
|
||||
void STLClearObject(T* obj) {
|
||||
T tmp;
|
||||
tmp.swap(*obj);
|
||||
// Sometimes "T tmp" allocates objects with memory (arena implementation?).
|
||||
// Hence using additional reserve(0) even if it doesn't always work.
|
||||
obj->reserve(0);
|
||||
}
|
||||
|
||||
// For a range within a container of pointers, calls delete (non-array version)
|
||||
// on these pointers.
|
||||
// NOTE: for these three functions, we could just implement a DeleteObject
|
||||
// functor and then call for_each() on the range and functor, but this
|
||||
// requires us to pull in all of algorithm.h, which seems expensive.
|
||||
// For hash_[multi]set, it is important that this deletes behind the iterator
|
||||
// because the hash_set may call the hash function on the iterator when it is
|
||||
// advanced, which could result in the hash function trying to deference a
|
||||
// stale pointer.
|
||||
template <class ForwardIterator>
|
||||
void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) {
|
||||
while (begin != end) {
|
||||
ForwardIterator temp = begin;
|
||||
++begin;
|
||||
delete *temp;
|
||||
}
|
||||
}
|
||||
|
||||
// For a range within a container of pairs, calls delete (non-array version) on
|
||||
// BOTH items in the pairs.
|
||||
// NOTE: Like STLDeleteContainerPointers, it is important that this deletes
|
||||
// behind the iterator because if both the key and value are deleted, the
|
||||
// container may call the hash function on the iterator when it is advanced,
|
||||
// which could result in the hash function trying to dereference a stale
|
||||
// pointer.
|
||||
template <class ForwardIterator>
|
||||
void STLDeleteContainerPairPointers(ForwardIterator begin,
|
||||
ForwardIterator end) {
|
||||
while (begin != end) {
|
||||
ForwardIterator temp = begin;
|
||||
++begin;
|
||||
delete temp->first;
|
||||
delete temp->second;
|
||||
}
|
||||
}
|
||||
|
||||
// For a range within a container of pairs, calls delete (non-array version) on
|
||||
// the FIRST item in the pairs.
|
||||
// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
|
||||
template <class ForwardIterator>
|
||||
void STLDeleteContainerPairFirstPointers(ForwardIterator begin,
|
||||
ForwardIterator end) {
|
||||
while (begin != end) {
|
||||
ForwardIterator temp = begin;
|
||||
++begin;
|
||||
delete temp->first;
|
||||
}
|
||||
}
|
||||
|
||||
// For a range within a container of pairs, calls delete.
|
||||
// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
|
||||
// Deleting the value does not always invalidate the iterator, but it may
|
||||
// do so if the key is a pointer into the value object.
|
||||
template <class ForwardIterator>
|
||||
void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
|
||||
ForwardIterator end) {
|
||||
while (begin != end) {
|
||||
ForwardIterator temp = begin;
|
||||
++begin;
|
||||
delete temp->second;
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
// which may not be null-terminated. Writing through this pointer will
|
||||
// modify the string.
|
||||
//
|
||||
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
|
||||
// next call to a string method that invalidates iterators.
|
||||
//
|
||||
// As of 2006-04, there is no standard-blessed way of getting a
|
||||
// mutable reference to a string's internal buffer. However, issue 530
|
||||
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
|
||||
// proposes this as the method. According to Matt Austern, this should
|
||||
// already work on all current implementations.
|
||||
inline char* string_as_array(std::string* str) {
|
||||
// DO NOT USE const_cast<char*>(str->data())
|
||||
return str->empty() ? NULL : &*str->begin();
|
||||
}
|
||||
|
||||
// The following functions are useful for cleaning up STL containers whose
|
||||
// elements point to allocated memory.
|
||||
|
||||
// STLDeleteElements() deletes all the elements in an STL container and clears
|
||||
// the container. This function is suitable for use with a vector, set,
|
||||
// hash_set, or any other STL container which defines sensible begin(), end(),
|
||||
// and clear() methods.
|
||||
//
|
||||
// If container is NULL, this function is a no-op.
|
||||
//
|
||||
// As an alternative to calling STLDeleteElements() directly, consider
|
||||
// STLElementDeleter (defined below), which ensures that your container's
|
||||
// elements are deleted when the STLElementDeleter goes out of scope.
|
||||
template <class T>
|
||||
void STLDeleteElements(T* container) {
|
||||
if (!container)
|
||||
return;
|
||||
STLDeleteContainerPointers(container->begin(), container->end());
|
||||
container->clear();
|
||||
}
|
||||
|
||||
// Given an STL container consisting of (key, value) pairs, STLDeleteValues
|
||||
// deletes all the "value" components and clears the container. Does nothing
|
||||
// in the case it's given a NULL pointer.
|
||||
template <class T>
|
||||
void STLDeleteValues(T* container) {
|
||||
if (!container)
|
||||
return;
|
||||
STLDeleteContainerPairSecondPointers(container->begin(), container->end());
|
||||
container->clear();
|
||||
}
|
||||
|
||||
|
||||
// The following classes provide a convenient way to delete all elements or
|
||||
// values from STL containers when they goes out of scope. This greatly
|
||||
// simplifies code that creates temporary objects and has multiple return
|
||||
// statements. Example:
|
||||
//
|
||||
// vector<MyProto *> tmp_proto;
|
||||
// STLElementDeleter<vector<MyProto *> > d(&tmp_proto);
|
||||
// if (...) return false;
|
||||
// ...
|
||||
// return success;
|
||||
|
||||
// Given a pointer to an STL container this class will delete all the element
|
||||
// pointers when it goes out of scope.
|
||||
template<class T>
|
||||
class STLElementDeleter {
|
||||
public:
|
||||
STLElementDeleter<T>(T* container) : container_(container) {}
|
||||
~STLElementDeleter<T>() { STLDeleteElements(container_); }
|
||||
|
||||
private:
|
||||
T* container_;
|
||||
};
|
||||
|
||||
// Given a pointer to an STL container this class will delete all the value
|
||||
// pointers when it goes out of scope.
|
||||
template<class T>
|
||||
class STLValueDeleter {
|
||||
public:
|
||||
STLValueDeleter<T>(T* container) : container_(container) {}
|
||||
~STLValueDeleter<T>() { STLDeleteValues(container_); }
|
||||
|
||||
private:
|
||||
T* container_;
|
||||
};
|
||||
|
||||
// Test to see if a set, map, hash_set or hash_map contains a particular key.
|
||||
// Returns true if the key is in the collection.
|
||||
template <typename Collection, typename Key>
|
||||
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.
|
||||
template <typename Container>
|
||||
bool STLIsSorted(const Container& cont) {
|
||||
// Note: Use reverse iterator on container to ensure we only require
|
||||
// value_type to implement operator<.
|
||||
return std::adjacent_find(cont.rbegin(), cont.rend(),
|
||||
std::less<typename Container::value_type>())
|
||||
== cont.rend();
|
||||
}
|
||||
|
||||
// Returns a new ResultType containing the difference of two sorted containers.
|
||||
template <typename ResultType, typename Arg1, typename Arg2>
|
||||
ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
|
||||
DCHECK(STLIsSorted(a1));
|
||||
DCHECK(STLIsSorted(a2));
|
||||
ResultType difference;
|
||||
std::set_difference(a1.begin(), a1.end(),
|
||||
a2.begin(), a2.end(),
|
||||
std::inserter(difference, difference.end()));
|
||||
return difference;
|
||||
}
|
||||
|
||||
// Returns a new ResultType containing the union of two sorted containers.
|
||||
template <typename ResultType, typename Arg1, typename Arg2>
|
||||
ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
|
||||
DCHECK(STLIsSorted(a1));
|
||||
DCHECK(STLIsSorted(a2));
|
||||
ResultType result;
|
||||
std::set_union(a1.begin(), a1.end(),
|
||||
a2.begin(), a2.end(),
|
||||
std::inserter(result, result.end()));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns a new ResultType containing the intersection of two sorted
|
||||
// containers.
|
||||
template <typename ResultType, typename Arg1, typename Arg2>
|
||||
ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
|
||||
DCHECK(STLIsSorted(a1));
|
||||
DCHECK(STLIsSorted(a2));
|
||||
ResultType result;
|
||||
std::set_intersection(a1.begin(), a1.end(),
|
||||
a2.begin(), a2.end(),
|
||||
std::inserter(result, result.end()));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns true if the sorted container |a1| contains all elements of the sorted
|
||||
// container |a2|.
|
||||
template <typename Arg1, typename Arg2>
|
||||
bool STLIncludes(const Arg1& a1, const Arg2& a2) {
|
||||
DCHECK(STLIsSorted(a1));
|
||||
DCHECK(STLIsSorted(a2));
|
||||
return std::includes(a1.begin(), a1.end(),
|
||||
a2.begin(), a2.end());
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STL_UTIL_H_
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) 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.
|
||||
|
||||
#include "base/strings/nullable_string16.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const NullableString16& value) {
|
||||
return value.is_null() ? out << "(null)" : out << UTF16ToUTF8(value.string());
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright (c) 2010 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_STRINGS_NULLABLE_STRING16_H_
|
||||
#define BASE_STRINGS_NULLABLE_STRING16_H_
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// This class is a simple wrapper for string16 which also contains a null
|
||||
// state. This should be used only where the difference between null and
|
||||
// empty is meaningful.
|
||||
class NullableString16 {
|
||||
public:
|
||||
NullableString16() : is_null_(true) { }
|
||||
NullableString16(const string16& string, bool is_null)
|
||||
: string_(string), is_null_(is_null) {
|
||||
}
|
||||
|
||||
const string16& string() const { return string_; }
|
||||
bool is_null() const { return is_null_; }
|
||||
|
||||
private:
|
||||
string16 string_;
|
||||
bool is_null_;
|
||||
};
|
||||
|
||||
inline bool operator==(const NullableString16& a, const NullableString16& b) {
|
||||
return a.is_null() == b.is_null() && a.string() == b.string();
|
||||
}
|
||||
|
||||
inline bool operator!=(const NullableString16& a, const NullableString16& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
BASE_EXPORT std::ostream& operator<<(std::ostream& out,
|
||||
const NullableString16& value);
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STRINGS_NULLABLE_STRING16_H_
|
||||
@@ -1,686 +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.
|
||||
|
||||
#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.
|
||||
// As our contract promises that SafeSPrintf() can be called from any
|
||||
// restricted run-time context, it is not actually safe to call logging
|
||||
// functions from it; and we only ever do so for debug builds and hope for the
|
||||
// best. We should _never_ call any logging function other than RAW_CHECK(),
|
||||
// and we should _never_ include any logging code that is active in production
|
||||
// builds. Most notably, we should not include these logging functions in
|
||||
// unofficial release builds, even though those builds would otherwise have
|
||||
// DCHECKS() enabled.
|
||||
// In other words; please do not remove the #ifdef around this #include.
|
||||
// Instead, in production builds we opt for returning a degraded result,
|
||||
// whenever an error is encountered.
|
||||
// E.g. The broken function call
|
||||
// SafeSPrintf("errno = %d (%x)", errno, strerror(errno))
|
||||
// will print something like
|
||||
// errno = 13, (%x)
|
||||
// instead of
|
||||
// errno = 13 (Access denied)
|
||||
// In most of the anticipated use cases, that's probably the preferred
|
||||
// behavior.
|
||||
#include "base/logging.h"
|
||||
#define DEBUG_CHECK RAW_CHECK
|
||||
#else
|
||||
#define DEBUG_CHECK(x) do { if (x) { } } while (0)
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace strings {
|
||||
|
||||
// The code in this file is extremely careful to be async-signal-safe.
|
||||
//
|
||||
// Most obviously, we avoid calling any code that could dynamically allocate
|
||||
// memory. Doing so would almost certainly result in bugs and dead-locks.
|
||||
// We also avoid calling any other STL functions that could have unintended
|
||||
// side-effects involving memory allocation or access to other shared
|
||||
// resources.
|
||||
//
|
||||
// But on top of that, we also avoid calling other library functions, as many
|
||||
// of them have the side-effect of calling getenv() (in order to deal with
|
||||
// localization) or accessing errno. The latter sounds benign, but there are
|
||||
// several execution contexts where it isn't even possible to safely read let
|
||||
// alone write errno.
|
||||
//
|
||||
// The stated design goal of the SafeSPrintf() function is that it can be
|
||||
// called from any context that can safely call C or C++ code (i.e. anything
|
||||
// that doesn't require assembly code).
|
||||
//
|
||||
// For a brief overview of some but not all of the issues with async-signal-
|
||||
// safety, refer to:
|
||||
// http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
|
||||
|
||||
namespace {
|
||||
const size_t kSSizeMaxConst = ((size_t)(ssize_t)-1) >> 1;
|
||||
|
||||
const char kUpCaseHexDigits[] = "0123456789ABCDEF";
|
||||
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 static_assert to
|
||||
// verify that this worked correctly.
|
||||
namespace {
|
||||
const size_t kSSizeMax = kSSizeMaxConst;
|
||||
}
|
||||
#else // defined(NDEBUG)
|
||||
// For efficiency, we really need kSSizeMax to be a constant. But for unit
|
||||
// tests, it should be adjustable. This allows us to verify edge cases without
|
||||
// having to fill the entire available address space. As a compromise, we make
|
||||
// kSSizeMax adjustable in debug builds, and then only compile that particular
|
||||
// part of the unit test in debug builds.
|
||||
namespace {
|
||||
static size_t kSSizeMax = kSSizeMaxConst;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
void SetSafeSPrintfSSizeMaxForTest(size_t max) {
|
||||
kSSizeMax = max;
|
||||
}
|
||||
|
||||
size_t GetSafeSPrintfSSizeMaxForTest() {
|
||||
return kSSizeMax;
|
||||
}
|
||||
}
|
||||
#endif // defined(NDEBUG)
|
||||
|
||||
namespace {
|
||||
class Buffer {
|
||||
public:
|
||||
// |buffer| is caller-allocated storage that SafeSPrintf() writes to. It
|
||||
// has |size| bytes of writable storage. It is the caller's responsibility
|
||||
// to ensure that the buffer is at least one byte in size, so that it fits
|
||||
// the trailing NUL that will be added by the destructor. The buffer also
|
||||
// must be smaller or equal to kSSizeMax in size.
|
||||
Buffer(char* buffer, size_t size)
|
||||
: buffer_(buffer),
|
||||
size_(size - 1), // Account for trailing NUL byte
|
||||
count_(0) {
|
||||
// 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()),
|
||||
"kSSizeMaxConst should be the max value of an ssize_t");
|
||||
#endif
|
||||
DEBUG_CHECK(size > 0);
|
||||
DEBUG_CHECK(size <= kSSizeMax);
|
||||
}
|
||||
|
||||
~Buffer() {
|
||||
// The code calling the constructor guaranteed that there was enough space
|
||||
// to store a trailing NUL -- and in debug builds, we are actually
|
||||
// verifying this with DEBUG_CHECK()s in the constructor. So, we can
|
||||
// always unconditionally write the NUL byte in the destructor. We do not
|
||||
// need to adjust the count_, as SafeSPrintf() copies snprintf() in not
|
||||
// including the NUL byte in its return code.
|
||||
*GetInsertionPoint() = '\000';
|
||||
}
|
||||
|
||||
// Returns true, iff the buffer is filled all the way to |kSSizeMax-1|. The
|
||||
// caller can now stop adding more data, as GetCount() has reached its
|
||||
// maximum possible value.
|
||||
inline bool OutOfAddressableSpace() const {
|
||||
return count_ == static_cast<size_t>(kSSizeMax - 1);
|
||||
}
|
||||
|
||||
// Returns the number of bytes that would have been emitted to |buffer_|
|
||||
// if it was sized sufficiently large. This number can be larger than
|
||||
// |size_|, if the caller provided an insufficiently large output buffer.
|
||||
// But it will never be bigger than |kSSizeMax-1|.
|
||||
inline ssize_t GetCount() const {
|
||||
DEBUG_CHECK(count_ < kSSizeMax);
|
||||
return static_cast<ssize_t>(count_);
|
||||
}
|
||||
|
||||
// Emits one |ch| character into the |buffer_| and updates the |count_| of
|
||||
// characters that are currently supposed to be in the buffer.
|
||||
// Returns "false", iff the buffer was already full.
|
||||
// N.B. |count_| increases even if no characters have been written. This is
|
||||
// needed so that GetCount() can return the number of bytes that should
|
||||
// have been allocated for the |buffer_|.
|
||||
inline bool Out(char ch) {
|
||||
if (size_ >= 1 && count_ < size_) {
|
||||
buffer_[count_] = ch;
|
||||
return IncrementCountByOne();
|
||||
}
|
||||
// |count_| still needs to be updated, even if the buffer has been
|
||||
// filled completely. This allows SafeSPrintf() to return the number of
|
||||
// bytes that should have been emitted.
|
||||
IncrementCountByOne();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Inserts |padding|-|len| bytes worth of padding into the |buffer_|.
|
||||
// |count_| will also be incremented by the number of bytes that were meant
|
||||
// to be emitted. The |pad| character is typically either a ' ' space
|
||||
// or a '0' zero, but other non-NUL values are legal.
|
||||
// Returns "false", iff the the |buffer_| filled up (i.e. |count_|
|
||||
// overflowed |size_|) at any time during padding.
|
||||
inline bool Pad(char pad, size_t padding, size_t len) {
|
||||
DEBUG_CHECK(pad);
|
||||
DEBUG_CHECK(padding <= kSSizeMax);
|
||||
for (; padding > len; --padding) {
|
||||
if (!Out(pad)) {
|
||||
if (--padding) {
|
||||
IncrementCount(padding-len);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// POSIX doesn't define any async-signal-safe function for converting
|
||||
// an integer to ASCII. Define our own version.
|
||||
//
|
||||
// This also gives us the ability to make the function a little more
|
||||
// powerful and have it deal with |padding|, with truncation, and with
|
||||
// predicting the length of the untruncated output.
|
||||
//
|
||||
// IToASCII() converts an integer |i| to ASCII.
|
||||
//
|
||||
// Unlike similar functions in the standard C library, it never appends a
|
||||
// NUL character. This is left for the caller to do.
|
||||
//
|
||||
// While the function signature takes a signed int64_t, the code decides at
|
||||
// run-time whether to treat the argument as signed (int64_t) or as unsigned
|
||||
// (uint64_t) based on the value of |sign|.
|
||||
//
|
||||
// It supports |base|s 2 through 16. Only a |base| of 10 is allowed to have
|
||||
// a |sign|. Otherwise, |i| is treated as unsigned.
|
||||
//
|
||||
// For bases larger than 10, |upcase| decides whether lower-case or upper-
|
||||
// case letters should be used to designate digits greater than 10.
|
||||
//
|
||||
// Padding can be done with either '0' zeros or ' ' spaces. Padding has to
|
||||
// be positive and will always be applied to the left of the output.
|
||||
//
|
||||
// Prepends a |prefix| to the number (e.g. "0x"). This prefix goes to
|
||||
// the left of |padding|, if |pad| is '0'; and to the right of |padding|
|
||||
// if |pad| is ' '.
|
||||
//
|
||||
// Returns "false", if the |buffer_| overflowed at any time.
|
||||
bool IToASCII(bool sign, bool upcase, int64_t i, int base,
|
||||
char pad, size_t padding, const char* prefix);
|
||||
|
||||
private:
|
||||
// Increments |count_| by |inc| unless this would cause |count_| to
|
||||
// overflow |kSSizeMax-1|. Returns "false", iff an overflow was detected;
|
||||
// it then clamps |count_| to |kSSizeMax-1|.
|
||||
inline bool IncrementCount(size_t inc) {
|
||||
// "inc" is either 1 or a "padding" value. Padding is clamped at
|
||||
// run-time to at most kSSizeMax-1. So, we know that "inc" is always in
|
||||
// the range 1..kSSizeMax-1.
|
||||
// This allows us to compute "kSSizeMax - 1 - inc" without incurring any
|
||||
// integer overflows.
|
||||
DEBUG_CHECK(inc <= kSSizeMax - 1);
|
||||
if (count_ > kSSizeMax - 1 - inc) {
|
||||
count_ = kSSizeMax - 1;
|
||||
return false;
|
||||
} else {
|
||||
count_ += inc;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience method for the common case of incrementing |count_| by one.
|
||||
inline bool IncrementCountByOne() {
|
||||
return IncrementCount(1);
|
||||
}
|
||||
|
||||
// Return the current insertion point into the buffer. This is typically
|
||||
// at |buffer_| + |count_|, but could be before that if truncation
|
||||
// happened. It always points to one byte past the last byte that was
|
||||
// successfully placed into the |buffer_|.
|
||||
inline char* GetInsertionPoint() const {
|
||||
size_t idx = count_;
|
||||
if (idx > size_) {
|
||||
idx = size_;
|
||||
}
|
||||
return buffer_ + idx;
|
||||
}
|
||||
|
||||
// User-provided buffer that will receive the fully formatted output string.
|
||||
char* buffer_;
|
||||
|
||||
// Number of bytes that are available in the buffer excluding the trailing
|
||||
// NUL byte that will be added by the destructor.
|
||||
const size_t size_;
|
||||
|
||||
// Number of bytes that would have been emitted to the buffer, if the buffer
|
||||
// was sufficiently big. This number always excludes the trailing NUL byte
|
||||
// and it is guaranteed to never grow bigger than kSSizeMax-1.
|
||||
size_t count_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Buffer);
|
||||
};
|
||||
|
||||
|
||||
bool Buffer::IToASCII(bool sign, bool upcase, int64_t i, int base,
|
||||
char pad, size_t padding, const char* prefix) {
|
||||
// Sanity check for parameters. None of these should ever fail, but see
|
||||
// above for the rationale why we can't call CHECK().
|
||||
DEBUG_CHECK(base >= 2);
|
||||
DEBUG_CHECK(base <= 16);
|
||||
DEBUG_CHECK(!sign || base == 10);
|
||||
DEBUG_CHECK(pad == '0' || pad == ' ');
|
||||
DEBUG_CHECK(padding <= kSSizeMax);
|
||||
DEBUG_CHECK(!(sign && prefix && *prefix));
|
||||
|
||||
// Handle negative numbers, if the caller indicated that |i| should be
|
||||
// treated as a signed number; otherwise treat |i| as unsigned (even if the
|
||||
// MSB is set!)
|
||||
// Details are tricky, because of limited data-types, but equivalent pseudo-
|
||||
// code would look like:
|
||||
// if (sign && i < 0)
|
||||
// prefix = "-";
|
||||
// num = abs(i);
|
||||
int minint = 0;
|
||||
uint64_t num;
|
||||
if (sign && i < 0) {
|
||||
prefix = "-";
|
||||
|
||||
// Turn our number positive.
|
||||
if (i == std::numeric_limits<int64_t>::min()) {
|
||||
// The most negative integer needs special treatment.
|
||||
minint = 1;
|
||||
num = static_cast<uint64_t>(-(i + 1));
|
||||
} else {
|
||||
// "Normal" negative numbers are easy.
|
||||
num = static_cast<uint64_t>(-i);
|
||||
}
|
||||
} else {
|
||||
num = static_cast<uint64_t>(i);
|
||||
}
|
||||
|
||||
// If padding with '0' zero, emit the prefix or '-' character now. Otherwise,
|
||||
// make the prefix accessible in reverse order, so that we can later output
|
||||
// it right between padding and the number.
|
||||
// We cannot choose the easier approach of just reversing the number, as that
|
||||
// fails in situations where we need to truncate numbers that have padding
|
||||
// and/or prefixes.
|
||||
const char* reverse_prefix = NULL;
|
||||
if (prefix && *prefix) {
|
||||
if (pad == '0') {
|
||||
while (*prefix) {
|
||||
if (padding) {
|
||||
--padding;
|
||||
}
|
||||
Out(*prefix++);
|
||||
}
|
||||
prefix = NULL;
|
||||
} else {
|
||||
for (reverse_prefix = prefix; *reverse_prefix; ++reverse_prefix) {
|
||||
}
|
||||
}
|
||||
} else
|
||||
prefix = NULL;
|
||||
const size_t prefix_length = reverse_prefix - prefix;
|
||||
|
||||
// Loop until we have converted the entire number. Output at least one
|
||||
// character (i.e. '0').
|
||||
size_t start = count_;
|
||||
size_t discarded = 0;
|
||||
bool started = false;
|
||||
do {
|
||||
// Make sure there is still enough space left in our output buffer.
|
||||
if (count_ >= size_) {
|
||||
if (start < size_) {
|
||||
// It is rare that we need to output a partial number. But if asked
|
||||
// to do so, we will still make sure we output the correct number of
|
||||
// leading digits.
|
||||
// Since we are generating the digits in reverse order, we actually
|
||||
// have to discard digits in the order that we have already emitted
|
||||
// them. This is essentially equivalent to:
|
||||
// memmove(buffer_ + start, buffer_ + start + 1, size_ - start - 1)
|
||||
for (char* move = buffer_ + start, *end = buffer_ + size_ - 1;
|
||||
move < end;
|
||||
++move) {
|
||||
*move = move[1];
|
||||
}
|
||||
++discarded;
|
||||
--count_;
|
||||
} else if (count_ - size_ > 1) {
|
||||
// Need to increment either |count_| or |discarded| to make progress.
|
||||
// The latter is more efficient, as it eventually triggers fast
|
||||
// handling of padding. But we have to ensure we don't accidentally
|
||||
// change the overall state (i.e. switch the state-machine from
|
||||
// discarding to non-discarding). |count_| needs to always stay
|
||||
// bigger than |size_|.
|
||||
--count_;
|
||||
++discarded;
|
||||
}
|
||||
}
|
||||
|
||||
// Output the next digit and (if necessary) compensate for the most
|
||||
// negative integer needing special treatment. This works because,
|
||||
// no matter the bit width of the integer, the lowest-most decimal
|
||||
// integer always ends in 2, 4, 6, or 8.
|
||||
if (!num && started) {
|
||||
if (reverse_prefix > prefix) {
|
||||
Out(*--reverse_prefix);
|
||||
} else {
|
||||
Out(pad);
|
||||
}
|
||||
} else {
|
||||
started = true;
|
||||
Out((upcase ? kUpCaseHexDigits : kDownCaseHexDigits)[num%base + minint]);
|
||||
}
|
||||
|
||||
minint = 0;
|
||||
num /= base;
|
||||
|
||||
// Add padding, if requested.
|
||||
if (padding > 0) {
|
||||
--padding;
|
||||
|
||||
// Performance optimization for when we are asked to output excessive
|
||||
// padding, but our output buffer is limited in size. Even if we output
|
||||
// a 64bit number in binary, we would never write more than 64 plus
|
||||
// prefix non-padding characters. So, once this limit has been passed,
|
||||
// any further state change can be computed arithmetically; we know that
|
||||
// by this time, our entire final output consists of padding characters
|
||||
// that have all already been output.
|
||||
if (discarded > 8*sizeof(num) + prefix_length) {
|
||||
IncrementCount(padding);
|
||||
padding = 0;
|
||||
}
|
||||
}
|
||||
} while (num || padding || (reverse_prefix > prefix));
|
||||
|
||||
// Conversion to ASCII actually resulted in the digits being in reverse
|
||||
// order. We can't easily generate them in forward order, as we can't tell
|
||||
// the number of characters needed until we are done converting.
|
||||
// So, now, we reverse the string (except for the possible '-' sign).
|
||||
char* front = buffer_ + start;
|
||||
char* back = GetInsertionPoint();
|
||||
while (--back > front) {
|
||||
char ch = *back;
|
||||
*back = *front;
|
||||
*front++ = ch;
|
||||
}
|
||||
|
||||
IncrementCount(discarded);
|
||||
return !discarded;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt, const Arg* args,
|
||||
const size_t max_args) {
|
||||
// Make sure that at least one NUL byte can be written, and that the buffer
|
||||
// never overflows kSSizeMax. Not only does that use up most or all of the
|
||||
// address space, it also would result in a return code that cannot be
|
||||
// represented.
|
||||
if (static_cast<ssize_t>(sz) < 1) {
|
||||
return -1;
|
||||
} else if (sz > kSSizeMax) {
|
||||
sz = kSSizeMax;
|
||||
}
|
||||
|
||||
// Iterate over format string and interpret '%' arguments as they are
|
||||
// encountered.
|
||||
Buffer buffer(buf, sz);
|
||||
size_t padding;
|
||||
char pad;
|
||||
for (unsigned int cur_arg = 0; *fmt && !buffer.OutOfAddressableSpace(); ) {
|
||||
if (*fmt++ == '%') {
|
||||
padding = 0;
|
||||
pad = ' ';
|
||||
char ch = *fmt++;
|
||||
format_character_found:
|
||||
switch (ch) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
// Found a width parameter. Convert to an integer value and store in
|
||||
// "padding". If the leading digit is a zero, change the padding
|
||||
// character from a space ' ' to a zero '0'.
|
||||
pad = ch == '0' ? '0' : ' ';
|
||||
for (;;) {
|
||||
// The maximum allowed padding fills all the available address
|
||||
// space and leaves just enough space to insert the trailing NUL.
|
||||
const size_t max_padding = kSSizeMax - 1;
|
||||
if (padding > max_padding/10 ||
|
||||
10*padding > max_padding - (ch - '0')) {
|
||||
DEBUG_CHECK(padding <= max_padding/10 &&
|
||||
10*padding <= max_padding - (ch - '0'));
|
||||
// Integer overflow detected. Skip the rest of the width until
|
||||
// we find the format character, then do the normal error handling.
|
||||
padding_overflow:
|
||||
padding = max_padding;
|
||||
while ((ch = *fmt++) >= '0' && ch <= '9') {
|
||||
}
|
||||
if (cur_arg < max_args) {
|
||||
++cur_arg;
|
||||
}
|
||||
goto fail_to_expand;
|
||||
}
|
||||
padding = 10*padding + ch - '0';
|
||||
if (padding > max_padding) {
|
||||
// This doesn't happen for "sane" values of kSSizeMax. But once
|
||||
// kSSizeMax gets smaller than about 10, our earlier range checks
|
||||
// are incomplete. Unittests do trigger this artificial corner
|
||||
// case.
|
||||
DEBUG_CHECK(padding <= max_padding);
|
||||
goto padding_overflow;
|
||||
}
|
||||
ch = *fmt++;
|
||||
if (ch < '0' || ch > '9') {
|
||||
// Reached the end of the width parameter. This is where the format
|
||||
// character is found.
|
||||
goto format_character_found;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'c': { // Output an ASCII character.
|
||||
// Check that there are arguments left to be inserted.
|
||||
if (cur_arg >= max_args) {
|
||||
DEBUG_CHECK(cur_arg < max_args);
|
||||
goto fail_to_expand;
|
||||
}
|
||||
|
||||
// Check that the argument has the expected type.
|
||||
const Arg& arg = args[cur_arg++];
|
||||
if (arg.type != Arg::INT && arg.type != Arg::UINT) {
|
||||
DEBUG_CHECK(arg.type == Arg::INT || arg.type == Arg::UINT);
|
||||
goto fail_to_expand;
|
||||
}
|
||||
|
||||
// Apply padding, if needed.
|
||||
buffer.Pad(' ', padding, 1);
|
||||
|
||||
// Convert the argument to an ASCII character and output it.
|
||||
char as_char = static_cast<char>(arg.integer.i);
|
||||
if (!as_char) {
|
||||
goto end_of_output_buffer;
|
||||
}
|
||||
buffer.Out(as_char);
|
||||
break; }
|
||||
case 'd': // Output a possibly signed decimal value.
|
||||
case 'o': // Output an unsigned octal value.
|
||||
case 'x': // Output an unsigned hexadecimal value.
|
||||
case 'X':
|
||||
case 'p': { // Output a pointer value.
|
||||
// Check that there are arguments left to be inserted.
|
||||
if (cur_arg >= max_args) {
|
||||
DEBUG_CHECK(cur_arg < max_args);
|
||||
goto fail_to_expand;
|
||||
}
|
||||
|
||||
const Arg& arg = args[cur_arg++];
|
||||
int64_t i;
|
||||
const char* prefix = NULL;
|
||||
if (ch != 'p') {
|
||||
// Check that the argument has the expected type.
|
||||
if (arg.type != Arg::INT && arg.type != Arg::UINT) {
|
||||
DEBUG_CHECK(arg.type == Arg::INT || arg.type == Arg::UINT);
|
||||
goto fail_to_expand;
|
||||
}
|
||||
i = arg.integer.i;
|
||||
|
||||
if (ch != 'd') {
|
||||
// The Arg() constructor automatically performed sign expansion on
|
||||
// signed parameters. This is great when outputting a %d decimal
|
||||
// number, but can result in unexpected leading 0xFF bytes when
|
||||
// outputting a %x hexadecimal number. Mask bits, if necessary.
|
||||
// We have to do this here, instead of in the Arg() constructor, as
|
||||
// the Arg() constructor cannot tell whether we will output a %d
|
||||
// or a %x. Only the latter should experience masking.
|
||||
if (arg.integer.width < sizeof(int64_t)) {
|
||||
i &= (1LL << (8*arg.integer.width)) - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Pointer values require an actual pointer or a string.
|
||||
if (arg.type == Arg::POINTER) {
|
||||
i = reinterpret_cast<uintptr_t>(arg.ptr);
|
||||
} else if (arg.type == Arg::STRING) {
|
||||
i = reinterpret_cast<uintptr_t>(arg.str);
|
||||
} else if (arg.type == Arg::INT &&
|
||||
arg.integer.width == sizeof(NULL) &&
|
||||
arg.integer.i == 0) { // Allow C++'s version of NULL
|
||||
i = 0;
|
||||
} else {
|
||||
DEBUG_CHECK(arg.type == Arg::POINTER || arg.type == Arg::STRING);
|
||||
goto fail_to_expand;
|
||||
}
|
||||
|
||||
// Pointers always include the "0x" prefix.
|
||||
prefix = "0x";
|
||||
}
|
||||
|
||||
// Use IToASCII() to convert to ASCII representation. For decimal
|
||||
// numbers, optionally print a sign. For hexadecimal numbers,
|
||||
// distinguish between upper and lower case. %p addresses are always
|
||||
// printed as upcase. Supports base 8, 10, and 16. Prints padding
|
||||
// and/or prefixes, if so requested.
|
||||
buffer.IToASCII(ch == 'd' && arg.type == Arg::INT,
|
||||
ch != 'x', i,
|
||||
ch == 'o' ? 8 : ch == 'd' ? 10 : 16,
|
||||
pad, padding, prefix);
|
||||
break; }
|
||||
case 's': {
|
||||
// Check that there are arguments left to be inserted.
|
||||
if (cur_arg >= max_args) {
|
||||
DEBUG_CHECK(cur_arg < max_args);
|
||||
goto fail_to_expand;
|
||||
}
|
||||
|
||||
// Check that the argument has the expected type.
|
||||
const Arg& arg = args[cur_arg++];
|
||||
const char *s;
|
||||
if (arg.type == Arg::STRING) {
|
||||
s = arg.str ? arg.str : "<NULL>";
|
||||
} else if (arg.type == Arg::INT && arg.integer.width == sizeof(NULL) &&
|
||||
arg.integer.i == 0) { // Allow C++'s version of NULL
|
||||
s = "<NULL>";
|
||||
} else {
|
||||
DEBUG_CHECK(arg.type == Arg::STRING);
|
||||
goto fail_to_expand;
|
||||
}
|
||||
|
||||
// Apply padding, if needed. This requires us to first check the
|
||||
// length of the string that we are outputting.
|
||||
if (padding) {
|
||||
size_t len = 0;
|
||||
for (const char* src = s; *src++; ) {
|
||||
++len;
|
||||
}
|
||||
buffer.Pad(' ', padding, len);
|
||||
}
|
||||
|
||||
// Printing a string involves nothing more than copying it into the
|
||||
// output buffer and making sure we don't output more bytes than
|
||||
// available space; Out() takes care of doing that.
|
||||
for (const char* src = s; *src; ) {
|
||||
buffer.Out(*src++);
|
||||
}
|
||||
break; }
|
||||
case '%':
|
||||
// Quoted percent '%' character.
|
||||
goto copy_verbatim;
|
||||
fail_to_expand:
|
||||
// C++ gives us tools to do type checking -- something that snprintf()
|
||||
// could never really do. So, whenever we see arguments that don't
|
||||
// match up with the format string, we refuse to output them. But
|
||||
// since we have to be extremely conservative about being async-
|
||||
// signal-safe, we are limited in the type of error handling that we
|
||||
// can do in production builds (in debug builds we can use
|
||||
// DEBUG_CHECK() and hope for the best). So, all we do is pass the
|
||||
// format string unchanged. That should eventually get the user's
|
||||
// attention; and in the meantime, it hopefully doesn't lose too much
|
||||
// data.
|
||||
default:
|
||||
// Unknown or unsupported format character. Just copy verbatim to
|
||||
// output.
|
||||
buffer.Out('%');
|
||||
DEBUG_CHECK(ch);
|
||||
if (!ch) {
|
||||
goto end_of_format_string;
|
||||
}
|
||||
buffer.Out(ch);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
copy_verbatim:
|
||||
buffer.Out(fmt[-1]);
|
||||
}
|
||||
}
|
||||
end_of_format_string:
|
||||
end_of_output_buffer:
|
||||
return buffer.GetCount();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt) {
|
||||
// Make sure that at least one NUL byte can be written, and that the buffer
|
||||
// never overflows kSSizeMax. Not only does that use up most or all of the
|
||||
// address space, it also would result in a return code that cannot be
|
||||
// represented.
|
||||
if (static_cast<ssize_t>(sz) < 1) {
|
||||
return -1;
|
||||
} else if (sz > kSSizeMax) {
|
||||
sz = kSSizeMax;
|
||||
}
|
||||
|
||||
Buffer buffer(buf, sz);
|
||||
|
||||
// In the slow-path, we deal with errors by copying the contents of
|
||||
// "fmt" unexpanded. This means, if there are no arguments passed, the
|
||||
// SafeSPrintf() function always degenerates to a version of strncpy() that
|
||||
// de-duplicates '%' characters.
|
||||
const char* src = fmt;
|
||||
for (; *src; ++src) {
|
||||
buffer.Out(*src);
|
||||
DEBUG_CHECK(src[0] != '%' || src[1] == '%');
|
||||
if (src[0] == '%' && src[1] == '%') {
|
||||
++src;
|
||||
}
|
||||
}
|
||||
return buffer.GetCount();
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace base
|
||||
@@ -1,246 +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.
|
||||
|
||||
#ifndef BASE_STRINGS_SAFE_SPRINTF_H_
|
||||
#define BASE_STRINGS_SAFE_SPRINTF_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// For ssize_t
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
namespace base {
|
||||
namespace strings {
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Define ssize_t inside of our namespace.
|
||||
#if defined(_WIN64)
|
||||
typedef __int64 ssize_t;
|
||||
#else
|
||||
typedef long ssize_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// SafeSPrintf() is a type-safe and completely self-contained version of
|
||||
// snprintf().
|
||||
//
|
||||
// SafeSNPrintf() is an alternative function signature that can be used when
|
||||
// not dealing with fixed-sized buffers. When possible, SafeSPrintf() should
|
||||
// always be used instead of SafeSNPrintf()
|
||||
//
|
||||
// These functions allow for formatting complicated messages from contexts that
|
||||
// require strict async-signal-safety. In fact, it is safe to call them from
|
||||
// any low-level execution context, as they are guaranteed to make no library
|
||||
// or system calls. It deliberately never touches "errno", either.
|
||||
//
|
||||
// The only exception to this rule is that in debug builds the code calls
|
||||
// RAW_CHECK() to help diagnose problems when the format string does not
|
||||
// match the rest of the arguments. In release builds, no CHECK()s are used,
|
||||
// and SafeSPrintf() instead returns an output string that expands only
|
||||
// those arguments that match their format characters. Mismatched arguments
|
||||
// are ignored.
|
||||
//
|
||||
// The code currently only supports a subset of format characters:
|
||||
// %c, %o, %d, %x, %X, %p, and %s.
|
||||
//
|
||||
// SafeSPrintf() aims to be as liberal as reasonably possible. Integer-like
|
||||
// values of arbitrary width can be passed to all of the format characters
|
||||
// that expect integers. Thus, it is explicitly legal to pass an "int" to
|
||||
// "%c", and output will automatically look at the LSB only. It is also
|
||||
// explicitly legal to pass either signed or unsigned values, and the format
|
||||
// characters will automatically interpret the arguments accordingly.
|
||||
//
|
||||
// It is still not legal to mix-and-match integer-like values with pointer
|
||||
// values. For instance, you cannot pass a pointer to %x, nor can you pass an
|
||||
// integer to %p.
|
||||
//
|
||||
// The one exception is "0" zero being accepted by "%p". This works-around
|
||||
// the problem of C++ defining NULL as an integer-like value.
|
||||
//
|
||||
// All format characters take an optional width parameter. This must be a
|
||||
// positive integer. For %d, %o, %x, %X and %p, if the width starts with
|
||||
// a leading '0', padding is done with '0' instead of ' ' characters.
|
||||
//
|
||||
// There are a few features of snprintf()-style format strings, that
|
||||
// SafeSPrintf() does not support at this time.
|
||||
//
|
||||
// If an actual user showed up, there is no particularly strong reason they
|
||||
// couldn't be added. But that assumes that the trade-offs between complexity
|
||||
// and utility are favorable.
|
||||
//
|
||||
// For example, adding support for negative padding widths, and for %n are all
|
||||
// likely to be viewed positively. They are all clearly useful, low-risk, easy
|
||||
// to test, don't jeopardize the async-signal-safety of the code, and overall
|
||||
// have little impact on other parts of SafeSPrintf() function.
|
||||
//
|
||||
// On the other hands, adding support for alternate forms, positional
|
||||
// arguments, grouping, wide characters, localization or floating point numbers
|
||||
// are all unlikely to ever be added.
|
||||
//
|
||||
// SafeSPrintf() and SafeSNPrintf() mimic the behavior of snprintf() and they
|
||||
// return the number of bytes needed to store the untruncated output. This
|
||||
// does *not* include the terminating NUL byte.
|
||||
//
|
||||
// They return -1, iff a fatal error happened. This typically can only happen,
|
||||
// if the buffer size is a) negative, or b) zero (i.e. not even the NUL byte
|
||||
// can be written). The return value can never be larger than SSIZE_MAX-1.
|
||||
// This ensures that the caller can always add one to the signed return code
|
||||
// in order to determine the amount of storage that needs to be allocated.
|
||||
//
|
||||
// While the code supports type checking and while it is generally very careful
|
||||
// to avoid printing incorrect values, it tends to be conservative in printing
|
||||
// as much as possible, even when given incorrect parameters. Typically, in
|
||||
// case of an error, the format string will not be expanded. (i.e. something
|
||||
// like SafeSPrintf(buf, "%p %d", 1, 2) results in "%p 2"). See above for
|
||||
// the use of RAW_CHECK() in debug builds, though.
|
||||
//
|
||||
// Basic example:
|
||||
// char buf[20];
|
||||
// base::strings::SafeSPrintf(buf, "The answer: %2d", 42);
|
||||
//
|
||||
// Example with dynamically sized buffer (async-signal-safe). This code won't
|
||||
// work on Visual studio, as it requires dynamically allocating arrays on the
|
||||
// stack. Consider picking a smaller value for |kMaxSize| if stack size is
|
||||
// limited and known. On the other hand, if the parameters to SafeSNPrintf()
|
||||
// are trusted and not controllable by the user, you can consider eliminating
|
||||
// the check for |kMaxSize| altogether. The current value of SSIZE_MAX is
|
||||
// essentially a no-op that just illustrates how to implement an upper bound:
|
||||
// const size_t kInitialSize = 128;
|
||||
// const size_t kMaxSize = std::numeric_limits<ssize_t>::max();
|
||||
// size_t size = kInitialSize;
|
||||
// for (;;) {
|
||||
// char buf[size];
|
||||
// size = SafeSNPrintf(buf, size, "Error message \"%s\"\n", err) + 1;
|
||||
// if (sizeof(buf) < kMaxSize && size > kMaxSize) {
|
||||
// size = kMaxSize;
|
||||
// continue;
|
||||
// } else if (size > sizeof(buf))
|
||||
// continue;
|
||||
// write(2, buf, size-1);
|
||||
// break;
|
||||
// }
|
||||
|
||||
namespace internal {
|
||||
// Helpers that use C++ overloading, templates, and specializations to deduce
|
||||
// and record type information from function arguments. This allows us to
|
||||
// later write a type-safe version of snprintf().
|
||||
|
||||
struct Arg {
|
||||
enum Type { INT, UINT, STRING, POINTER };
|
||||
|
||||
// Any integer-like value.
|
||||
Arg(signed char c) : type(INT) {
|
||||
integer.i = c;
|
||||
integer.width = sizeof(char);
|
||||
}
|
||||
Arg(unsigned char c) : type(UINT) {
|
||||
integer.i = c;
|
||||
integer.width = sizeof(char);
|
||||
}
|
||||
Arg(signed short j) : type(INT) {
|
||||
integer.i = j;
|
||||
integer.width = sizeof(short);
|
||||
}
|
||||
Arg(unsigned short j) : type(UINT) {
|
||||
integer.i = j;
|
||||
integer.width = sizeof(short);
|
||||
}
|
||||
Arg(signed int j) : type(INT) {
|
||||
integer.i = j;
|
||||
integer.width = sizeof(int);
|
||||
}
|
||||
Arg(unsigned int j) : type(UINT) {
|
||||
integer.i = j;
|
||||
integer.width = sizeof(int);
|
||||
}
|
||||
Arg(signed long j) : type(INT) {
|
||||
integer.i = j;
|
||||
integer.width = sizeof(long);
|
||||
}
|
||||
Arg(unsigned long j) : type(UINT) {
|
||||
integer.i = j;
|
||||
integer.width = sizeof(long);
|
||||
}
|
||||
Arg(signed long long j) : type(INT) {
|
||||
integer.i = j;
|
||||
integer.width = sizeof(long long);
|
||||
}
|
||||
Arg(unsigned long long j) : type(UINT) {
|
||||
integer.i = j;
|
||||
integer.width = sizeof(long long);
|
||||
}
|
||||
|
||||
// A C-style text string.
|
||||
Arg(const char* s) : str(s), type(STRING) { }
|
||||
Arg(char* s) : str(s), type(STRING) { }
|
||||
|
||||
// Any pointer value that can be cast to a "void*".
|
||||
template<class T> Arg(T* p) : ptr((void*)p), type(POINTER) { }
|
||||
|
||||
union {
|
||||
// An integer-like value.
|
||||
struct {
|
||||
int64_t i;
|
||||
unsigned char width;
|
||||
} integer;
|
||||
|
||||
// A C-style text string.
|
||||
const char* str;
|
||||
|
||||
// A pointer to an arbitrary object.
|
||||
const void* ptr;
|
||||
};
|
||||
const enum Type type;
|
||||
};
|
||||
|
||||
// This is the internal function that performs the actual formatting of
|
||||
// an snprintf()-style format string.
|
||||
BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt,
|
||||
const Arg* args, size_t max_args);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
// In debug builds, allow unit tests to artificially lower the kSSizeMax
|
||||
// constant that is used as a hard upper-bound for all buffers. In normal
|
||||
// use, this constant should always be std::numeric_limits<ssize_t>::max().
|
||||
BASE_EXPORT void SetSafeSPrintfSSizeMaxForTest(size_t max);
|
||||
BASE_EXPORT size_t GetSafeSPrintfSSizeMaxForTest();
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template<typename... Args>
|
||||
ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args... args) {
|
||||
// Use Arg() object to record type information and then copy arguments to an
|
||||
// array to make it easier to iterate over them.
|
||||
const internal::Arg arg_array[] = { args... };
|
||||
return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args));
|
||||
}
|
||||
|
||||
template<size_t N, typename... Args>
|
||||
ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, Args... args) {
|
||||
// Use Arg() object to record type information and then copy arguments to an
|
||||
// array to make it easier to iterate over them.
|
||||
const internal::Arg arg_array[] = { args... };
|
||||
return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args));
|
||||
}
|
||||
|
||||
// Fast-path when we don't actually need to substitute any arguments.
|
||||
BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt);
|
||||
template<size_t N>
|
||||
inline ssize_t SafeSPrintf(char (&buf)[N], const char* fmt) {
|
||||
return SafeSNPrintf(buf, N, fmt);
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STRINGS_SAFE_SPRINTF_H_
|
||||
@@ -1,763 +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.
|
||||
|
||||
#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
|
||||
// tests, as they just make it hard to spot real problems.
|
||||
// TODO(markus): See if the restrictions on Android can eventually be lifted.
|
||||
#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
|
||||
#define ALLOW_DEATH_TEST
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace strings {
|
||||
|
||||
TEST(SafeSPrintfTest, Empty) {
|
||||
char buf[2] = { 'X', 'X' };
|
||||
|
||||
// Negative buffer size should always result in an error.
|
||||
EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), ""));
|
||||
EXPECT_EQ('X', buf[0]);
|
||||
EXPECT_EQ('X', buf[1]);
|
||||
|
||||
// Zero buffer size should always result in an error.
|
||||
EXPECT_EQ(-1, SafeSNPrintf(buf, 0, ""));
|
||||
EXPECT_EQ('X', buf[0]);
|
||||
EXPECT_EQ('X', buf[1]);
|
||||
|
||||
// A one-byte buffer should always print a single NUL byte.
|
||||
EXPECT_EQ(0, SafeSNPrintf(buf, 1, ""));
|
||||
EXPECT_EQ(0, buf[0]);
|
||||
EXPECT_EQ('X', buf[1]);
|
||||
buf[0] = 'X';
|
||||
|
||||
// A larger buffer should leave the trailing bytes unchanged.
|
||||
EXPECT_EQ(0, SafeSNPrintf(buf, 2, ""));
|
||||
EXPECT_EQ(0, buf[0]);
|
||||
EXPECT_EQ('X', buf[1]);
|
||||
buf[0] = 'X';
|
||||
|
||||
// The same test using SafeSPrintf() instead of SafeSNPrintf().
|
||||
EXPECT_EQ(0, SafeSPrintf(buf, ""));
|
||||
EXPECT_EQ(0, buf[0]);
|
||||
EXPECT_EQ('X', buf[1]);
|
||||
buf[0] = 'X';
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, NoArguments) {
|
||||
// Output a text message that doesn't require any substitutions. This
|
||||
// is roughly equivalent to calling strncpy() (but unlike strncpy(), it does
|
||||
// always add a trailing NUL; it always deduplicates '%' characters).
|
||||
static const char text[] = "hello world";
|
||||
char ref[20], buf[20];
|
||||
memset(ref, 'X', sizeof(ref));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// A negative buffer size should always result in an error.
|
||||
EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), text));
|
||||
EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
|
||||
|
||||
// Zero buffer size should always result in an error.
|
||||
EXPECT_EQ(-1, SafeSNPrintf(buf, 0, text));
|
||||
EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
|
||||
|
||||
// A one-byte buffer should always print a single NUL byte.
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 1, text));
|
||||
EXPECT_EQ(0, buf[0]);
|
||||
EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// A larger (but limited) buffer should always leave the trailing bytes
|
||||
// unchanged.
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 2, text));
|
||||
EXPECT_EQ(text[0], buf[0]);
|
||||
EXPECT_EQ(0, buf[1]);
|
||||
EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// A unrestricted buffer length should always leave the trailing bytes
|
||||
// unchanged.
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
|
||||
SafeSNPrintf(buf, sizeof(buf), text));
|
||||
EXPECT_EQ(std::string(text), std::string(buf));
|
||||
EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
|
||||
sizeof(buf) - sizeof(text)));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// The same test using SafeSPrintf() instead of SafeSNPrintf().
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, text));
|
||||
EXPECT_EQ(std::string(text), std::string(buf));
|
||||
EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
|
||||
sizeof(buf) - sizeof(text)));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// Check for deduplication of '%' percent characters.
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%%"));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%%%%"));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%%X"));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%%%%X"));
|
||||
#if defined(NDEBUG)
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%"));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%%%"));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%X"));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%%%X"));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%"), "src.1. == '%'");
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'");
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%X"), "src.1. == '%'");
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%%%X"), "src.1. == '%'");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, OneArgument) {
|
||||
// Test basic single-argument single-character substitution.
|
||||
const char text[] = "hello world";
|
||||
const char fmt[] = "hello%cworld";
|
||||
char ref[20], buf[20];
|
||||
memset(ref, 'X', sizeof(buf));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// A negative buffer size should always result in an error.
|
||||
EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), fmt, ' '));
|
||||
EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
|
||||
|
||||
// Zero buffer size should always result in an error.
|
||||
EXPECT_EQ(-1, SafeSNPrintf(buf, 0, fmt, ' '));
|
||||
EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
|
||||
|
||||
// A one-byte buffer should always print a single NUL byte.
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
|
||||
SafeSNPrintf(buf, 1, fmt, ' '));
|
||||
EXPECT_EQ(0, buf[0]);
|
||||
EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// A larger (but limited) buffer should always leave the trailing bytes
|
||||
// unchanged.
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
|
||||
SafeSNPrintf(buf, 2, fmt, ' '));
|
||||
EXPECT_EQ(text[0], buf[0]);
|
||||
EXPECT_EQ(0, buf[1]);
|
||||
EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// A unrestricted buffer length should always leave the trailing bytes
|
||||
// unchanged.
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
|
||||
SafeSNPrintf(buf, sizeof(buf), fmt, ' '));
|
||||
EXPECT_EQ(std::string(text), std::string(buf));
|
||||
EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
|
||||
sizeof(buf) - sizeof(text)));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// The same test using SafeSPrintf() instead of SafeSNPrintf().
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, fmt, ' '));
|
||||
EXPECT_EQ(std::string(text), std::string(buf));
|
||||
EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
|
||||
sizeof(buf) - sizeof(text)));
|
||||
memcpy(buf, ref, sizeof(buf));
|
||||
|
||||
// Check for deduplication of '%' percent characters.
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%%", 0));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%%%%", 0));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%Y", 0));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%%Y", 0));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%%%Y", 0));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%%%%Y", 0));
|
||||
#if defined(NDEBUG)
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%", 0));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%", 0), "ch");
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, MissingArg) {
|
||||
#if defined(NDEBUG)
|
||||
char buf[20];
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%c%c", 'A'));
|
||||
EXPECT_EQ("A%c", std::string(buf));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
char buf[20];
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%c%c", 'A'), "cur_arg < max_args");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, ASANFriendlyBufferTest) {
|
||||
// Print into a buffer that is sized exactly to size. ASAN can verify that
|
||||
// nobody attempts to write past the end of the buffer.
|
||||
// There is a more complicated test in PrintLongString() that covers a lot
|
||||
// more edge case, but it is also harder to debug in case of a failure.
|
||||
const char kTestString[] = "This is a test";
|
||||
scoped_ptr<char[]> buf(new char[sizeof(kTestString)]);
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1),
|
||||
SafeSNPrintf(buf.get(), sizeof(kTestString), kTestString));
|
||||
EXPECT_EQ(std::string(kTestString), std::string(buf.get()));
|
||||
EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1),
|
||||
SafeSNPrintf(buf.get(), sizeof(kTestString), "%s", kTestString));
|
||||
EXPECT_EQ(std::string(kTestString), std::string(buf.get()));
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, NArgs) {
|
||||
// Pre-C++11 compilers have a different code path, that can only print
|
||||
// up to ten distinct arguments.
|
||||
// We test both SafeSPrintf() and SafeSNPrintf(). This makes sure we don't
|
||||
// have typos in the copy-n-pasted code that is needed to deal with various
|
||||
// numbers of arguments.
|
||||
char buf[12];
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%c", 1));
|
||||
EXPECT_EQ("\1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%c%c", 1, 2));
|
||||
EXPECT_EQ("\1\2", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%c%c%c", 1, 2, 3));
|
||||
EXPECT_EQ("\1\2\3", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%c%c%c%c", 1, 2, 3, 4));
|
||||
EXPECT_EQ("\1\2\3\4", std::string(buf));
|
||||
EXPECT_EQ(5, SafeSPrintf(buf, "%c%c%c%c%c", 1, 2, 3, 4, 5));
|
||||
EXPECT_EQ("\1\2\3\4\5", std::string(buf));
|
||||
EXPECT_EQ(6, SafeSPrintf(buf, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6));
|
||||
EXPECT_EQ("\1\2\3\4\5\6", std::string(buf));
|
||||
EXPECT_EQ(7, SafeSPrintf(buf, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7));
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf));
|
||||
EXPECT_EQ(8, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7, 8));
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf));
|
||||
EXPECT_EQ(9, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c",
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9));
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf));
|
||||
EXPECT_EQ(10, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c",
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
|
||||
|
||||
// Repeat all the tests with SafeSNPrintf() instead of SafeSPrintf().
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf));
|
||||
EXPECT_EQ(1, SafeSNPrintf(buf, 11, "%c", 1));
|
||||
EXPECT_EQ("\1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSNPrintf(buf, 11, "%c%c", 1, 2));
|
||||
EXPECT_EQ("\1\2", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSNPrintf(buf, 11, "%c%c%c", 1, 2, 3));
|
||||
EXPECT_EQ("\1\2\3", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSNPrintf(buf, 11, "%c%c%c%c", 1, 2, 3, 4));
|
||||
EXPECT_EQ("\1\2\3\4", std::string(buf));
|
||||
EXPECT_EQ(5, SafeSNPrintf(buf, 11, "%c%c%c%c%c", 1, 2, 3, 4, 5));
|
||||
EXPECT_EQ("\1\2\3\4\5", std::string(buf));
|
||||
EXPECT_EQ(6, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6));
|
||||
EXPECT_EQ("\1\2\3\4\5\6", std::string(buf));
|
||||
EXPECT_EQ(7, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7));
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf));
|
||||
EXPECT_EQ(8, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c",
|
||||
1, 2, 3, 4, 5, 6, 7, 8));
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf));
|
||||
EXPECT_EQ(9, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c",
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9));
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf));
|
||||
EXPECT_EQ(10, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c%c",
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf));
|
||||
|
||||
EXPECT_EQ(11, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c%c",
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf));
|
||||
EXPECT_EQ(11, SafeSNPrintf(buf, 12, "%c%c%c%c%c%c%c%c%c%c%c",
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
|
||||
EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf));
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, DataTypes) {
|
||||
char buf[40];
|
||||
|
||||
// Bytes
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint8_t)1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%d", (uint8_t)-1));
|
||||
EXPECT_EQ("255", std::string(buf));
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int8_t)1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int8_t)-1));
|
||||
EXPECT_EQ("-1", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%d", (int8_t)-128));
|
||||
EXPECT_EQ("-128", std::string(buf));
|
||||
|
||||
// Half-words
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint16_t)1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(5, SafeSPrintf(buf, "%d", (uint16_t)-1));
|
||||
EXPECT_EQ("65535", std::string(buf));
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int16_t)1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int16_t)-1));
|
||||
EXPECT_EQ("-1", std::string(buf));
|
||||
EXPECT_EQ(6, SafeSPrintf(buf, "%d", (int16_t)-32768));
|
||||
EXPECT_EQ("-32768", std::string(buf));
|
||||
|
||||
// Words
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint32_t)1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(10, SafeSPrintf(buf, "%d", (uint32_t)-1));
|
||||
EXPECT_EQ("4294967295", std::string(buf));
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int32_t)1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int32_t)-1));
|
||||
EXPECT_EQ("-1", std::string(buf));
|
||||
// Work-around for an limitation of C90
|
||||
EXPECT_EQ(11, SafeSPrintf(buf, "%d", (int32_t)-2147483647-1));
|
||||
EXPECT_EQ("-2147483648", std::string(buf));
|
||||
|
||||
// Quads
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint64_t)1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(20, SafeSPrintf(buf, "%d", (uint64_t)-1));
|
||||
EXPECT_EQ("18446744073709551615", std::string(buf));
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int64_t)1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int64_t)-1));
|
||||
EXPECT_EQ("-1", std::string(buf));
|
||||
// Work-around for an limitation of C90
|
||||
EXPECT_EQ(20, SafeSPrintf(buf, "%d", (int64_t)-9223372036854775807LL-1));
|
||||
EXPECT_EQ("-9223372036854775808", std::string(buf));
|
||||
|
||||
// Strings (both const and mutable).
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "test"));
|
||||
EXPECT_EQ("test", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, buf));
|
||||
EXPECT_EQ("test", std::string(buf));
|
||||
|
||||
// Pointer
|
||||
char addr[20];
|
||||
sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf);
|
||||
SafeSPrintf(buf, "%p", buf);
|
||||
EXPECT_EQ(std::string(addr), std::string(buf));
|
||||
SafeSPrintf(buf, "%p", (const char *)buf);
|
||||
EXPECT_EQ(std::string(addr), std::string(buf));
|
||||
sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)sprintf);
|
||||
SafeSPrintf(buf, "%p", sprintf);
|
||||
EXPECT_EQ(std::string(addr), std::string(buf));
|
||||
|
||||
// Padding for pointers is a little more complicated because of the "0x"
|
||||
// prefix. Padding with '0' zeros is relatively straight-forward, but
|
||||
// padding with ' ' spaces requires more effort.
|
||||
sprintf(addr, "0x%017llX", (unsigned long long)(uintptr_t)buf);
|
||||
SafeSPrintf(buf, "%019p", buf);
|
||||
EXPECT_EQ(std::string(addr), std::string(buf));
|
||||
sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf);
|
||||
memset(addr, ' ',
|
||||
(char*)memmove(addr + sizeof(addr) - strlen(addr) - 1,
|
||||
addr, strlen(addr)+1) - addr);
|
||||
SafeSPrintf(buf, "%19p", buf);
|
||||
EXPECT_EQ(std::string(addr), std::string(buf));
|
||||
}
|
||||
|
||||
namespace {
|
||||
void PrintLongString(char* buf, size_t sz) {
|
||||
// Output a reasonably complex expression into a limited-size buffer.
|
||||
// At least one byte is available for writing the NUL character.
|
||||
CHECK_GT(sz, static_cast<size_t>(0));
|
||||
|
||||
// Allocate slightly more space, so that we can verify that SafeSPrintf()
|
||||
// never writes past the end of the buffer.
|
||||
scoped_ptr<char[]> tmp(new char[sz+2]);
|
||||
memset(tmp.get(), 'X', sz+2);
|
||||
|
||||
// Use SafeSPrintf() to output a complex list of arguments:
|
||||
// - test padding and truncating %c single characters.
|
||||
// - test truncating %s simple strings.
|
||||
// - test mismatching arguments and truncating (for %d != %s).
|
||||
// - test zero-padding and truncating %x hexadecimal numbers.
|
||||
// - test outputting and truncating %d MININT.
|
||||
// - test outputting and truncating %p arbitrary pointer values.
|
||||
// - test outputting, padding and truncating NULL-pointer %s strings.
|
||||
char* out = tmp.get();
|
||||
size_t out_sz = sz;
|
||||
size_t len;
|
||||
for (scoped_ptr<char[]> perfect_buf;;) {
|
||||
size_t needed = SafeSNPrintf(out, out_sz,
|
||||
#if defined(NDEBUG)
|
||||
"A%2cong %s: %d %010X %d %p%7s", 'l', "string", "",
|
||||
#else
|
||||
"A%2cong %s: %%d %010X %d %p%7s", 'l', "string",
|
||||
#endif
|
||||
0xDEADBEEF, std::numeric_limits<intptr_t>::min(),
|
||||
PrintLongString, static_cast<char*>(NULL)) + 1;
|
||||
|
||||
// Various sanity checks:
|
||||
// The numbered of characters needed to print the full string should always
|
||||
// be bigger or equal to the bytes that have actually been output.
|
||||
len = strlen(tmp.get());
|
||||
CHECK_GE(needed, len+1);
|
||||
|
||||
// The number of characters output should always fit into the buffer that
|
||||
// was passed into SafeSPrintf().
|
||||
CHECK_LT(len, out_sz);
|
||||
|
||||
// The output is always terminated with a NUL byte (actually, this test is
|
||||
// always going to pass, as strlen() already verified this)
|
||||
EXPECT_FALSE(tmp[len]);
|
||||
|
||||
// ASAN can check that we are not overwriting buffers, iff we make sure the
|
||||
// buffer is exactly the size that we are expecting to be written. After
|
||||
// running SafeSNPrintf() the first time, it is possible to compute the
|
||||
// correct buffer size for this test. So, allocate a second buffer and run
|
||||
// the exact same SafeSNPrintf() command again.
|
||||
if (!perfect_buf.get()) {
|
||||
out_sz = std::min(needed, sz);
|
||||
out = new char[out_sz];
|
||||
perfect_buf.reset(out);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// All trailing bytes are unchanged.
|
||||
for (size_t i = len+1; i < sz+2; ++i)
|
||||
EXPECT_EQ('X', tmp[i]);
|
||||
|
||||
// The text that was generated by SafeSPrintf() should always match the
|
||||
// equivalent text generated by sprintf(). Please note that the format
|
||||
// string for sprintf() is not complicated, as it does not have the
|
||||
// benefit of getting type information from the C++ compiler.
|
||||
//
|
||||
// N.B.: It would be so much cleaner to use snprintf(). But unfortunately,
|
||||
// Visual Studio doesn't support this function, and the work-arounds
|
||||
// are all really awkward.
|
||||
char ref[256];
|
||||
CHECK_LE(sz, sizeof(ref));
|
||||
sprintf(ref, "A long string: %%d 00DEADBEEF %lld 0x%llX <NULL>",
|
||||
static_cast<long long>(std::numeric_limits<intptr_t>::min()),
|
||||
static_cast<unsigned long long>(
|
||||
reinterpret_cast<uintptr_t>(PrintLongString)));
|
||||
ref[sz-1] = '\000';
|
||||
|
||||
#if defined(NDEBUG)
|
||||
const size_t kSSizeMax = std::numeric_limits<ssize_t>::max();
|
||||
#else
|
||||
const size_t kSSizeMax = internal::GetSafeSPrintfSSizeMaxForTest();
|
||||
#endif
|
||||
|
||||
// Compare the output from SafeSPrintf() to the one from sprintf().
|
||||
EXPECT_EQ(std::string(ref).substr(0, kSSizeMax-1), std::string(tmp.get()));
|
||||
|
||||
// We allocated a slightly larger buffer, so that we could perform some
|
||||
// extra sanity checks. Now that the tests have all passed, we copy the
|
||||
// data to the output buffer that the caller provided.
|
||||
memcpy(buf, tmp.get(), len+1);
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
class ScopedSafeSPrintfSSizeMaxSetter {
|
||||
public:
|
||||
ScopedSafeSPrintfSSizeMaxSetter(size_t sz) {
|
||||
old_ssize_max_ = internal::GetSafeSPrintfSSizeMaxForTest();
|
||||
internal::SetSafeSPrintfSSizeMaxForTest(sz);
|
||||
}
|
||||
|
||||
~ScopedSafeSPrintfSSizeMaxSetter() {
|
||||
internal::SetSafeSPrintfSSizeMaxForTest(old_ssize_max_);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t old_ssize_max_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedSafeSPrintfSSizeMaxSetter);
|
||||
};
|
||||
#endif
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(SafeSPrintfTest, Truncation) {
|
||||
// We use PrintLongString() to print a complex long string and then
|
||||
// truncate to all possible lengths. This ends up exercising a lot of
|
||||
// different code paths in SafeSPrintf() and IToASCII(), as truncation can
|
||||
// happen in a lot of different states.
|
||||
char ref[256];
|
||||
PrintLongString(ref, sizeof(ref));
|
||||
for (size_t i = strlen(ref)+1; i; --i) {
|
||||
char buf[sizeof(ref)];
|
||||
PrintLongString(buf, i);
|
||||
EXPECT_EQ(std::string(ref, i - 1), std::string(buf));
|
||||
}
|
||||
|
||||
// When compiling in debug mode, we have the ability to fake a small
|
||||
// upper limit for the maximum value that can be stored in an ssize_t.
|
||||
// SafeSPrintf() uses this upper limit to determine how many bytes it will
|
||||
// write to the buffer, even if the caller claimed a bigger buffer size.
|
||||
// Repeat the truncation test and verify that this other code path in
|
||||
// SafeSPrintf() works correctly, too.
|
||||
#if !defined(NDEBUG)
|
||||
for (size_t i = strlen(ref)+1; i > 1; --i) {
|
||||
ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(i);
|
||||
char buf[sizeof(ref)];
|
||||
PrintLongString(buf, sizeof(buf));
|
||||
EXPECT_EQ(std::string(ref, i - 1), std::string(buf));
|
||||
}
|
||||
|
||||
// kSSizeMax is also used to constrain the maximum amount of padding, before
|
||||
// SafeSPrintf() detects an error in the format string.
|
||||
ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(100);
|
||||
char buf[256];
|
||||
EXPECT_EQ(99, SafeSPrintf(buf, "%99c", ' '));
|
||||
EXPECT_EQ(std::string(99, ' '), std::string(buf));
|
||||
*buf = '\000';
|
||||
#if defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%100c", ' '), "padding <= max_padding");
|
||||
#endif
|
||||
EXPECT_EQ(0, *buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, Padding) {
|
||||
char buf[40], fmt[40];
|
||||
|
||||
// Chars %c
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%c", 'A'));
|
||||
EXPECT_EQ("A", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%2c", 'A'));
|
||||
EXPECT_EQ(" A", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%02c", 'A'));
|
||||
EXPECT_EQ(" A", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%-2c", 'A'));
|
||||
EXPECT_EQ("%-2c", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%dc", std::numeric_limits<ssize_t>::max() - 1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, SafeSPrintf(buf, fmt, 'A'));
|
||||
SafeSPrintf(fmt, "%%%dc",
|
||||
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
||||
#if defined(NDEBUG)
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, fmt, 'A'));
|
||||
EXPECT_EQ("%c", std::string(buf));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, fmt, 'A'), "padding <= max_padding");
|
||||
#endif
|
||||
|
||||
// Octal %o
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%o", 1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%2o", 1));
|
||||
EXPECT_EQ(" 1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%02o", 1));
|
||||
EXPECT_EQ("01", std::string(buf));
|
||||
EXPECT_EQ(12, SafeSPrintf(buf, "%12o", -1));
|
||||
EXPECT_EQ(" 37777777777", std::string(buf));
|
||||
EXPECT_EQ(12, SafeSPrintf(buf, "%012o", -1));
|
||||
EXPECT_EQ("037777777777", std::string(buf));
|
||||
EXPECT_EQ(23, SafeSPrintf(buf, "%23o", -1LL));
|
||||
EXPECT_EQ(" 1777777777777777777777", std::string(buf));
|
||||
EXPECT_EQ(23, SafeSPrintf(buf, "%023o", -1LL));
|
||||
EXPECT_EQ("01777777777777777777777", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%2o", 0111));
|
||||
EXPECT_EQ("111", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%-2o", 1));
|
||||
EXPECT_EQ("%-2o", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%do", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, 1));
|
||||
EXPECT_EQ(" ", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%0%do", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, 1));
|
||||
EXPECT_EQ("000", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%do",
|
||||
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
||||
#if defined(NDEBUG)
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
|
||||
EXPECT_EQ("%o", std::string(buf));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
|
||||
#endif
|
||||
|
||||
// Decimals %d
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", 1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%2d", 1));
|
||||
EXPECT_EQ(" 1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%02d", 1));
|
||||
EXPECT_EQ("01", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%3d", -1));
|
||||
EXPECT_EQ(" -1", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%03d", -1));
|
||||
EXPECT_EQ("-01", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%2d", 111));
|
||||
EXPECT_EQ("111", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%2d", -111));
|
||||
EXPECT_EQ("-111", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%-2d", 1));
|
||||
EXPECT_EQ("%-2d", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%dd", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, 1));
|
||||
EXPECT_EQ(" ", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%0%dd", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, 1));
|
||||
EXPECT_EQ("000", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%dd",
|
||||
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
||||
#if defined(NDEBUG)
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
|
||||
EXPECT_EQ("%d", std::string(buf));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
|
||||
#endif
|
||||
|
||||
// Hex %X
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%X", 1));
|
||||
EXPECT_EQ("1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%2X", 1));
|
||||
EXPECT_EQ(" 1", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%02X", 1));
|
||||
EXPECT_EQ("01", std::string(buf));
|
||||
EXPECT_EQ(9, SafeSPrintf(buf, "%9X", -1));
|
||||
EXPECT_EQ(" FFFFFFFF", std::string(buf));
|
||||
EXPECT_EQ(9, SafeSPrintf(buf, "%09X", -1));
|
||||
EXPECT_EQ("0FFFFFFFF", std::string(buf));
|
||||
EXPECT_EQ(17, SafeSPrintf(buf, "%17X", -1LL));
|
||||
EXPECT_EQ(" FFFFFFFFFFFFFFFF", std::string(buf));
|
||||
EXPECT_EQ(17, SafeSPrintf(buf, "%017X", -1LL));
|
||||
EXPECT_EQ("0FFFFFFFFFFFFFFFF", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%2X", 0x111));
|
||||
EXPECT_EQ("111", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%-2X", 1));
|
||||
EXPECT_EQ("%-2X", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%dX", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, 1));
|
||||
EXPECT_EQ(" ", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%0%dX", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, 1));
|
||||
EXPECT_EQ("000", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%dX",
|
||||
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
||||
#if defined(NDEBUG)
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
|
||||
EXPECT_EQ("%X", std::string(buf));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
|
||||
#endif
|
||||
|
||||
// Pointer %p
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%p", (void*)1));
|
||||
EXPECT_EQ("0x1", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%4p", (void*)1));
|
||||
EXPECT_EQ(" 0x1", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%04p", (void*)1));
|
||||
EXPECT_EQ("0x01", std::string(buf));
|
||||
EXPECT_EQ(5, SafeSPrintf(buf, "%4p", (void*)0x111));
|
||||
EXPECT_EQ("0x111", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%-2p", (void*)1));
|
||||
EXPECT_EQ("%-2p", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%dp", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, (void*)1));
|
||||
EXPECT_EQ(" ", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%0%dp", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, (void*)1));
|
||||
EXPECT_EQ("0x0", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%dp",
|
||||
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
||||
#if defined(NDEBUG)
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
|
||||
EXPECT_EQ("%p", std::string(buf));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
|
||||
#endif
|
||||
|
||||
// String
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%s", "A"));
|
||||
EXPECT_EQ("A", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%2s", "A"));
|
||||
EXPECT_EQ(" A", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%02s", "A"));
|
||||
EXPECT_EQ(" A", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%2s", "AAA"));
|
||||
EXPECT_EQ("AAA", std::string(buf));
|
||||
EXPECT_EQ(4, SafeSPrintf(buf, "%-2s", "A"));
|
||||
EXPECT_EQ("%-2s", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%ds", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, "A"));
|
||||
EXPECT_EQ(" ", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%0%ds", std::numeric_limits<ssize_t>::max()-1);
|
||||
EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
|
||||
SafeSNPrintf(buf, 4, fmt, "A"));
|
||||
EXPECT_EQ(" ", std::string(buf));
|
||||
SafeSPrintf(fmt, "%%%ds",
|
||||
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
||||
#if defined(NDEBUG)
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, fmt, "A"));
|
||||
EXPECT_EQ("%s", std::string(buf));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, fmt, "A"), "padding <= max_padding");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, EmbeddedNul) {
|
||||
char buf[] = { 'X', 'X', 'X', 'X' };
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%3c", 0));
|
||||
EXPECT_EQ(' ', buf[0]);
|
||||
EXPECT_EQ(' ', buf[1]);
|
||||
EXPECT_EQ(0, buf[2]);
|
||||
EXPECT_EQ('X', buf[3]);
|
||||
|
||||
// Check handling of a NUL format character. N.B. this takes two different
|
||||
// code paths depending on whether we are actually passing arguments. If
|
||||
// we don't have any arguments, we are running in the fast-path code, that
|
||||
// looks (almost) like a strncpy().
|
||||
#if defined(NDEBUG)
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%%%"));
|
||||
EXPECT_EQ("%%", std::string(buf));
|
||||
EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0));
|
||||
EXPECT_EQ("%%", std::string(buf));
|
||||
#elif defined(ALLOW_DEATH_TEST)
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'");
|
||||
EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, EmitNULL) {
|
||||
char buf[40];
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wconversion-null"
|
||||
#endif
|
||||
EXPECT_EQ(1, SafeSPrintf(buf, "%d", NULL));
|
||||
EXPECT_EQ("0", std::string(buf));
|
||||
EXPECT_EQ(3, SafeSPrintf(buf, "%p", NULL));
|
||||
EXPECT_EQ("0x0", std::string(buf));
|
||||
EXPECT_EQ(6, SafeSPrintf(buf, "%s", NULL));
|
||||
EXPECT_EQ("<NULL>", std::string(buf));
|
||||
#if defined(__GCC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(SafeSPrintfTest, PointerSize) {
|
||||
// The internal data representation is a 64bit value, independent of the
|
||||
// native word size. We want to perform sign-extension for signed integers,
|
||||
// but we want to avoid doing so for pointer types. This could be a
|
||||
// problem on systems, where pointers are only 32bit. This tests verifies
|
||||
// that there is no such problem.
|
||||
char *str = reinterpret_cast<char *>(0x80000000u);
|
||||
void *ptr = str;
|
||||
char buf[40];
|
||||
EXPECT_EQ(10, SafeSPrintf(buf, "%p", str));
|
||||
EXPECT_EQ("0x80000000", std::string(buf));
|
||||
EXPECT_EQ(10, SafeSPrintf(buf, "%p", ptr));
|
||||
EXPECT_EQ("0x80000000", std::string(buf));
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace base
|
||||
@@ -1,82 +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.
|
||||
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
#if defined(WCHAR_T_IS_UTF16)
|
||||
|
||||
#error This file should not be used on 2-byte wchar_t systems
|
||||
// If this winds up being needed on 2-byte wchar_t systems, either the
|
||||
// definitions below can be used, or the host system's wide character
|
||||
// functions like wmemcmp can be wrapped.
|
||||
|
||||
#elif defined(WCHAR_T_IS_UTF32)
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
int c16memcmp(const char16* s1, const char16* s2, size_t n) {
|
||||
// We cannot call memcmp because that changes the semantics.
|
||||
while (n-- > 0) {
|
||||
if (*s1 != *s2) {
|
||||
// We cannot use (*s1 - *s2) because char16 is unsigned.
|
||||
return ((*s1 < *s2) ? -1 : 1);
|
||||
}
|
||||
++s1;
|
||||
++s2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t c16len(const char16* s) {
|
||||
const char16 *s_orig = s;
|
||||
while (*s) {
|
||||
++s;
|
||||
}
|
||||
return s - s_orig;
|
||||
}
|
||||
|
||||
const char16* c16memchr(const char16* s, char16 c, size_t n) {
|
||||
while (n-- > 0) {
|
||||
if (*s == c) {
|
||||
return s;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char16* c16memmove(char16* s1, const char16* s2, size_t n) {
|
||||
return static_cast<char16*>(memmove(s1, s2, n * sizeof(char16)));
|
||||
}
|
||||
|
||||
char16* c16memcpy(char16* s1, const char16* s2, size_t n) {
|
||||
return static_cast<char16*>(memcpy(s1, s2, n * sizeof(char16)));
|
||||
}
|
||||
|
||||
char16* c16memset(char16* s, char16 c, size_t n) {
|
||||
char16 *s_orig = s;
|
||||
while (n-- > 0) {
|
||||
*s = c;
|
||||
++s;
|
||||
}
|
||||
return s_orig;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const string16& str) {
|
||||
return out << UTF16ToUTF8(str);
|
||||
}
|
||||
|
||||
void PrintTo(const string16& str, std::ostream* out) {
|
||||
*out << str;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
template class std::basic_string<base::char16, base::string16_char_traits>;
|
||||
|
||||
#endif // WCHAR_T_IS_UTF32
|
||||
@@ -1,187 +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.
|
||||
|
||||
#ifndef BASE_STRINGS_STRING16_H_
|
||||
#define BASE_STRINGS_STRING16_H_
|
||||
|
||||
// WHAT:
|
||||
// A version of std::basic_string that provides 2-byte characters even when
|
||||
// wchar_t is not implemented as a 2-byte type. You can access this class as
|
||||
// string16. We also define char16, which string16 is based upon.
|
||||
//
|
||||
// WHY:
|
||||
// On Windows, wchar_t is 2 bytes, and it can conveniently handle UTF-16/UCS-2
|
||||
// data. Plenty of existing code operates on strings encoded as UTF-16.
|
||||
//
|
||||
// On many other platforms, sizeof(wchar_t) is 4 bytes by default. We can make
|
||||
// it 2 bytes by using the GCC flag -fshort-wchar. But then std::wstring fails
|
||||
// at run time, because it calls some functions (like wcslen) that come from
|
||||
// the system's native C library -- which was built with a 4-byte wchar_t!
|
||||
// It's wasteful to use 4-byte wchar_t strings to carry UTF-16 data, and it's
|
||||
// entirely improper on those systems where the encoding of wchar_t is defined
|
||||
// as UTF-32.
|
||||
//
|
||||
// Here, we define string16, which is similar to std::wstring but replaces all
|
||||
// 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 "build/build_config.h"
|
||||
|
||||
#if defined(WCHAR_T_IS_UTF16)
|
||||
|
||||
namespace base {
|
||||
|
||||
typedef wchar_t char16;
|
||||
typedef std::wstring string16;
|
||||
typedef std::char_traits<wchar_t> string16_char_traits;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#elif defined(WCHAR_T_IS_UTF32)
|
||||
|
||||
namespace base {
|
||||
|
||||
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"
|
||||
// instead of "c16").
|
||||
BASE_EXPORT int c16memcmp(const char16* s1, const char16* s2, size_t n);
|
||||
BASE_EXPORT size_t c16len(const char16* s);
|
||||
BASE_EXPORT const char16* c16memchr(const char16* s, char16 c, size_t n);
|
||||
BASE_EXPORT char16* c16memmove(char16* s1, const char16* s2, size_t n);
|
||||
BASE_EXPORT char16* c16memcpy(char16* s1, const char16* s2, size_t n);
|
||||
BASE_EXPORT char16* c16memset(char16* s, char16 c, size_t n);
|
||||
|
||||
struct string16_char_traits {
|
||||
typedef char16 char_type;
|
||||
typedef int int_type;
|
||||
|
||||
// int_type needs to be able to hold each possible value of char_type, and in
|
||||
// addition, the distinct value of eof().
|
||||
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;
|
||||
typedef std::fpos<state_type> pos_type;
|
||||
|
||||
static void assign(char_type& c1, const char_type& c2) {
|
||||
c1 = c2;
|
||||
}
|
||||
|
||||
static bool eq(const char_type& c1, const char_type& c2) {
|
||||
return c1 == c2;
|
||||
}
|
||||
static bool lt(const char_type& c1, const char_type& c2) {
|
||||
return c1 < c2;
|
||||
}
|
||||
|
||||
static int compare(const char_type* s1, const char_type* s2, size_t n) {
|
||||
return c16memcmp(s1, s2, n);
|
||||
}
|
||||
|
||||
static size_t length(const char_type* s) {
|
||||
return c16len(s);
|
||||
}
|
||||
|
||||
static const char_type* find(const char_type* s, size_t n,
|
||||
const char_type& a) {
|
||||
return c16memchr(s, a, n);
|
||||
}
|
||||
|
||||
static char_type* move(char_type* s1, const char_type* s2, size_t n) {
|
||||
return c16memmove(s1, s2, n);
|
||||
}
|
||||
|
||||
static char_type* copy(char_type* s1, const char_type* s2, size_t n) {
|
||||
return c16memcpy(s1, s2, n);
|
||||
}
|
||||
|
||||
static char_type* assign(char_type* s, size_t n, char_type a) {
|
||||
return c16memset(s, a, n);
|
||||
}
|
||||
|
||||
static int_type not_eof(const int_type& c) {
|
||||
return eq_int_type(c, eof()) ? 0 : c;
|
||||
}
|
||||
|
||||
static char_type to_char_type(const int_type& c) {
|
||||
return char_type(c);
|
||||
}
|
||||
|
||||
static int_type to_int_type(const char_type& c) {
|
||||
return int_type(c);
|
||||
}
|
||||
|
||||
static bool eq_int_type(const int_type& c1, const int_type& c2) {
|
||||
return c1 == c2;
|
||||
}
|
||||
|
||||
static int_type eof() {
|
||||
return static_cast<int_type>(EOF);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::basic_string<char16, base::string16_char_traits> string16;
|
||||
|
||||
BASE_EXPORT extern std::ostream& operator<<(std::ostream& out,
|
||||
const string16& str);
|
||||
|
||||
// This is required by googletest to print a readable output on test failures.
|
||||
BASE_EXPORT extern void PrintTo(const string16& str, std::ostream* out);
|
||||
|
||||
} // namespace base
|
||||
|
||||
// The string class will be explicitly instantiated only once, in string16.cc.
|
||||
//
|
||||
// std::basic_string<> in GNU libstdc++ contains a static data member,
|
||||
// _S_empty_rep_storage, to represent empty strings. When an operation such
|
||||
// as assignment or destruction is performed on a string, causing its existing
|
||||
// data member to be invalidated, it must not be freed if this static data
|
||||
// member is being used. Otherwise, it counts as an attempt to free static
|
||||
// (and not allocated) data, which is a memory error.
|
||||
//
|
||||
// Generally, due to C++ template magic, _S_empty_rep_storage will be marked
|
||||
// as a coalesced symbol, meaning that the linker will combine multiple
|
||||
// instances into a single one when generating output.
|
||||
//
|
||||
// If a string class is used by multiple shared libraries, a problem occurs.
|
||||
// Each library will get its own copy of _S_empty_rep_storage. When strings
|
||||
// are passed across a library boundary for alteration or destruction, memory
|
||||
// errors will result. GNU libstdc++ contains a configuration option,
|
||||
// --enable-fully-dynamic-string (_GLIBCXX_FULLY_DYNAMIC_STRING), which
|
||||
// disables the static data member optimization, but it's a good optimization
|
||||
// and non-STL code is generally at the mercy of the system's STL
|
||||
// configuration. Fully-dynamic strings are not the default for GNU libstdc++
|
||||
// libstdc++ itself or for the libstdc++ installations on the systems we care
|
||||
// about, such as Mac OS X and relevant flavors of Linux.
|
||||
//
|
||||
// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24196 .
|
||||
//
|
||||
// To avoid problems, string classes need to be explicitly instantiated only
|
||||
// once, in exactly one library. All other string users see it via an "extern"
|
||||
// declaration. This is precisely how GNU libstdc++ handles
|
||||
// std::basic_string<char> (string) and std::basic_string<wchar_t> (wstring).
|
||||
//
|
||||
// This also works around a Mac OS X linker bug in ld64-85.2.1 (Xcode 3.1.2),
|
||||
// in which the linker does not fully coalesce symbols when dead code
|
||||
// stripping is enabled. This bug causes the memory errors described above
|
||||
// to occur even when a std::basic_string<> does not cross shared library
|
||||
// boundaries, such as in statically-linked executables.
|
||||
//
|
||||
// TODO(mark): File this bug with Apple and update this note with a bug number.
|
||||
|
||||
extern template
|
||||
class BASE_EXPORT std::basic_string<base::char16, base::string16_char_traits>;
|
||||
|
||||
#endif // WCHAR_T_IS_UTF32
|
||||
|
||||
#endif // BASE_STRINGS_STRING16_H_
|
||||
@@ -1,485 +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.
|
||||
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#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"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename STR, typename INT>
|
||||
struct IntToStringT {
|
||||
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 size_t kOutputBufSize =
|
||||
3 * sizeof(INT) + std::numeric_limits<INT>::is_signed;
|
||||
|
||||
// Create the string in a temporary buffer, write it back to front, and
|
||||
// then return the substr of what we ended up using.
|
||||
using CHR = typename STR::value_type;
|
||||
CHR outbuf[kOutputBufSize];
|
||||
|
||||
// The ValueOrDie call below can never fail, because UnsignedAbs is valid
|
||||
// for all valid inputs.
|
||||
auto res = CheckedNumeric<INT>(value).UnsignedAbs().ValueOrDie();
|
||||
|
||||
CHR* end = outbuf + kOutputBufSize;
|
||||
CHR* i = end;
|
||||
do {
|
||||
--i;
|
||||
DCHECK(i != outbuf);
|
||||
*i = static_cast<CHR>((res % 10) + '0');
|
||||
res /= 10;
|
||||
} while (res != 0);
|
||||
if (IsValueNegative(value)) {
|
||||
--i;
|
||||
DCHECK(i != outbuf);
|
||||
*i = static_cast<CHR>('-');
|
||||
}
|
||||
return STR(i, end);
|
||||
}
|
||||
};
|
||||
|
||||
// Utility to convert a character to a digit in a given base
|
||||
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_t* digit) {
|
||||
if (c >= '0' && c < '0' + BASE) {
|
||||
*digit = static_cast<uint8_t>(c - '0');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for bases where 10 < base <= 36
|
||||
template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
|
||||
public:
|
||||
static bool Convert(CHAR c, uint8_t* digit) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
*digit = c - '0';
|
||||
} else if (c >= 'a' && c < 'a' + BASE - 10) {
|
||||
*digit = c - 'a' + 10;
|
||||
} else if (c >= 'A' && c < 'A' + BASE - 10) {
|
||||
*digit = c - 'A' + 10;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <int BASE, typename CHAR>
|
||||
bool CharToDigit(CHAR c, uint8_t* digit) {
|
||||
return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
|
||||
}
|
||||
|
||||
// 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 {
|
||||
};
|
||||
|
||||
template<> class WhitespaceHelper<char> {
|
||||
public:
|
||||
static bool Invoke(char c) {
|
||||
return 0 != isspace(static_cast<unsigned char>(c));
|
||||
}
|
||||
};
|
||||
|
||||
template<> class WhitespaceHelper<char16> {
|
||||
public:
|
||||
static bool Invoke(char16 c) {
|
||||
return 0 != iswspace(c);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename CHAR> bool LocalIsWhitespace(CHAR c) {
|
||||
return WhitespaceHelper<CHAR>::Invoke(c);
|
||||
}
|
||||
|
||||
// IteratorRangeToNumberTraits should provide:
|
||||
// - a typedef for iterator_type, the iterator type used as input.
|
||||
// - a typedef for value_type, the target numeric type.
|
||||
// - static functions min, max (returning the minimum and maximum permitted
|
||||
// values)
|
||||
// - constant kBase, the base in which to interpret the input
|
||||
template<typename IteratorRangeToNumberTraits>
|
||||
class IteratorRangeToNumber {
|
||||
public:
|
||||
typedef IteratorRangeToNumberTraits traits;
|
||||
typedef typename traits::iterator_type const_iterator;
|
||||
typedef typename traits::value_type value_type;
|
||||
|
||||
// Generalized iterator-range-to-number conversion.
|
||||
//
|
||||
static bool Invoke(const_iterator begin,
|
||||
const_iterator end,
|
||||
value_type* output) {
|
||||
bool valid = true;
|
||||
|
||||
while (begin != end && LocalIsWhitespace(*begin)) {
|
||||
valid = false;
|
||||
++begin;
|
||||
}
|
||||
|
||||
if (begin != end && *begin == '-') {
|
||||
if (!std::numeric_limits<value_type>::is_signed) {
|
||||
valid = false;
|
||||
} else if (!Negative::Invoke(begin + 1, end, output)) {
|
||||
valid = false;
|
||||
}
|
||||
} else {
|
||||
if (begin != end && *begin == '+') {
|
||||
++begin;
|
||||
}
|
||||
if (!Positive::Invoke(begin, end, output)) {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
private:
|
||||
// Sign provides:
|
||||
// - a static function, CheckBounds, that determines whether the next digit
|
||||
// causes an overflow/underflow
|
||||
// - a static function, Increment, that appends the next digit appropriately
|
||||
// according to the sign of the number being parsed.
|
||||
template<typename Sign>
|
||||
class Base {
|
||||
public:
|
||||
static bool Invoke(const_iterator begin, const_iterator end,
|
||||
typename traits::value_type* output) {
|
||||
*output = 0;
|
||||
|
||||
if (begin == end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: no performance difference was found when using template
|
||||
// specialization to remove this check in bases other than 16
|
||||
if (traits::kBase == 16 && end - begin > 2 && *begin == '0' &&
|
||||
(*(begin + 1) == 'x' || *(begin + 1) == 'X')) {
|
||||
begin += 2;
|
||||
}
|
||||
|
||||
for (const_iterator current = begin; current != end; ++current) {
|
||||
uint8_t new_digit = 0;
|
||||
|
||||
if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current != begin) {
|
||||
if (!Sign::CheckBounds(output, new_digit)) {
|
||||
return false;
|
||||
}
|
||||
*output *= traits::kBase;
|
||||
}
|
||||
|
||||
Sign::Increment(new_digit, output);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class Positive : public Base<Positive> {
|
||||
public:
|
||||
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)) {
|
||||
*output = traits::max();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static void Increment(uint8_t increment, value_type* output) {
|
||||
*output += increment;
|
||||
}
|
||||
};
|
||||
|
||||
class Negative : public Base<Negative> {
|
||||
public:
|
||||
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)) {
|
||||
*output = traits::min();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static void Increment(uint8_t increment, value_type* output) {
|
||||
*output -= increment;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<typename ITERATOR, typename VALUE, int BASE>
|
||||
class BaseIteratorRangeToNumberTraits {
|
||||
public:
|
||||
typedef ITERATOR iterator_type;
|
||||
typedef VALUE value_type;
|
||||
static value_type min() {
|
||||
return std::numeric_limits<value_type>::min();
|
||||
}
|
||||
static value_type max() {
|
||||
return std::numeric_limits<value_type>::max();
|
||||
}
|
||||
static const int kBase = BASE;
|
||||
};
|
||||
|
||||
template<typename ITERATOR>
|
||||
class BaseHexIteratorRangeToIntTraits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
|
||||
};
|
||||
|
||||
template <typename ITERATOR>
|
||||
class BaseHexIteratorRangeToUIntTraits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, uint32_t, 16> {};
|
||||
|
||||
template <typename ITERATOR>
|
||||
class BaseHexIteratorRangeToInt64Traits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, int64_t, 16> {};
|
||||
|
||||
template <typename ITERATOR>
|
||||
class BaseHexIteratorRangeToUInt64Traits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, uint64_t, 16> {};
|
||||
|
||||
typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
|
||||
HexIteratorRangeToIntTraits;
|
||||
|
||||
typedef BaseHexIteratorRangeToUIntTraits<StringPiece::const_iterator>
|
||||
HexIteratorRangeToUIntTraits;
|
||||
|
||||
typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
|
||||
HexIteratorRangeToInt64Traits;
|
||||
|
||||
typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator>
|
||||
HexIteratorRangeToUInt64Traits;
|
||||
|
||||
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_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;
|
||||
output->push_back((msb << 4) | lsb);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename VALUE, int BASE>
|
||||
class StringPieceToNumberTraits
|
||||
: public BaseIteratorRangeToNumberTraits<StringPiece::const_iterator,
|
||||
VALUE,
|
||||
BASE> {
|
||||
};
|
||||
|
||||
template <typename VALUE>
|
||||
bool StringToIntImpl(const StringPiece& input, VALUE* output) {
|
||||
return IteratorRangeToNumber<StringPieceToNumberTraits<VALUE, 10> >::Invoke(
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
template <typename VALUE, int BASE>
|
||||
class StringPiece16ToNumberTraits
|
||||
: public BaseIteratorRangeToNumberTraits<StringPiece16::const_iterator,
|
||||
VALUE,
|
||||
BASE> {
|
||||
};
|
||||
|
||||
template <typename VALUE>
|
||||
bool String16ToIntImpl(const StringPiece16& input, VALUE* output) {
|
||||
return IteratorRangeToNumber<StringPiece16ToNumberTraits<VALUE, 10> >::Invoke(
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string IntToString(int value) {
|
||||
return IntToStringT<std::string, int>::IntToString(value);
|
||||
}
|
||||
|
||||
string16 IntToString16(int value) {
|
||||
return IntToStringT<string16, int>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string UintToString(unsigned int value) {
|
||||
return IntToStringT<std::string, unsigned int>::IntToString(value);
|
||||
}
|
||||
|
||||
string16 UintToString16(unsigned int value) {
|
||||
return IntToStringT<string16, unsigned int>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string Int64ToString(int64_t value) {
|
||||
return IntToStringT<std::string, int64_t>::IntToString(value);
|
||||
}
|
||||
|
||||
string16 Int64ToString16(int64_t value) {
|
||||
return IntToStringT<string16, int64_t>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string Uint64ToString(uint64_t value) {
|
||||
return IntToStringT<std::string, uint64_t>::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>::IntToString(value);
|
||||
}
|
||||
|
||||
string16 SizeTToString16(size_t value) {
|
||||
return IntToStringT<string16, size_t>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string DoubleToString(double value) {
|
||||
// According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
|
||||
char buffer[32];
|
||||
dmg_fp::g_fmt(buffer, value);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
bool StringToInt(const StringPiece& input, int* output) {
|
||||
return StringToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToInt(const StringPiece16& input, int* output) {
|
||||
return String16ToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToUint(const StringPiece& input, unsigned* output) {
|
||||
return StringToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToUint(const StringPiece16& input, unsigned* output) {
|
||||
return String16ToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToInt64(const StringPiece& input, int64_t* output) {
|
||||
return StringToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToInt64(const StringPiece16& input, int64_t* output) {
|
||||
return String16ToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToUint64(const StringPiece& input, uint64_t* output) {
|
||||
return StringToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToUint64(const StringPiece16& input, uint64_t* output) {
|
||||
return String16ToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToSizeT(const StringPiece& input, size_t* output) {
|
||||
return StringToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToSizeT(const StringPiece16& input, size_t* output) {
|
||||
return String16ToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToDouble(const std::string& input, double* output) {
|
||||
// Thread-safe? It is on at least Mac, Linux, and Windows.
|
||||
ScopedClearErrno clear_errno;
|
||||
|
||||
char* endptr = NULL;
|
||||
*output = dmg_fp::strtod(input.c_str(), &endptr);
|
||||
|
||||
// Cases to return false:
|
||||
// - If errno is ERANGE, there was an overflow or underflow.
|
||||
// - If the input string is empty, there was nothing to parse.
|
||||
// - If endptr does not point to the end of the string, there are either
|
||||
// characters remaining in the string after a parsed number, or the string
|
||||
// does not begin with a parseable number. endptr is compared to the
|
||||
// expected end given the string's stated length to correctly catch cases
|
||||
// where the string contains embedded NUL characters.
|
||||
// - If the first character is a space, there was leading whitespace
|
||||
return errno == 0 &&
|
||||
!input.empty() &&
|
||||
input.c_str() + input.length() == endptr &&
|
||||
!isspace(input[0]);
|
||||
}
|
||||
|
||||
// Note: if you need to add String16ToDouble, first ask yourself if it's
|
||||
// really necessary. If it is, probably the best implementation here is to
|
||||
// convert to 8-bit and then use the 8-bit version.
|
||||
|
||||
// Note: if you need to add an iterator range version of StringToDouble, first
|
||||
// ask yourself if it's really necessary. If it is, probably the best
|
||||
// implementation here is to instantiate a string and use the string version.
|
||||
|
||||
std::string HexEncode(const void* bytes, size_t size) {
|
||||
static const char kHexChars[] = "0123456789ABCDEF";
|
||||
|
||||
// Each input byte creates two output hex characters.
|
||||
std::string ret(size * 2, '\0');
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
char b = reinterpret_cast<const char*>(bytes)[i];
|
||||
ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
|
||||
ret[(i * 2) + 1] = kHexChars[b & 0xf];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool HexStringToInt(const StringPiece& input, int* output) {
|
||||
return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke(
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
bool HexStringToUInt(const StringPiece& input, uint32_t* output) {
|
||||
return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
bool HexStringToInt64(const StringPiece& input, int64_t* output) {
|
||||
return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
|
||||
input.begin(), input.end(), 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_t>* output) {
|
||||
return HexStringToBytesT(input, output);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
@@ -1,137 +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_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/strings/string16.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// IMPORTANT MESSAGE FROM YOUR SPONSOR
|
||||
//
|
||||
// This file contains no "wstring" variants. New code should use string16. If
|
||||
// you need to make old code work, use the UTF8 version and convert. Please do
|
||||
// not add wstring variants.
|
||||
//
|
||||
// Please do not add "convenience" functions for converting strings to integers
|
||||
// that return the value and ignore success/failure. That encourages people to
|
||||
// write code that doesn't properly handle the error conditions.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace base {
|
||||
|
||||
// Number -> string conversions ------------------------------------------------
|
||||
|
||||
BASE_EXPORT std::string IntToString(int value);
|
||||
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_t value);
|
||||
BASE_EXPORT string16 Int64ToString16(int64_t 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);
|
||||
|
||||
// DoubleToString converts the double to a string format that ignores the
|
||||
// locale. If you want to use locale specific formatting, use ICU.
|
||||
BASE_EXPORT std::string DoubleToString(double value);
|
||||
|
||||
// String -> number conversions ------------------------------------------------
|
||||
|
||||
// Perform a best-effort conversion of the input string to a numeric type,
|
||||
// setting |*output| to the result of the conversion. Returns true for
|
||||
// "perfect" conversions; returns false in the following cases:
|
||||
// - Overflow. |*output| will be set to the maximum value supported
|
||||
// by the data type.
|
||||
// - Underflow. |*output| will be set to the minimum value supported
|
||||
// by the data type.
|
||||
// - Trailing characters in the string after parsing the number. |*output|
|
||||
// will be set to the value of the number that was parsed.
|
||||
// - Leading whitespace in the string before parsing the number. |*output| will
|
||||
// be set to the value of the number that was parsed.
|
||||
// - 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_t* output);
|
||||
BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64_t* 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-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 ----------------------------------------------------------------
|
||||
|
||||
// Returns a hex string representation of a binary buffer. The returned hex
|
||||
// string will be in upper case. This function does not check if |size| is
|
||||
// within reasonable limits since it's written with trusted data in mind. If
|
||||
// you suspect that the data you want to format might be large, the absolute
|
||||
// max size for |size| should be is
|
||||
// std::numeric_limits<size_t>::max() / 2
|
||||
BASE_EXPORT std::string HexEncode(const void* bytes, size_t size);
|
||||
|
||||
// Best effort conversion, see StringToInt above for restrictions.
|
||||
// Will only successful parse hex values that will fit into |output|, i.e.
|
||||
// -0x80000000 < |input| < 0x7FFFFFFF.
|
||||
BASE_EXPORT bool HexStringToInt(const StringPiece& input, int* output);
|
||||
|
||||
// Best effort conversion, see StringToInt above for restrictions.
|
||||
// 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_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_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_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_t>* output);
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
|
||||
@@ -1,452 +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.
|
||||
// Copied from strings/stringpiece.cc with modifications
|
||||
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
namespace {
|
||||
|
||||
// For each character in characters_wanted, sets the index corresponding
|
||||
// to the ASCII code of that character to 1 in table. This is used by
|
||||
// the find_.*_of methods below to tell whether or not a character is in
|
||||
// the lookup table in constant time.
|
||||
// The argument `table' must be an array that is large enough to hold all
|
||||
// the possible values of an unsigned char. Thus it should be be declared
|
||||
// as follows:
|
||||
// bool table[UCHAR_MAX + 1]
|
||||
inline void BuildLookupTable(const StringPiece& characters_wanted,
|
||||
bool* table) {
|
||||
const size_t length = characters_wanted.length();
|
||||
const char* const data = characters_wanted.data();
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
table[static_cast<unsigned char>(data[i])] = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// MSVC doesn't like complex extern templates and DLLs.
|
||||
#if !defined(COMPILER_MSVC)
|
||||
template class BasicStringPiece<std::string>;
|
||||
template class BasicStringPiece<string16>;
|
||||
#endif
|
||||
|
||||
bool operator==(const StringPiece& x, const StringPiece& y) {
|
||||
if (x.size() != y.size())
|
||||
return false;
|
||||
|
||||
return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
|
||||
o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
|
||||
return o;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename STR>
|
||||
void CopyToStringT(const BasicStringPiece<STR>& self, STR* target) {
|
||||
if (self.empty())
|
||||
target->clear();
|
||||
else
|
||||
target->assign(self.data(), self.size());
|
||||
}
|
||||
|
||||
void CopyToString(const StringPiece& self, std::string* target) {
|
||||
CopyToStringT(self, target);
|
||||
}
|
||||
|
||||
void CopyToString(const StringPiece16& self, string16* target) {
|
||||
CopyToStringT(self, target);
|
||||
}
|
||||
|
||||
template<typename STR>
|
||||
void AppendToStringT(const BasicStringPiece<STR>& self, STR* target) {
|
||||
if (!self.empty())
|
||||
target->append(self.data(), self.size());
|
||||
}
|
||||
|
||||
void AppendToString(const StringPiece& self, std::string* target) {
|
||||
AppendToStringT(self, target);
|
||||
}
|
||||
|
||||
void AppendToString(const StringPiece16& self, string16* target) {
|
||||
AppendToStringT(self, target);
|
||||
}
|
||||
|
||||
template<typename STR>
|
||||
size_t copyT(const BasicStringPiece<STR>& self,
|
||||
typename STR::value_type* buf,
|
||||
size_t n,
|
||||
size_t pos) {
|
||||
size_t ret = std::min(self.size() - pos, n);
|
||||
memcpy(buf, self.data() + pos, ret * sizeof(typename STR::value_type));
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos) {
|
||||
return copyT(self, buf, n, pos);
|
||||
}
|
||||
|
||||
size_t copy(const StringPiece16& self, char16* buf, size_t n, size_t pos) {
|
||||
return copyT(self, buf, n, pos);
|
||||
}
|
||||
|
||||
template<typename STR>
|
||||
size_t findT(const BasicStringPiece<STR>& self,
|
||||
const BasicStringPiece<STR>& s,
|
||||
size_t pos) {
|
||||
if (pos > self.size())
|
||||
return BasicStringPiece<STR>::npos;
|
||||
|
||||
typename BasicStringPiece<STR>::const_iterator result =
|
||||
std::search(self.begin() + pos, self.end(), s.begin(), s.end());
|
||||
const size_t xpos =
|
||||
static_cast<size_t>(result - self.begin());
|
||||
return xpos + s.size() <= self.size() ? xpos : BasicStringPiece<STR>::npos;
|
||||
}
|
||||
|
||||
size_t find(const StringPiece& self, const StringPiece& s, size_t pos) {
|
||||
return findT(self, s, pos);
|
||||
}
|
||||
|
||||
size_t find(const StringPiece16& self, const StringPiece16& s, size_t pos) {
|
||||
return findT(self, s, pos);
|
||||
}
|
||||
|
||||
template<typename STR>
|
||||
size_t findT(const BasicStringPiece<STR>& self,
|
||||
typename STR::value_type c,
|
||||
size_t pos) {
|
||||
if (pos >= self.size())
|
||||
return BasicStringPiece<STR>::npos;
|
||||
|
||||
typename BasicStringPiece<STR>::const_iterator result =
|
||||
std::find(self.begin() + pos, self.end(), c);
|
||||
return result != self.end() ?
|
||||
static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
|
||||
}
|
||||
|
||||
size_t find(const StringPiece& self, char c, size_t pos) {
|
||||
return findT(self, c, pos);
|
||||
}
|
||||
|
||||
size_t find(const StringPiece16& self, char16 c, size_t pos) {
|
||||
return findT(self, c, pos);
|
||||
}
|
||||
|
||||
template<typename STR>
|
||||
size_t rfindT(const BasicStringPiece<STR>& self,
|
||||
const BasicStringPiece<STR>& s,
|
||||
size_t pos) {
|
||||
if (self.size() < s.size())
|
||||
return BasicStringPiece<STR>::npos;
|
||||
|
||||
if (s.empty())
|
||||
return std::min(self.size(), pos);
|
||||
|
||||
typename BasicStringPiece<STR>::const_iterator last =
|
||||
self.begin() + std::min(self.size() - s.size(), pos) + s.size();
|
||||
typename BasicStringPiece<STR>::const_iterator result =
|
||||
std::find_end(self.begin(), last, s.begin(), s.end());
|
||||
return result != last ?
|
||||
static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
|
||||
}
|
||||
|
||||
size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos) {
|
||||
return rfindT(self, s, pos);
|
||||
}
|
||||
|
||||
size_t rfind(const StringPiece16& self, const StringPiece16& s, size_t pos) {
|
||||
return rfindT(self, s, pos);
|
||||
}
|
||||
|
||||
template<typename STR>
|
||||
size_t rfindT(const BasicStringPiece<STR>& self,
|
||||
typename STR::value_type c,
|
||||
size_t pos) {
|
||||
if (self.size() == 0)
|
||||
return BasicStringPiece<STR>::npos;
|
||||
|
||||
for (size_t i = std::min(pos, self.size() - 1); ;
|
||||
--i) {
|
||||
if (self.data()[i] == c)
|
||||
return i;
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
return BasicStringPiece<STR>::npos;
|
||||
}
|
||||
|
||||
size_t rfind(const StringPiece& self, char c, size_t pos) {
|
||||
return rfindT(self, c, pos);
|
||||
}
|
||||
|
||||
size_t rfind(const StringPiece16& self, char16 c, size_t pos) {
|
||||
return rfindT(self, c, pos);
|
||||
}
|
||||
|
||||
// 8-bit version using lookup table.
|
||||
size_t find_first_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
size_t pos) {
|
||||
if (self.size() == 0 || s.size() == 0)
|
||||
return StringPiece::npos;
|
||||
|
||||
// Avoid the cost of BuildLookupTable() for a single-character search.
|
||||
if (s.size() == 1)
|
||||
return find(self, s.data()[0], pos);
|
||||
|
||||
bool lookup[UCHAR_MAX + 1] = { false };
|
||||
BuildLookupTable(s, lookup);
|
||||
for (size_t i = pos; i < self.size(); ++i) {
|
||||
if (lookup[static_cast<unsigned char>(self.data()[i])]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return StringPiece::npos;
|
||||
}
|
||||
|
||||
// 16-bit brute force version.
|
||||
size_t find_first_of(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos) {
|
||||
StringPiece16::const_iterator found =
|
||||
std::find_first_of(self.begin() + pos, self.end(), s.begin(), s.end());
|
||||
if (found == self.end())
|
||||
return StringPiece16::npos;
|
||||
return found - self.begin();
|
||||
}
|
||||
|
||||
// 8-bit version using lookup table.
|
||||
size_t find_first_not_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
size_t pos) {
|
||||
if (self.size() == 0)
|
||||
return StringPiece::npos;
|
||||
|
||||
if (s.size() == 0)
|
||||
return 0;
|
||||
|
||||
// Avoid the cost of BuildLookupTable() for a single-character search.
|
||||
if (s.size() == 1)
|
||||
return find_first_not_of(self, s.data()[0], pos);
|
||||
|
||||
bool lookup[UCHAR_MAX + 1] = { false };
|
||||
BuildLookupTable(s, lookup);
|
||||
for (size_t i = pos; i < self.size(); ++i) {
|
||||
if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return StringPiece::npos;
|
||||
}
|
||||
|
||||
// 16-bit brute-force version.
|
||||
BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos) {
|
||||
if (self.size() == 0)
|
||||
return StringPiece16::npos;
|
||||
|
||||
for (size_t self_i = pos; self_i < self.size(); ++self_i) {
|
||||
bool found = false;
|
||||
for (size_t s_i = 0; s_i < s.size(); ++s_i) {
|
||||
if (self[self_i] == s[s_i]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return self_i;
|
||||
}
|
||||
return StringPiece16::npos;
|
||||
}
|
||||
|
||||
template<typename STR>
|
||||
size_t find_first_not_ofT(const BasicStringPiece<STR>& self,
|
||||
typename STR::value_type c,
|
||||
size_t pos) {
|
||||
if (self.size() == 0)
|
||||
return BasicStringPiece<STR>::npos;
|
||||
|
||||
for (; pos < self.size(); ++pos) {
|
||||
if (self.data()[pos] != c) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
return BasicStringPiece<STR>::npos;
|
||||
}
|
||||
|
||||
size_t find_first_not_of(const StringPiece& self,
|
||||
char c,
|
||||
size_t pos) {
|
||||
return find_first_not_ofT(self, c, pos);
|
||||
}
|
||||
|
||||
size_t find_first_not_of(const StringPiece16& self,
|
||||
char16 c,
|
||||
size_t pos) {
|
||||
return find_first_not_ofT(self, c, pos);
|
||||
}
|
||||
|
||||
// 8-bit version using lookup table.
|
||||
size_t find_last_of(const StringPiece& self, const StringPiece& s, size_t pos) {
|
||||
if (self.size() == 0 || s.size() == 0)
|
||||
return StringPiece::npos;
|
||||
|
||||
// Avoid the cost of BuildLookupTable() for a single-character search.
|
||||
if (s.size() == 1)
|
||||
return rfind(self, s.data()[0], pos);
|
||||
|
||||
bool lookup[UCHAR_MAX + 1] = { false };
|
||||
BuildLookupTable(s, lookup);
|
||||
for (size_t i = std::min(pos, self.size() - 1); ; --i) {
|
||||
if (lookup[static_cast<unsigned char>(self.data()[i])])
|
||||
return i;
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
return StringPiece::npos;
|
||||
}
|
||||
|
||||
// 16-bit brute-force version.
|
||||
size_t find_last_of(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos) {
|
||||
if (self.size() == 0)
|
||||
return StringPiece16::npos;
|
||||
|
||||
for (size_t self_i = std::min(pos, self.size() - 1); ;
|
||||
--self_i) {
|
||||
for (size_t s_i = 0; s_i < s.size(); s_i++) {
|
||||
if (self.data()[self_i] == s[s_i])
|
||||
return self_i;
|
||||
}
|
||||
if (self_i == 0)
|
||||
break;
|
||||
}
|
||||
return StringPiece16::npos;
|
||||
}
|
||||
|
||||
// 8-bit version using lookup table.
|
||||
size_t find_last_not_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
size_t pos) {
|
||||
if (self.size() == 0)
|
||||
return StringPiece::npos;
|
||||
|
||||
size_t i = std::min(pos, self.size() - 1);
|
||||
if (s.size() == 0)
|
||||
return i;
|
||||
|
||||
// Avoid the cost of BuildLookupTable() for a single-character search.
|
||||
if (s.size() == 1)
|
||||
return find_last_not_of(self, s.data()[0], pos);
|
||||
|
||||
bool lookup[UCHAR_MAX + 1] = { false };
|
||||
BuildLookupTable(s, lookup);
|
||||
for (; ; --i) {
|
||||
if (!lookup[static_cast<unsigned char>(self.data()[i])])
|
||||
return i;
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
return StringPiece::npos;
|
||||
}
|
||||
|
||||
// 16-bit brute-force version.
|
||||
size_t find_last_not_of(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos) {
|
||||
if (self.size() == 0)
|
||||
return StringPiece::npos;
|
||||
|
||||
for (size_t self_i = std::min(pos, self.size() - 1); ; --self_i) {
|
||||
bool found = false;
|
||||
for (size_t s_i = 0; s_i < s.size(); s_i++) {
|
||||
if (self.data()[self_i] == s[s_i]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return self_i;
|
||||
if (self_i == 0)
|
||||
break;
|
||||
}
|
||||
return StringPiece16::npos;
|
||||
}
|
||||
|
||||
template<typename STR>
|
||||
size_t find_last_not_ofT(const BasicStringPiece<STR>& self,
|
||||
typename STR::value_type c,
|
||||
size_t pos) {
|
||||
if (self.size() == 0)
|
||||
return BasicStringPiece<STR>::npos;
|
||||
|
||||
for (size_t i = std::min(pos, self.size() - 1); ; --i) {
|
||||
if (self.data()[i] != c)
|
||||
return i;
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
return BasicStringPiece<STR>::npos;
|
||||
}
|
||||
|
||||
size_t find_last_not_of(const StringPiece& self,
|
||||
char c,
|
||||
size_t pos) {
|
||||
return find_last_not_ofT(self, c, pos);
|
||||
}
|
||||
|
||||
size_t find_last_not_of(const StringPiece16& self,
|
||||
char16 c,
|
||||
size_t pos) {
|
||||
return find_last_not_ofT(self, c, pos);
|
||||
}
|
||||
|
||||
template<typename STR>
|
||||
BasicStringPiece<STR> substrT(const BasicStringPiece<STR>& self,
|
||||
size_t pos,
|
||||
size_t n) {
|
||||
if (pos > self.size()) pos = self.size();
|
||||
if (n > self.size() - pos) n = self.size() - pos;
|
||||
return BasicStringPiece<STR>(self.data() + pos, n);
|
||||
}
|
||||
|
||||
StringPiece substr(const StringPiece& self,
|
||||
size_t pos,
|
||||
size_t n) {
|
||||
return substrT(self, pos, n);
|
||||
}
|
||||
|
||||
StringPiece16 substr(const StringPiece16& self,
|
||||
size_t pos,
|
||||
size_t n) {
|
||||
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
|
||||
@@ -1,469 +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.
|
||||
// Copied from strings/stringpiece.h with modifications
|
||||
//
|
||||
// A string-like object that points to a sized piece of memory.
|
||||
//
|
||||
// You can use StringPiece as a function or method parameter. A StringPiece
|
||||
// parameter can receive a double-quoted string literal argument, a "const
|
||||
// char*" argument, a string argument, or a StringPiece argument with no data
|
||||
// copying. Systematic use of StringPiece for arguments reduces data
|
||||
// copies and strlen() calls.
|
||||
//
|
||||
// Prefer passing StringPieces by value:
|
||||
// void MyFunction(StringPiece arg);
|
||||
// If circumstances require, you may also pass by const reference:
|
||||
// void MyFunction(const StringPiece& arg); // not preferred
|
||||
// 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.
|
||||
|
||||
#ifndef BASE_STRINGS_STRING_PIECE_H_
|
||||
#define BASE_STRINGS_STRING_PIECE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename STRING_TYPE> class BasicStringPiece;
|
||||
typedef BasicStringPiece<std::string> StringPiece;
|
||||
typedef BasicStringPiece<string16> StringPiece16;
|
||||
|
||||
// internal --------------------------------------------------------------------
|
||||
|
||||
// Many of the StringPiece functions use different implementations for the
|
||||
// 8-bit and 16-bit versions, and we don't want lots of template expansions in
|
||||
// this (very common) header that will slow down compilation.
|
||||
//
|
||||
// So here we define overloaded functions called by the StringPiece template.
|
||||
// For those that share an implementation, the two versions will expand to a
|
||||
// template internal to the .cc file.
|
||||
namespace internal {
|
||||
|
||||
BASE_EXPORT void CopyToString(const StringPiece& self, std::string* target);
|
||||
BASE_EXPORT void CopyToString(const StringPiece16& self, string16* target);
|
||||
|
||||
BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target);
|
||||
BASE_EXPORT void AppendToString(const StringPiece16& self, string16* target);
|
||||
|
||||
BASE_EXPORT size_t copy(const StringPiece& self,
|
||||
char* buf,
|
||||
size_t n,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t copy(const StringPiece16& self,
|
||||
char16* buf,
|
||||
size_t n,
|
||||
size_t pos);
|
||||
|
||||
BASE_EXPORT size_t find(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find(const StringPiece& self,
|
||||
char c,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find(const StringPiece16& self,
|
||||
char16 c,
|
||||
size_t pos);
|
||||
|
||||
BASE_EXPORT size_t rfind(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t rfind(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t rfind(const StringPiece& self,
|
||||
char c,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t rfind(const StringPiece16& self,
|
||||
char16 c,
|
||||
size_t pos);
|
||||
|
||||
BASE_EXPORT size_t find_first_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_first_of(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos);
|
||||
|
||||
BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
|
||||
char c,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
|
||||
char16 c,
|
||||
size_t pos);
|
||||
|
||||
BASE_EXPORT size_t find_last_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_last_of(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_last_of(const StringPiece& self,
|
||||
char c,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_last_of(const StringPiece16& self,
|
||||
char16 c,
|
||||
size_t pos);
|
||||
|
||||
BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
|
||||
const StringPiece16& s,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
|
||||
char16 c,
|
||||
size_t pos);
|
||||
BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
|
||||
char c,
|
||||
size_t pos);
|
||||
|
||||
BASE_EXPORT StringPiece substr(const StringPiece& self,
|
||||
size_t pos,
|
||||
size_t n);
|
||||
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 ------------------------------------------------------------
|
||||
|
||||
// Defines the types, methods, operators, and data members common to both
|
||||
// StringPiece and StringPiece16. Do not refer to this class directly, but
|
||||
// rather to BasicStringPiece, StringPiece, or StringPiece16.
|
||||
//
|
||||
// This is templatized by string class type rather than character type, so
|
||||
// BasicStringPiece<std::string> or BasicStringPiece<base::string16>.
|
||||
template <typename STRING_TYPE> class BasicStringPiece {
|
||||
public:
|
||||
// Standard STL container boilerplate.
|
||||
typedef size_t size_type;
|
||||
typedef typename STRING_TYPE::value_type value_type;
|
||||
typedef const value_type* pointer;
|
||||
typedef const value_type& reference;
|
||||
typedef const value_type& const_reference;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef const value_type* const_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
static const size_type npos;
|
||||
|
||||
public:
|
||||
// We provide non-explicit singleton constructors so users can pass
|
||||
// in a "const char*" or a "string" wherever a "StringPiece" is
|
||||
// expected (likewise for char16, string16, StringPiece16).
|
||||
BasicStringPiece() : ptr_(NULL), length_(0) {}
|
||||
BasicStringPiece(const value_type* str)
|
||||
: ptr_(str),
|
||||
length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {}
|
||||
BasicStringPiece(const STRING_TYPE& str)
|
||||
: ptr_(str.data()), length_(str.size()) {}
|
||||
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) {
|
||||
#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
|
||||
// typically a mistake to pass data() to a routine that expects a NUL
|
||||
// terminated string.
|
||||
const value_type* data() const { return ptr_; }
|
||||
size_type size() const { return length_; }
|
||||
size_type length() const { return length_; }
|
||||
bool empty() const { return length_ == 0; }
|
||||
|
||||
void clear() {
|
||||
ptr_ = NULL;
|
||||
length_ = 0;
|
||||
}
|
||||
void set(const value_type* data, size_type len) {
|
||||
ptr_ = data;
|
||||
length_ = len;
|
||||
}
|
||||
void set(const value_type* str) {
|
||||
ptr_ = str;
|
||||
length_ = str ? STRING_TYPE::traits_type::length(str) : 0;
|
||||
}
|
||||
|
||||
value_type operator[](size_type i) const { return ptr_[i]; }
|
||||
|
||||
void remove_prefix(size_type n) {
|
||||
ptr_ += n;
|
||||
length_ -= n;
|
||||
}
|
||||
|
||||
void remove_suffix(size_type n) {
|
||||
length_ -= n;
|
||||
}
|
||||
|
||||
int compare(const BasicStringPiece<STRING_TYPE>& x) const {
|
||||
int r = wordmemcmp(
|
||||
ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_));
|
||||
if (r == 0) {
|
||||
if (length_ < x.length_) r = -1;
|
||||
else if (length_ > x.length_) r = +1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
STRING_TYPE as_string() const {
|
||||
// std::string doesn't like to take a NULL pointer even with a 0 size.
|
||||
return empty() ? STRING_TYPE() : STRING_TYPE(data(), size());
|
||||
}
|
||||
|
||||
const_iterator begin() const { return ptr_; }
|
||||
const_iterator end() const { return ptr_ + length_; }
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(ptr_ + length_);
|
||||
}
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(ptr_);
|
||||
}
|
||||
|
||||
size_type max_size() const { return length_; }
|
||||
size_type capacity() const { return length_; }
|
||||
|
||||
static int wordmemcmp(const value_type* p,
|
||||
const value_type* p2,
|
||||
size_type N) {
|
||||
return STRING_TYPE::traits_type::compare(p, p2, N);
|
||||
}
|
||||
|
||||
// Sets the value of the given string target type to be the current string.
|
||||
// This saves a temporary over doing |a = b.as_string()|
|
||||
void CopyToString(STRING_TYPE* target) const {
|
||||
internal::CopyToString(*this, target);
|
||||
}
|
||||
|
||||
void AppendToString(STRING_TYPE* target) const {
|
||||
internal::AppendToString(*this, target);
|
||||
}
|
||||
|
||||
size_type copy(value_type* buf, size_type n, size_type pos = 0) const {
|
||||
return internal::copy(*this, buf, n, pos);
|
||||
}
|
||||
|
||||
// Does "this" start with "x"
|
||||
bool starts_with(const BasicStringPiece& x) const {
|
||||
return ((this->length_ >= x.length_) &&
|
||||
(wordmemcmp(this->ptr_, x.ptr_, x.length_) == 0));
|
||||
}
|
||||
|
||||
// Does "this" end with "x"
|
||||
bool ends_with(const BasicStringPiece& x) const {
|
||||
return ((this->length_ >= x.length_) &&
|
||||
(wordmemcmp(this->ptr_ + (this->length_-x.length_),
|
||||
x.ptr_, x.length_) == 0));
|
||||
}
|
||||
|
||||
// find: Search for a character or substring at a given offset.
|
||||
size_type find(const BasicStringPiece<STRING_TYPE>& s,
|
||||
size_type pos = 0) const {
|
||||
return internal::find(*this, s, pos);
|
||||
}
|
||||
size_type find(value_type c, size_type pos = 0) const {
|
||||
return internal::find(*this, c, pos);
|
||||
}
|
||||
|
||||
// rfind: Reverse find.
|
||||
size_type rfind(const BasicStringPiece& s,
|
||||
size_type pos = BasicStringPiece::npos) const {
|
||||
return internal::rfind(*this, s, pos);
|
||||
}
|
||||
size_type rfind(value_type c, size_type pos = BasicStringPiece::npos) const {
|
||||
return internal::rfind(*this, c, pos);
|
||||
}
|
||||
|
||||
// find_first_of: Find the first occurence of one of a set of characters.
|
||||
size_type find_first_of(const BasicStringPiece& s,
|
||||
size_type pos = 0) const {
|
||||
return internal::find_first_of(*this, s, pos);
|
||||
}
|
||||
size_type find_first_of(value_type c, size_type pos = 0) const {
|
||||
return find(c, pos);
|
||||
}
|
||||
|
||||
// find_first_not_of: Find the first occurence not of a set of characters.
|
||||
size_type find_first_not_of(const BasicStringPiece& s,
|
||||
size_type pos = 0) const {
|
||||
return internal::find_first_not_of(*this, s, pos);
|
||||
}
|
||||
size_type find_first_not_of(value_type c, size_type pos = 0) const {
|
||||
return internal::find_first_not_of(*this, c, pos);
|
||||
}
|
||||
|
||||
// find_last_of: Find the last occurence of one of a set of characters.
|
||||
size_type find_last_of(const BasicStringPiece& s,
|
||||
size_type pos = BasicStringPiece::npos) const {
|
||||
return internal::find_last_of(*this, s, pos);
|
||||
}
|
||||
size_type find_last_of(value_type c,
|
||||
size_type pos = BasicStringPiece::npos) const {
|
||||
return rfind(c, pos);
|
||||
}
|
||||
|
||||
// find_last_not_of: Find the last occurence not of a set of characters.
|
||||
size_type find_last_not_of(const BasicStringPiece& s,
|
||||
size_type pos = BasicStringPiece::npos) const {
|
||||
return internal::find_last_not_of(*this, s, pos);
|
||||
}
|
||||
size_type find_last_not_of(value_type c,
|
||||
size_type pos = BasicStringPiece::npos) const {
|
||||
return internal::find_last_not_of(*this, c, pos);
|
||||
}
|
||||
|
||||
// substr.
|
||||
BasicStringPiece substr(size_type pos,
|
||||
size_type n = BasicStringPiece::npos) const {
|
||||
return internal::substr(*this, pos, n);
|
||||
}
|
||||
|
||||
protected:
|
||||
const value_type* ptr_;
|
||||
size_type length_;
|
||||
};
|
||||
|
||||
template <typename STRING_TYPE>
|
||||
const typename BasicStringPiece<STRING_TYPE>::size_type
|
||||
BasicStringPiece<STRING_TYPE>::npos =
|
||||
typename BasicStringPiece<STRING_TYPE>::size_type(-1);
|
||||
|
||||
// MSVC doesn't like complex extern templates and DLLs.
|
||||
#if !defined(COMPILER_MSVC)
|
||||
extern template class BASE_EXPORT BasicStringPiece<std::string>;
|
||||
extern template class BASE_EXPORT BasicStringPiece<string16>;
|
||||
#endif
|
||||
|
||||
// StingPiece operators --------------------------------------------------------
|
||||
|
||||
BASE_EXPORT bool operator==(const StringPiece& x, const StringPiece& y);
|
||||
|
||||
inline bool operator!=(const StringPiece& x, const StringPiece& y) {
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
inline bool operator<(const StringPiece& x, const StringPiece& y) {
|
||||
const int r = StringPiece::wordmemcmp(
|
||||
x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
|
||||
return ((r < 0) || ((r == 0) && (x.size() < y.size())));
|
||||
}
|
||||
|
||||
inline bool operator>(const StringPiece& x, const StringPiece& y) {
|
||||
return y < x;
|
||||
}
|
||||
|
||||
inline bool operator<=(const StringPiece& x, const StringPiece& y) {
|
||||
return !(x > y);
|
||||
}
|
||||
|
||||
inline bool operator>=(const StringPiece& x, const StringPiece& y) {
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
// StringPiece16 operators -----------------------------------------------------
|
||||
|
||||
inline bool operator==(const StringPiece16& x, const StringPiece16& y) {
|
||||
if (x.size() != y.size())
|
||||
return false;
|
||||
|
||||
return StringPiece16::wordmemcmp(x.data(), y.data(), x.size()) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const StringPiece16& x, const StringPiece16& y) {
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
inline bool operator<(const StringPiece16& x, const StringPiece16& y) {
|
||||
const int r = StringPiece16::wordmemcmp(
|
||||
x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
|
||||
return ((r < 0) || ((r == 0) && (x.size() < y.size())));
|
||||
}
|
||||
|
||||
inline bool operator>(const StringPiece16& x, const StringPiece16& y) {
|
||||
return y < x;
|
||||
}
|
||||
|
||||
inline bool operator<=(const StringPiece16& x, const StringPiece16& y) {
|
||||
return !(x > y);
|
||||
}
|
||||
|
||||
inline bool operator>=(const StringPiece16& x, const StringPiece16& y) {
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
BASE_EXPORT std::ostream& operator<<(std::ostream& o,
|
||||
const StringPiece& piece);
|
||||
|
||||
} // namespace base
|
||||
|
||||
// Hashing ---------------------------------------------------------------------
|
||||
|
||||
// We provide appropriate hash functions so StringPiece and StringPiece16 can
|
||||
// be used as keys in hash sets and maps.
|
||||
|
||||
// This hash function is copied from base/containers/hash_tables.h. We don't
|
||||
// use the ones already defined for string and string16 directly because it
|
||||
// would require the string constructors to be called, which we don't want.
|
||||
#define HASH_STRING_PIECE(StringPieceType, string_piece) \
|
||||
std::size_t result = 0; \
|
||||
for (StringPieceType::const_iterator i = string_piece.begin(); \
|
||||
i != string_piece.end(); ++i) \
|
||||
result = (result * 131) + *i; \
|
||||
return result; \
|
||||
|
||||
namespace BASE_HASH_NAMESPACE {
|
||||
|
||||
template<>
|
||||
struct hash<base::StringPiece> {
|
||||
std::size_t operator()(const base::StringPiece& sp) const {
|
||||
HASH_STRING_PIECE(base::StringPiece, sp);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct hash<base::StringPiece16> {
|
||||
std::size_t operator()(const base::StringPiece16& sp16) const {
|
||||
HASH_STRING_PIECE(base::StringPiece16, sp16);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace BASE_HASH_NAMESPACE
|
||||
|
||||
#endif // BASE_STRINGS_STRING_PIECE_H_
|
||||
@@ -1,264 +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.
|
||||
|
||||
#include "base/strings/string_split.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/third_party/icu/icu_utf.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// 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 = input.find_first_of(delimiter);
|
||||
if (end_key_pos == std::string::npos) {
|
||||
DVLOG(1) << "cannot find delimiter in: " << input;
|
||||
return false; // No delimiter.
|
||||
}
|
||||
input.substr(0, end_key_pos).CopyToString(&result_pair.first);
|
||||
|
||||
// Find the value string.
|
||||
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.
|
||||
}
|
||||
remains.substr(begin_value_pos, remains.size() - begin_value_pos)
|
||||
.CopyToString(&result_pair.second);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
result->clear();
|
||||
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);
|
||||
|
||||
if (whitespace == TRIM_WHITESPACE)
|
||||
term = TrimString(term, WhitespaceForType<Str>(), TRIM_ALL);
|
||||
|
||||
if (result_type == SPLIT_WANT_ALL || !term.empty())
|
||||
result->push_back(PieceToOutputType<Str, OutputStringType>(term));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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<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 (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;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void SplitStringUsingSubstr(StringPiece16 input,
|
||||
StringPiece16 delimiter,
|
||||
std::vector<string16>* result) {
|
||||
SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
|
||||
result);
|
||||
}
|
||||
|
||||
void SplitStringUsingSubstr(StringPiece input,
|
||||
StringPiece delimiter,
|
||||
std::vector<std::string>* 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
|
||||
@@ -1,129 +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_STRINGS_STRING_SPLIT_H_
|
||||
#define BASE_STRINGS_STRING_SPLIT_H_
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
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.
|
||||
//
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
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(StringPiece input,
|
||||
char key_value_delimiter,
|
||||
char key_value_pair_delimiter,
|
||||
StringPairs* key_value_pairs);
|
||||
|
||||
// Similar to SplitString, but use a substring delimiter instead of a list of
|
||||
// characters that are all possible delimiters.
|
||||
//
|
||||
// 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 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
@@ -1,461 +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 defines utility functions for working with strings.
|
||||
|
||||
#ifndef BASE_STRINGS_STRING_UTIL_H_
|
||||
#define BASE_STRINGS_STRING_UTIL_H_
|
||||
|
||||
#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/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 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
|
||||
// string, even when truncation occurs.
|
||||
int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments)
|
||||
PRINTF_FORMAT(3, 0);
|
||||
|
||||
// Some of these implementations need to be inlined.
|
||||
|
||||
// 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,
|
||||
_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);
|
||||
va_end(arguments);
|
||||
return result;
|
||||
}
|
||||
|
||||
// BSD-style safe and consistent string copy functions.
|
||||
// Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|.
|
||||
// Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as
|
||||
// long as |dst_size| is not 0. Returns the length of |src| in characters.
|
||||
// If the return value is >= dst_size, then the output was truncated.
|
||||
// NOTE: All sizes are in number of characters, NOT in bytes.
|
||||
BASE_EXPORT size_t strlcpy(char* dst, const char* src, size_t dst_size);
|
||||
BASE_EXPORT size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size);
|
||||
|
||||
// Scan a wprintf format string to determine whether it's portable across a
|
||||
// variety of systems. This function only checks that the conversion
|
||||
// specifiers used by the format string are supported and have the same meaning
|
||||
// on a variety of systems. It doesn't check for other errors that might occur
|
||||
// within a format string.
|
||||
//
|
||||
// Nonportable conversion specifiers for wprintf are:
|
||||
// - 's' and 'c' without an 'l' length modifier. %s and %c operate on char
|
||||
// data on all systems except Windows, which treat them as wchar_t data.
|
||||
// Use %ls and %lc for wchar_t data instead.
|
||||
// - 'S' and 'C', which operate on wchar_t data on all systems except Windows,
|
||||
// which treat them as char data. Use %ls and %lc for wchar_t data
|
||||
// instead.
|
||||
// - 'F', which is not identified by Windows wprintf documentation.
|
||||
// - 'D', 'O', and 'U', which are deprecated and not available on all systems.
|
||||
// Use %ld, %lo, and %lu instead.
|
||||
//
|
||||
// Note that there is no portable conversion specifier for char data when
|
||||
// working with wprintf.
|
||||
//
|
||||
// This function is intended to be called from base::vswprintf.
|
||||
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.
|
||||
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.
|
||||
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;
|
||||
}
|
||||
|
||||
// Converts the given string to it's ASCII-lowercase equivalent.
|
||||
BASE_EXPORT std::string ToLowerASCII(StringPiece str);
|
||||
BASE_EXPORT string16 ToLowerASCII(StringPiece16 str);
|
||||
|
||||
// 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 {
|
||||
return ToLowerASCII(x) == ToLowerASCII(y);
|
||||
}
|
||||
};
|
||||
|
||||
// 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.
|
||||
//
|
||||
// It is likely faster to construct a new empty string object (just a few
|
||||
// instructions to set the length to 0) than to get the empty string singleton
|
||||
// returned by these functions (which requires threadsafe singleton access).
|
||||
//
|
||||
// Therefore, DO NOT USE THESE AS A GENERAL-PURPOSE SUBSTITUTE FOR DEFAULT
|
||||
// CONSTRUCTORS. There is only one case where you should use these: functions
|
||||
// which need to return a string by reference (e.g. as a class member
|
||||
// accessor), and don't have an empty string to use (e.g. in an error case).
|
||||
// These should not be used as initializers, function arguments, or return
|
||||
// values for functions which return by value or outparam.
|
||||
BASE_EXPORT const std::string& EmptyString();
|
||||
BASE_EXPORT const string16& EmptyString16();
|
||||
|
||||
// Contains the set of characters representing whitespace in the corresponding
|
||||
// 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[];
|
||||
|
||||
// Removes characters in |remove_chars| from anywhere in |input|. Returns true
|
||||
// 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 StringPiece16& remove_chars,
|
||||
string16* output);
|
||||
BASE_EXPORT bool RemoveChars(const std::string& input,
|
||||
const StringPiece& remove_chars,
|
||||
std::string* output);
|
||||
|
||||
// Replaces characters in |replace_chars| from anywhere in |input| with
|
||||
// |replace_with|. Each character in |replace_chars| will be replaced with
|
||||
// the |replace_with| string. Returns true if any characters were replaced.
|
||||
// |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 StringPiece16& replace_chars,
|
||||
const string16& replace_with,
|
||||
string16* output);
|
||||
BASE_EXPORT bool ReplaceChars(const std::string& input,
|
||||
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|.
|
||||
// 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,
|
||||
StringPiece16 trim_chars,
|
||||
string16* output);
|
||||
BASE_EXPORT bool TrimString(const std::string& input,
|
||||
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.
|
||||
//
|
||||
// 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.
|
||||
BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
|
||||
TrimPositions positions,
|
||||
string16* output);
|
||||
BASE_EXPORT StringPiece16 TrimWhitespace(StringPiece16 input,
|
||||
TrimPositions positions);
|
||||
BASE_EXPORT TrimPositions TrimWhitespaceASCII(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
|
||||
// copied from terminals.
|
||||
// Returns |text|, with the following three transformations:
|
||||
// (1) Leading and trailing whitespace is trimmed.
|
||||
// (2) If |trim_sequences_with_line_breaks| is true, any other whitespace
|
||||
// sequences containing a CR or LF are trimmed.
|
||||
// (3) All other whitespace sequences are converted to single spaces.
|
||||
BASE_EXPORT string16 CollapseWhitespace(
|
||||
const string16& text,
|
||||
bool trim_sequences_with_line_breaks);
|
||||
BASE_EXPORT std::string CollapseWhitespaceASCII(
|
||||
const std::string& text,
|
||||
bool trim_sequences_with_line_breaks);
|
||||
|
||||
// Returns true if |input| is empty or contains only characters found in
|
||||
// |characters|.
|
||||
BASE_EXPORT bool ContainsOnlyChars(const StringPiece& input,
|
||||
const StringPiece& characters);
|
||||
BASE_EXPORT bool ContainsOnlyChars(const StringPiece16& input,
|
||||
const StringPiece16& characters);
|
||||
|
||||
// Returns true if the specified string matches the criteria. How can a wide
|
||||
// string be 8-bit or UTF8? It contains only characters that are < 256 (in the
|
||||
// first case) or characters that use only 8-bits and whose 8-bit
|
||||
// representation looks like a UTF-8 string (the second case).
|
||||
//
|
||||
// Note that IsStringUTF8 checks not only if the input is structurally
|
||||
// valid but also if it doesn't contain any non-character codepoint
|
||||
// (e.g. U+FFFE). It's done on purpose because all the existing callers want
|
||||
// to have the maximum 'discriminating' power from other encodings. If
|
||||
// there's a use case for just checking the structural validity, we have to
|
||||
// add a new function for that.
|
||||
//
|
||||
// IsStringASCII assumes the input is likely all ASCII, and does not leave early
|
||||
// if it is not the case.
|
||||
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
|
||||
// StringPieces directly.
|
||||
BASE_EXPORT bool IsStringASCII(const string16& str);
|
||||
#if defined(WCHAR_T_IS_UTF32)
|
||||
BASE_EXPORT bool IsStringASCII(const std::wstring& str);
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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).
|
||||
template <typename Char>
|
||||
inline bool IsAsciiWhitespace(Char c) {
|
||||
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
|
||||
}
|
||||
template <typename Char>
|
||||
inline bool IsAsciiAlpha(Char c) {
|
||||
return ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
|
||||
}
|
||||
template <typename Char>
|
||||
inline bool IsAsciiDigit(Char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline bool IsHexDigit(Char c) {
|
||||
return (c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'F') ||
|
||||
(c >= 'a' && c <= 'f');
|
||||
}
|
||||
|
||||
// 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 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 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,
|
||||
StringPiece16 find_this,
|
||||
StringPiece16 replace_with);
|
||||
BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
|
||||
std::string* str,
|
||||
size_t start_offset,
|
||||
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|.
|
||||
//
|
||||
// This does entire substrings; use std::replace in <algorithm> for single
|
||||
// characters, for example:
|
||||
// std::replace(str.begin(), str.end(), 'a', 'b');
|
||||
BASE_EXPORT void ReplaceSubstringsAfterOffset(
|
||||
string16* str,
|
||||
size_t start_offset,
|
||||
StringPiece16 find_this,
|
||||
StringPiece16 replace_with);
|
||||
BASE_EXPORT void ReplaceSubstringsAfterOffset(
|
||||
std::string* str,
|
||||
size_t start_offset,
|
||||
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
|
||||
// pointer to the underlying contiguous array of characters. This is typically
|
||||
// used when calling a function that writes results into a character array, but
|
||||
// the caller wants the data to be managed by a string-like object. It is
|
||||
// convenient in that is can be used inline in the call, and fast in that it
|
||||
// avoids copying the results of the call from a char* into a string.
|
||||
//
|
||||
// |length_with_null| must be at least 2, since otherwise the underlying string
|
||||
// would have size 0, and trying to access &((*str)[0]) in that case can result
|
||||
// in a number of problems.
|
||||
//
|
||||
// Internally, this takes linear time because the resize() call 0-fills the
|
||||
// underlying array for potentially all
|
||||
// (|length_with_null - 1| * sizeof(string_type::value_type)) bytes. Ideally we
|
||||
// could avoid this aspect of the resize() call, as we expect the caller to
|
||||
// immediately write over this memory, but there is no other way to set the size
|
||||
// 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).
|
||||
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 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 string16 ReplaceStringPlaceholders(
|
||||
const string16& format_string,
|
||||
const std::vector<string16>& subst,
|
||||
std::vector<size_t>* offsets);
|
||||
|
||||
BASE_EXPORT std::string ReplaceStringPlaceholders(
|
||||
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 string16 ReplaceStringPlaceholders(const string16& format_string,
|
||||
const string16& a,
|
||||
size_t* offset);
|
||||
|
||||
} // 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
|
||||
|
||||
#endif // BASE_STRINGS_STRING_UTIL_H_
|
||||
@@ -1,67 +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.
|
||||
|
||||
#include "base/strings/string_util.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
#define WHITESPACE_UNICODE \
|
||||
0x0009, /* CHARACTER TABULATION */ \
|
||||
0x000A, /* LINE FEED (LF) */ \
|
||||
0x000B, /* LINE TABULATION */ \
|
||||
0x000C, /* FORM FEED (FF) */ \
|
||||
0x000D, /* CARRIAGE RETURN (CR) */ \
|
||||
0x0020, /* SPACE */ \
|
||||
0x0085, /* NEXT LINE (NEL) */ \
|
||||
0x00A0, /* NO-BREAK SPACE */ \
|
||||
0x1680, /* OGHAM SPACE MARK */ \
|
||||
0x2000, /* EN QUAD */ \
|
||||
0x2001, /* EM QUAD */ \
|
||||
0x2002, /* EN SPACE */ \
|
||||
0x2003, /* EM SPACE */ \
|
||||
0x2004, /* THREE-PER-EM SPACE */ \
|
||||
0x2005, /* FOUR-PER-EM SPACE */ \
|
||||
0x2006, /* SIX-PER-EM SPACE */ \
|
||||
0x2007, /* FIGURE SPACE */ \
|
||||
0x2008, /* PUNCTUATION SPACE */ \
|
||||
0x2009, /* THIN SPACE */ \
|
||||
0x200A, /* HAIR SPACE */ \
|
||||
0x2028, /* LINE SEPARATOR */ \
|
||||
0x2029, /* PARAGRAPH SEPARATOR */ \
|
||||
0x202F, /* NARROW NO-BREAK SPACE */ \
|
||||
0x205F, /* MEDIUM MATHEMATICAL SPACE */ \
|
||||
0x3000, /* IDEOGRAPHIC SPACE */ \
|
||||
0
|
||||
|
||||
const wchar_t kWhitespaceWide[] = {
|
||||
WHITESPACE_UNICODE
|
||||
};
|
||||
|
||||
const char16 kWhitespaceUTF16[] = {
|
||||
WHITESPACE_UNICODE
|
||||
};
|
||||
|
||||
const char kWhitespaceASCII[] = {
|
||||
0x09, // CHARACTER TABULATION
|
||||
0x0A, // LINE FEED (LF)
|
||||
0x0B, // LINE TABULATION
|
||||
0x0C, // FORM FEED (FF)
|
||||
0x0D, // CARRIAGE RETURN (CR)
|
||||
0x20, // SPACE
|
||||
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
|
||||
@@ -1,37 +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.
|
||||
|
||||
#ifndef BASE_STRINGS_STRING_UTIL_POSIX_H_
|
||||
#define BASE_STRINGS_STRING_UTIL_POSIX_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Chromium code style is to not use malloc'd strings; this is only for use
|
||||
// for interaction with APIs that require it.
|
||||
inline char* strdup(const char* str) {
|
||||
return ::strdup(str);
|
||||
}
|
||||
|
||||
inline int vsnprintf(char* buffer, size_t size,
|
||||
const char* format, va_list arguments) {
|
||||
return ::vsnprintf(buffer, size, format, arguments);
|
||||
}
|
||||
|
||||
inline int vswprintf(wchar_t* buffer, size_t size,
|
||||
const wchar_t* format, va_list arguments) {
|
||||
DCHECK(IsWprintfFormatPortable(format));
|
||||
return ::vswprintf(buffer, size, format, arguments);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STRINGS_STRING_UTIL_POSIX_H_
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user