зеркало из https://github.com/mozilla/gecko-dev.git
Bug 922756 - Initial import of subset of Chromium sandbox. r=aklotz
This commit is contained in:
Родитель
de45bd4422
Коммит
52aea6cfef
|
@ -0,0 +1,82 @@
|
|||
// 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
|
|
@ -0,0 +1,76 @@
|
|||
// 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/basictypes.h"
|
||||
#include "base/callback.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_
|
|
@ -0,0 +1,80 @@
|
|||
// 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.
|
||||
//
|
||||
// The implementation includes annotations to avoid some false positives
|
||||
// when using data race detection tools.
|
||||
|
||||
#ifndef BASE_ATOMIC_REF_COUNT_H_
|
||||
#define BASE_ATOMIC_REF_COUNT_H_
|
||||
|
||||
#include "base/atomicops.h"
|
||||
#include "base/third_party/dynamic_annotations/dynamic_annotations.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) {
|
||||
ANNOTATE_HAPPENS_BEFORE(ptr);
|
||||
bool res = (subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0);
|
||||
if (!res) {
|
||||
ANNOTATE_HAPPENS_AFTER(ptr);
|
||||
}
|
||||
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);
|
||||
if (res) {
|
||||
ANNOTATE_HAPPENS_AFTER(ptr);
|
||||
}
|
||||
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);
|
||||
if (res) {
|
||||
ANNOTATE_HAPPENS_AFTER(ptr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMIC_REF_COUNT_H_
|
|
@ -0,0 +1,60 @@
|
|||
// 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/basictypes.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_
|
|
@ -0,0 +1,164 @@
|
|||
// 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 "base/basictypes.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 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 base::subtle
|
||||
} // namespace base
|
||||
|
||||
// Include our platform specific implementation.
|
||||
#if defined(THREAD_SANITIZER)
|
||||
#include "base/atomicops_internals_tsan.h"
|
||||
#elif defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
|
||||
#include "base/atomicops_internals_x86_msvc.h"
|
||||
#elif defined(OS_MACOSX)
|
||||
#include "base/atomicops_internals_mac.h"
|
||||
#elif defined(OS_NACL)
|
||||
#include "base/atomicops_internals_gcc.h"
|
||||
#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY)
|
||||
#include "base/atomicops_internals_arm_gcc.h"
|
||||
#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
|
||||
#include "base/atomicops_internals_x86_gcc.h"
|
||||
#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY)
|
||||
#include "base/atomicops_internals_mips_gcc.h"
|
||||
#else
|
||||
#error "Atomic operations are not supported on your platform"
|
||||
#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_
|
|
@ -0,0 +1,378 @@
|
|||
// 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 is an internal atomic implementation for compiler-based
|
||||
// ThreadSanitizer. Use base/atomicops.h instead.
|
||||
|
||||
#ifndef BASE_ATOMICOPS_INTERNALS_TSAN_H_
|
||||
#define BASE_ATOMICOPS_INTERNALS_TSAN_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
// This struct is not part of the public API of this module; clients may not
|
||||
// use it. (However, it's exported via BASE_EXPORT because clients implicitly
|
||||
// do use it at link time by inlining these functions.)
|
||||
// Features of this x86. Values may not be correct before main() is run,
|
||||
// but are set conservatively.
|
||||
struct AtomicOps_x86CPUFeatureStruct {
|
||||
bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
|
||||
// after acquire compare-and-swap.
|
||||
bool has_sse2; // Processor has SSE2.
|
||||
};
|
||||
BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
|
||||
AtomicOps_Internalx86CPUFeatures;
|
||||
|
||||
#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
#ifndef TSAN_INTERFACE_ATOMIC_H
|
||||
#define TSAN_INTERFACE_ATOMIC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef char __tsan_atomic8;
|
||||
typedef short __tsan_atomic16; // NOLINT
|
||||
typedef int __tsan_atomic32;
|
||||
typedef long __tsan_atomic64; // NOLINT
|
||||
|
||||
#if defined(__SIZEOF_INT128__) \
|
||||
|| (__clang_major__ * 100 + __clang_minor__ >= 302)
|
||||
typedef __int128 __tsan_atomic128;
|
||||
#define __TSAN_HAS_INT128 1
|
||||
#else
|
||||
typedef char __tsan_atomic128;
|
||||
#define __TSAN_HAS_INT128 0
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
__tsan_memory_order_relaxed,
|
||||
__tsan_memory_order_consume,
|
||||
__tsan_memory_order_acquire,
|
||||
__tsan_memory_order_release,
|
||||
__tsan_memory_order_acq_rel,
|
||||
__tsan_memory_order_seq_cst,
|
||||
} __tsan_memory_order;
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a,
|
||||
__tsan_memory_order mo);
|
||||
|
||||
void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v,
|
||||
__tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 v, __tsan_memory_order mo);
|
||||
|
||||
int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
|
||||
int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
|
||||
__tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
|
||||
__tsan_memory_order fail_mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
|
||||
volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
|
||||
volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
|
||||
volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
|
||||
volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
|
||||
volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
|
||||
__tsan_memory_order mo, __tsan_memory_order fail_mo);
|
||||
|
||||
void __tsan_atomic_thread_fence(__tsan_memory_order mo);
|
||||
void __tsan_atomic_signal_fence(__tsan_memory_order mo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // #ifndef TSAN_INTERFACE_ATOMIC_H
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 cmp = old_value;
|
||||
__tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
|
||||
__tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
|
||||
Atomic32 new_value) {
|
||||
return __tsan_atomic32_exchange(ptr, new_value,
|
||||
__tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
|
||||
Atomic32 new_value) {
|
||||
return __tsan_atomic32_exchange(ptr, new_value,
|
||||
__tsan_memory_order_acquire);
|
||||
}
|
||||
|
||||
inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
|
||||
Atomic32 new_value) {
|
||||
return __tsan_atomic32_exchange(ptr, new_value,
|
||||
__tsan_memory_order_release);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
|
||||
Atomic32 increment) {
|
||||
return increment + __tsan_atomic32_fetch_add(ptr, increment,
|
||||
__tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
|
||||
Atomic32 increment) {
|
||||
return increment + __tsan_atomic32_fetch_add(ptr, increment,
|
||||
__tsan_memory_order_acq_rel);
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 cmp = old_value;
|
||||
__tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
|
||||
__tsan_memory_order_acquire, __tsan_memory_order_acquire);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 cmp = old_value;
|
||||
__tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
|
||||
__tsan_memory_order_release, __tsan_memory_order_relaxed);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
|
||||
__tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
|
||||
__tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
|
||||
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
|
||||
__tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
|
||||
return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
|
||||
return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
|
||||
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
|
||||
return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 cmp = old_value;
|
||||
__tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
|
||||
__tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
|
||||
Atomic64 new_value) {
|
||||
return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
|
||||
Atomic64 new_value) {
|
||||
return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire);
|
||||
}
|
||||
|
||||
inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
|
||||
Atomic64 new_value) {
|
||||
return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release);
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
|
||||
Atomic64 increment) {
|
||||
return increment + __tsan_atomic64_fetch_add(ptr, increment,
|
||||
__tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
|
||||
Atomic64 increment) {
|
||||
return increment + __tsan_atomic64_fetch_add(ptr, increment,
|
||||
__tsan_memory_order_acq_rel);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
|
||||
__tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
|
||||
__tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
|
||||
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
|
||||
__tsan_atomic64_store(ptr, value, __tsan_memory_order_release);
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
|
||||
return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
|
||||
return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire);
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
|
||||
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
|
||||
return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 cmp = old_value;
|
||||
__tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
|
||||
__tsan_memory_order_acquire, __tsan_memory_order_acquire);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 cmp = old_value;
|
||||
__tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
|
||||
__tsan_memory_order_release, __tsan_memory_order_relaxed);
|
||||
return cmp;
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
__tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
|
||||
}
|
||||
|
||||
} // namespace base::subtle
|
||||
} // namespace base
|
||||
|
||||
#undef ATOMICOPS_COMPILER_BARRIER
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_TSAN_H_
|
|
@ -0,0 +1,269 @@
|
|||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file is an internal atomic implementation, use base/atomicops.h instead.
|
||||
|
||||
#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|
||||
#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
// This struct is not part of the public API of this module; clients may not
|
||||
// use it. (However, it's exported via BASE_EXPORT because clients implicitly
|
||||
// do use it at link time by inlining these functions.)
|
||||
// Features of this x86. Values may not be correct before main() is run,
|
||||
// but are set conservatively.
|
||||
struct AtomicOps_x86CPUFeatureStruct {
|
||||
bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
|
||||
// after acquire compare-and-swap.
|
||||
bool has_sse2; // Processor has SSE2.
|
||||
};
|
||||
BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
|
||||
AtomicOps_Internalx86CPUFeatures;
|
||||
|
||||
#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
// 32-bit low-level operations on any platform.
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev;
|
||||
__asm__ __volatile__("lock; cmpxchgl %1,%2"
|
||||
: "=a" (prev)
|
||||
: "q" (new_value), "m" (*ptr), "0" (old_value)
|
||||
: "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
__asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg.
|
||||
: "=r" (new_value)
|
||||
: "m" (*ptr), "0" (new_value)
|
||||
: "memory");
|
||||
return new_value; // Now it's the previous value.
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddl %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now holds the old value of *ptr
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddl %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now holds the old value of *ptr
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
// 64-bit implementations of memory barrier can be simpler, because it
|
||||
// "mfence" is guaranteed to exist.
|
||||
inline void MemoryBarrier() {
|
||||
__asm__ __volatile__("mfence" : : : "memory");
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
|
||||
__asm__ __volatile__("mfence" : : : "memory");
|
||||
} else { // mfence is faster but not present on PIII
|
||||
Atomic32 x = 0;
|
||||
NoBarrier_AtomicExchange(&x, 0); // acts as a barrier on PIII
|
||||
}
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
|
||||
*ptr = value;
|
||||
__asm__ __volatile__("mfence" : : : "memory");
|
||||
} else {
|
||||
NoBarrier_AtomicExchange(ptr, value);
|
||||
// acts as a barrier on PIII
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
*ptr = value; // An x86 store acts as a release barrier.
|
||||
// See comments in Atomic64 version of Release_Store(), below.
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
|
||||
// See comments in Atomic64 version of Release_Store(), below.
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
// 64-bit low-level operations on 64-bit platform.
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 prev;
|
||||
__asm__ __volatile__("lock; cmpxchgq %1,%2"
|
||||
: "=a" (prev)
|
||||
: "q" (new_value), "m" (*ptr), "0" (old_value)
|
||||
: "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
|
||||
Atomic64 new_value) {
|
||||
__asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg.
|
||||
: "=r" (new_value)
|
||||
: "m" (*ptr), "0" (new_value)
|
||||
: "memory");
|
||||
return new_value; // Now it's the previous value.
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
Atomic64 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddq %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now contains the previous value of *ptr
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
Atomic64 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddq %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now contains the previous value of *ptr
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
|
||||
*ptr = value; // An x86 store acts as a release barrier
|
||||
// for current AMD/Intel chips as of Jan 2008.
|
||||
// See also Acquire_Load(), below.
|
||||
|
||||
// When new chips come out, check:
|
||||
// IA-32 Intel Architecture Software Developer's Manual, Volume 3:
|
||||
// System Programming Guide, Chatper 7: Multiple-processor management,
|
||||
// Section 7.2, Memory Ordering.
|
||||
// Last seen at:
|
||||
// http://developer.intel.com/design/pentium4/manuals/index_new.htm
|
||||
//
|
||||
// x86 stores/loads fail to act as barriers for a few instructions (clflush
|
||||
// maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
|
||||
// not generated by the compiler, and are rare. Users of these instructions
|
||||
// need to know about cache behaviour in any case since all of these involve
|
||||
// either flushing cache lines or non-temporal cache hints.
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
|
||||
// for current AMD/Intel chips as of Jan 2008.
|
||||
// See also Release_Store(), above.
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
#endif // defined(__x86_64__)
|
||||
|
||||
} // namespace base::subtle
|
||||
} // namespace base
|
||||
|
||||
#undef ATOMICOPS_COMPILER_BARRIER
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|
|
@ -0,0 +1,194 @@
|
|||
// 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>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
|
||||
#error "We require at least vs2005 for MemoryBarrier"
|
||||
#endif
|
||||
inline void MemoryBarrier() {
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
// See #undef and note at the top of this file.
|
||||
__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.
|
||||
|
||||
COMPILE_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 base::subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
|
|
@ -0,0 +1,34 @@
|
|||
// 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)
|
||||
#define BASE_EXPORT_PRIVATE __declspec(dllexport)
|
||||
#else
|
||||
#define BASE_EXPORT __declspec(dllimport)
|
||||
#define BASE_EXPORT_PRIVATE __declspec(dllimport)
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
|
||||
#else // defined(WIN32)
|
||||
#if defined(BASE_IMPLEMENTATION)
|
||||
#define BASE_EXPORT __attribute__((visibility("default")))
|
||||
#define BASE_EXPORT_PRIVATE __attribute__((visibility("default")))
|
||||
#else
|
||||
#define BASE_EXPORT
|
||||
#define BASE_EXPORT_PRIVATE
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
#endif
|
||||
|
||||
#else // defined(COMPONENT_BUILD)
|
||||
#define BASE_EXPORT
|
||||
#define BASE_EXPORT_PRIVATE
|
||||
#endif
|
||||
|
||||
#endif // BASE_BASE_EXPORT_H_
|
|
@ -0,0 +1,47 @@
|
|||
// 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.
|
||||
|
||||
#include "base/base_paths.h"
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/path_service.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
bool PathProvider(int key, FilePath* result) {
|
||||
// NOTE: DIR_CURRENT is a special case in PathService::Get
|
||||
|
||||
FilePath cur;
|
||||
switch (key) {
|
||||
case DIR_EXE:
|
||||
PathService::Get(FILE_EXE, &cur);
|
||||
cur = cur.DirName();
|
||||
break;
|
||||
case DIR_MODULE:
|
||||
PathService::Get(FILE_MODULE, &cur);
|
||||
cur = cur.DirName();
|
||||
break;
|
||||
case DIR_TEMP:
|
||||
if (!file_util::GetTempDir(&cur))
|
||||
return false;
|
||||
break;
|
||||
case DIR_TEST_DATA:
|
||||
if (!PathService::Get(DIR_SOURCE_ROOT, &cur))
|
||||
return false;
|
||||
cur = cur.Append(FILE_PATH_LITERAL("base"));
|
||||
cur = cur.Append(FILE_PATH_LITERAL("test"));
|
||||
cur = cur.Append(FILE_PATH_LITERAL("data"));
|
||||
if (!base::PathExists(cur)) // We don't want to create this.
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -0,0 +1,51 @@
|
|||
// 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.
|
||||
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_
|
|
@ -0,0 +1,208 @@
|
|||
// 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 <windows.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include "base/base_paths.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/win/scoped_co_mem.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
||||
// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
using base::FilePath;
|
||||
|
||||
namespace {
|
||||
|
||||
bool GetQuickLaunchPath(bool default_user, FilePath* result) {
|
||||
if (default_user) {
|
||||
wchar_t system_buffer[MAX_PATH];
|
||||
system_buffer[0] = 0;
|
||||
// As per MSDN, passing -1 for |hToken| indicates the Default user:
|
||||
// http://msdn.microsoft.com/library/windows/desktop/bb762181.aspx
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA,
|
||||
reinterpret_cast<HANDLE>(-1), SHGFP_TYPE_CURRENT,
|
||||
system_buffer))) {
|
||||
return false;
|
||||
}
|
||||
*result = FilePath(system_buffer);
|
||||
} else if (!PathService::Get(base::DIR_APP_DATA, result)) {
|
||||
// For the current user, grab the APPDATA directory directly from the
|
||||
// PathService cache.
|
||||
return false;
|
||||
}
|
||||
// According to various sources, appending
|
||||
// "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only
|
||||
// reliable way to get the quick launch folder across all versions of Windows.
|
||||
// http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick-
|
||||
// http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx
|
||||
*result = result->AppendASCII("Microsoft");
|
||||
*result = result->AppendASCII("Internet Explorer");
|
||||
*result = result->AppendASCII("Quick Launch");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace base {
|
||||
|
||||
bool PathProviderWin(int key, FilePath* result) {
|
||||
// We need to go compute the value. It would be nice to support paths with
|
||||
// names longer than MAX_PATH, but the system functions don't seem to be
|
||||
// designed for it either, with the exception of GetTempPath (but other
|
||||
// things will surely break if the temp path is too long, so we don't bother
|
||||
// handling it.
|
||||
wchar_t system_buffer[MAX_PATH];
|
||||
system_buffer[0] = 0;
|
||||
|
||||
FilePath cur;
|
||||
switch (key) {
|
||||
case base::FILE_EXE:
|
||||
GetModuleFileName(NULL, system_buffer, MAX_PATH);
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::FILE_MODULE: {
|
||||
// the resource containing module is assumed to be the one that
|
||||
// this code lives in, whether that's a dll or exe
|
||||
HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
|
||||
GetModuleFileName(this_module, system_buffer, MAX_PATH);
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
}
|
||||
case base::DIR_WINDOWS:
|
||||
GetWindowsDirectory(system_buffer, MAX_PATH);
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_SYSTEM:
|
||||
GetSystemDirectory(system_buffer, MAX_PATH);
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_PROGRAM_FILESX86:
|
||||
if (base::win::OSInfo::GetInstance()->architecture() !=
|
||||
base::win::OSInfo::X86_ARCHITECTURE) {
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
}
|
||||
// Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine.
|
||||
case base::DIR_PROGRAM_FILES:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_IE_INTERNET_CACHE:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_COMMON_START_MENU:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_START_MENU:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_APP_DATA:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
|
||||
system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_COMMON_APP_DATA:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_PROFILE:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT,
|
||||
system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_LOCAL_APP_DATA_LOW:
|
||||
if (win::GetVersion() < win::VERSION_VISTA)
|
||||
return false;
|
||||
|
||||
// TODO(nsylvain): We should use SHGetKnownFolderPath instead. Bug 1281128
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
|
||||
system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer).DirName().AppendASCII("LocalLow");
|
||||
break;
|
||||
case base::DIR_LOCAL_APP_DATA:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer)))
|
||||
return false;
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_SOURCE_ROOT: {
|
||||
FilePath executableDir;
|
||||
// On Windows, unit tests execute two levels deep from the source root.
|
||||
// For example: chrome/{Debug|Release}/ui_tests.exe
|
||||
PathService::Get(base::DIR_EXE, &executableDir);
|
||||
cur = executableDir.DirName().DirName();
|
||||
break;
|
||||
}
|
||||
case base::DIR_APP_SHORTCUTS: {
|
||||
if (win::GetVersion() < win::VERSION_WIN8)
|
||||
return false;
|
||||
|
||||
base::win::ScopedCoMem<wchar_t> path_buf;
|
||||
if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL,
|
||||
&path_buf)))
|
||||
return false;
|
||||
|
||||
cur = FilePath(string16(path_buf));
|
||||
break;
|
||||
}
|
||||
case base::DIR_USER_DESKTOP:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer))) {
|
||||
return false;
|
||||
}
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_COMMON_DESKTOP:
|
||||
if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL,
|
||||
SHGFP_TYPE_CURRENT, system_buffer))) {
|
||||
return false;
|
||||
}
|
||||
cur = FilePath(system_buffer);
|
||||
break;
|
||||
case base::DIR_USER_QUICK_LAUNCH:
|
||||
if (!GetQuickLaunchPath(false, &cur))
|
||||
return false;
|
||||
break;
|
||||
case base::DIR_DEFAULT_USER_QUICK_LAUNCH:
|
||||
if (!GetQuickLaunchPath(true, &cur))
|
||||
return false;
|
||||
break;
|
||||
case base::DIR_TASKBAR_PINS:
|
||||
if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur))
|
||||
return false;
|
||||
cur = cur.AppendASCII("User Pinned");
|
||||
cur = cur.AppendASCII("TaskBar");
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -0,0 +1,51 @@
|
|||
// 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"
|
||||
DIR_PROGRAM_FILES, // Usually c:\program files
|
||||
DIR_PROGRAM_FILESX86, // Usually c:\program files or c:\program files (x86)
|
||||
|
||||
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_PROFILE, // Usually "C:\Documents and settings\<user>.
|
||||
DIR_LOCAL_APP_DATA_LOW, // Local AppData directory for low integrity level.
|
||||
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_DEFAULT_USER_QUICK_LAUNCH, // Directory for the quick launch shortcuts
|
||||
// of the Default user.
|
||||
DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar via
|
||||
// base::win::TaskbarPinShortcutLink().
|
||||
|
||||
PATH_WIN_END
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BASE_PATHS_WIN_H__
|
|
@ -0,0 +1,60 @@
|
|||
// 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"
|
||||
|
||||
namespace switches {
|
||||
|
||||
// If the program includes base/debug/debug_on_start_win.h, the process will
|
||||
// (on Windows only) start the JIT system-registered debugger on itself and
|
||||
// will wait for 60 seconds for the debugger to attach to itself. Then a break
|
||||
// point will be hit.
|
||||
const char kDebugOnStart[] = "debug-on-start";
|
||||
|
||||
// Disables the crash reporting.
|
||||
const char kDisableBreakpad[] = "disable-breakpad";
|
||||
|
||||
// Enable DCHECKs in release mode.
|
||||
const char kEnableDCHECK[] = "enable-dcheck";
|
||||
|
||||
// Generates full memory crash dump.
|
||||
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
|
||||
|
||||
// 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 a pretty-printed version of tracing info to the console.
|
||||
const char kTraceToConsole[] = "trace-to-console";
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// A flag, generated internally for renderer and other helper process command
|
||||
// lines on Linux and Mac. It tells the helper process to enable crash dumping
|
||||
// and reporting, because helpers cannot access the files needed to make this
|
||||
// decision.
|
||||
const char kEnableCrashReporter[] = "enable-crash-reporter";
|
||||
#endif
|
||||
|
||||
} // namespace switches
|
|
@ -0,0 +1,31 @@
|
|||
// 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 kDebugOnStart[];
|
||||
extern const char kDisableBreakpad[];
|
||||
extern const char kEnableDCHECK[];
|
||||
extern const char kFullMemoryCrashReport[];
|
||||
extern const char kNoErrorDialogs[];
|
||||
extern const char kTestChildProcess[];
|
||||
extern const char kV[];
|
||||
extern const char kVModule[];
|
||||
extern const char kWaitForDebugger[];
|
||||
extern const char kTraceToConsole[];
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
extern const char kEnableCrashReporter[];
|
||||
#endif
|
||||
|
||||
} // namespace switches
|
||||
|
||||
#endif // BASE_BASE_SWITCHES_H_
|
|
@ -0,0 +1,369 @@
|
|||
// 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_BASICTYPES_H_
|
||||
#define BASE_BASICTYPES_H_
|
||||
|
||||
#include <limits.h> // So we can set the bounds of our types
|
||||
#include <stddef.h> // For size_t
|
||||
#include <string.h> // for memcpy
|
||||
|
||||
#include "base/port.h" // Types that only need exist on certain systems
|
||||
|
||||
#ifndef COMPILER_MSVC
|
||||
// stdint.h is part of C99 but MSVC doesn't have it.
|
||||
#include <stdint.h> // For intptr_t.
|
||||
#endif
|
||||
|
||||
typedef signed char schar;
|
||||
typedef signed char int8;
|
||||
typedef short int16;
|
||||
typedef int int32;
|
||||
|
||||
// The NSPR system headers define 64-bit as |long| when possible, except on
|
||||
// Mac OS X. In order to not have typedef mismatches, we do the same on LP64.
|
||||
//
|
||||
// On Mac OS X, |long long| is used for 64-bit types for compatibility with
|
||||
// <inttypes.h> format macros even in the LP64 model.
|
||||
#if defined(__LP64__) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
|
||||
typedef long int64;
|
||||
#else
|
||||
typedef long long int64;
|
||||
#endif
|
||||
|
||||
// NOTE: It is DANGEROUS to compare signed with unsigned types in loop
|
||||
// conditions and other conditional expressions, and it is DANGEROUS to
|
||||
// compute object/allocation sizes, indices, and offsets with signed types.
|
||||
// Integer overflow behavior for signed types is UNDEFINED in the C/C++
|
||||
// standards, but is defined for unsigned types.
|
||||
//
|
||||
// Use the unsigned types if your variable represents a bit pattern (e.g. a
|
||||
// hash value), object or allocation size, object count, offset,
|
||||
// array/vector index, etc.
|
||||
//
|
||||
// Do NOT use 'unsigned' to express "this value should always be positive";
|
||||
// use assertions for this.
|
||||
//
|
||||
// See the Chromium style guide for more information.
|
||||
// https://sites.google.com/a/chromium.org/dev/developers/coding-style
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
// See the comment above about NSPR and 64-bit.
|
||||
#if defined(__LP64__) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
|
||||
typedef unsigned long uint64;
|
||||
#else
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
|
||||
// A type to represent a Unicode code-point value. As of Unicode 4.0,
|
||||
// such values require up to 21 bits.
|
||||
// (For type-checking on pointers, make this explicitly signed,
|
||||
// and it should always be the signed version of whatever int32 is.)
|
||||
typedef signed int char32;
|
||||
|
||||
const uint8 kuint8max = (( uint8) 0xFF);
|
||||
const uint16 kuint16max = ((uint16) 0xFFFF);
|
||||
const uint32 kuint32max = ((uint32) 0xFFFFFFFF);
|
||||
const uint64 kuint64max = ((uint64) GG_LONGLONG(0xFFFFFFFFFFFFFFFF));
|
||||
const int8 kint8min = (( int8) 0x80);
|
||||
const int8 kint8max = (( int8) 0x7F);
|
||||
const int16 kint16min = (( int16) 0x8000);
|
||||
const int16 kint16max = (( int16) 0x7FFF);
|
||||
const int32 kint32min = (( int32) 0x80000000);
|
||||
const int32 kint32max = (( int32) 0x7FFFFFFF);
|
||||
const int64 kint64min = (( int64) GG_LONGLONG(0x8000000000000000));
|
||||
const int64 kint64max = (( int64) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
|
||||
|
||||
// Put this in the private: declarations for a class to be uncopyable.
|
||||
#define DISALLOW_COPY(TypeName) \
|
||||
TypeName(const TypeName&)
|
||||
|
||||
// Put this in the private: declarations for a class to be unassignable.
|
||||
#define DISALLOW_ASSIGN(TypeName) \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
// 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&)
|
||||
|
||||
// An older, deprecated, politically incorrect name for the above.
|
||||
// NOTE: The usage of this macro was banned from our code base, but some
|
||||
// third_party libraries are yet using it.
|
||||
// TODO(tfarina): Figure out how to fix the usage of this macro in the
|
||||
// third_party libraries and get rid of it.
|
||||
#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName)
|
||||
|
||||
// A macro to disallow all the implicit constructors, namely the
|
||||
// default constructor, copy constructor and operator= functions.
|
||||
//
|
||||
// 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(); \
|
||||
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.
|
||||
//
|
||||
// One caveat is that arraysize() doesn't accept any array of an
|
||||
// anonymous type or a type defined inside a function. In these rare
|
||||
// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is
|
||||
// due to a limitation in C++'s template system. The limitation might
|
||||
// eventually be removed, but it hasn't happened yet.
|
||||
|
||||
// This template function declaration is used in defining arraysize.
|
||||
// Note that the function doesn't need an implementation, as we only
|
||||
// use its type.
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||
|
||||
// That gcc wants both of these prototypes seems mysterious. VC, for
|
||||
// its part, can't decide which to use (another mystery). Matching of
|
||||
// template overloads: the final frontier.
|
||||
#ifndef _MSC_VER
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(const T (&array)[N]))[N];
|
||||
#endif
|
||||
|
||||
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
|
||||
|
||||
// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
|
||||
// but can be used on anonymous types or types defined inside
|
||||
// functions. It's less safe than arraysize as it accepts some
|
||||
// (although not all) pointers. Therefore, you should use arraysize
|
||||
// whenever possible.
|
||||
//
|
||||
// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
|
||||
// size_t.
|
||||
//
|
||||
// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error
|
||||
//
|
||||
// "warning: division by zero in ..."
|
||||
//
|
||||
// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
|
||||
// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
|
||||
//
|
||||
// The following comments are on the implementation details, and can
|
||||
// be ignored by the users.
|
||||
//
|
||||
// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
|
||||
// the array) and sizeof(*(arr)) (the # of bytes in one array
|
||||
// element). If the former is divisible by the latter, perhaps arr is
|
||||
// indeed an array, in which case the division result is the # of
|
||||
// elements in the array. Otherwise, arr cannot possibly be an array,
|
||||
// and we generate a compiler error to prevent the code from
|
||||
// compiling.
|
||||
//
|
||||
// Since the size of bool is implementation-defined, we need to cast
|
||||
// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
|
||||
// result has type size_t.
|
||||
//
|
||||
// This macro is not perfect as it wrongfully accepts certain
|
||||
// pointers, namely where the pointer size is divisible by the pointee
|
||||
// size. Since all our code has to go through a 32-bit compiler,
|
||||
// where a pointer is 4 bytes, this means all pointers to a type whose
|
||||
// size is 3 or greater than 4 will be (righteously) rejected.
|
||||
|
||||
#define ARRAYSIZE_UNSAFE(a) \
|
||||
((sizeof(a) / sizeof(*(a))) / \
|
||||
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
|
||||
|
||||
|
||||
// Use implicit_cast as a safe version of static_cast or const_cast
|
||||
// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
|
||||
// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
|
||||
// a const pointer to Foo).
|
||||
// When you use implicit_cast, the compiler checks that the cast is safe.
|
||||
// Such explicit implicit_casts are necessary in surprisingly many
|
||||
// situations where C++ demands an exact type match instead of an
|
||||
// argument type convertible to a target type.
|
||||
//
|
||||
// The From type can be inferred, so the preferred syntax for using
|
||||
// implicit_cast is the same as for static_cast etc.:
|
||||
//
|
||||
// implicit_cast<ToType>(expr)
|
||||
//
|
||||
// implicit_cast would have been part of the C++ standard library,
|
||||
// but the proposal was submitted too late. It will probably make
|
||||
// its way into the language in the future.
|
||||
template<typename To, typename From>
|
||||
inline To implicit_cast(From const &f) {
|
||||
return f;
|
||||
}
|
||||
|
||||
// The COMPILE_ASSERT macro can be used to verify that a compile time
|
||||
// expression is true. For example, you could use it to verify the
|
||||
// size of a static array:
|
||||
//
|
||||
// COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES,
|
||||
// content_type_names_incorrect_size);
|
||||
//
|
||||
// or to make sure a struct is smaller than a certain size:
|
||||
//
|
||||
// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
|
||||
//
|
||||
// The second argument to the macro is the name of the variable. If
|
||||
// the expression is false, most compilers will issue a warning/error
|
||||
// containing the name of the variable.
|
||||
|
||||
template <bool>
|
||||
struct CompileAssert {
|
||||
};
|
||||
|
||||
#undef COMPILE_ASSERT
|
||||
#define COMPILE_ASSERT(expr, msg) \
|
||||
typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
|
||||
|
||||
// Implementation details of COMPILE_ASSERT:
|
||||
//
|
||||
// - COMPILE_ASSERT works by defining an array type that has -1
|
||||
// elements (and thus is invalid) when the expression is false.
|
||||
//
|
||||
// - The simpler definition
|
||||
//
|
||||
// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
|
||||
//
|
||||
// does not work, as gcc supports variable-length arrays whose sizes
|
||||
// are determined at run-time (this is gcc's extension and not part
|
||||
// of the C++ standard). As a result, gcc fails to reject the
|
||||
// following code with the simple definition:
|
||||
//
|
||||
// int foo;
|
||||
// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
|
||||
// // not a compile-time constant.
|
||||
//
|
||||
// - By using the type CompileAssert<(bool(expr))>, we ensures that
|
||||
// expr is a compile-time constant. (Template arguments must be
|
||||
// determined at compile-time.)
|
||||
//
|
||||
// - The outer parentheses in CompileAssert<(bool(expr))> are necessary
|
||||
// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
|
||||
//
|
||||
// CompileAssert<bool(expr)>
|
||||
//
|
||||
// instead, these compilers will refuse to compile
|
||||
//
|
||||
// COMPILE_ASSERT(5 > 0, some_message);
|
||||
//
|
||||
// (They seem to think the ">" in "5 > 0" marks the end of the
|
||||
// template argument list.)
|
||||
//
|
||||
// - The array size is (bool(expr) ? 1 : -1), instead of simply
|
||||
//
|
||||
// ((expr) ? 1 : -1).
|
||||
//
|
||||
// This is to avoid running into a bug in MS VC 7.1, which
|
||||
// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
|
||||
|
||||
|
||||
// bit_cast<Dest,Source> is a template function that implements the
|
||||
// equivalent of "*reinterpret_cast<Dest*>(&source)". We need this in
|
||||
// very low-level functions like the protobuf library and fast math
|
||||
// support.
|
||||
//
|
||||
// float f = 3.14159265358979;
|
||||
// int i = bit_cast<int32>(f);
|
||||
// // i = 0x40490fdb
|
||||
//
|
||||
// The classical address-casting method is:
|
||||
//
|
||||
// // WRONG
|
||||
// float f = 3.14159265358979; // WRONG
|
||||
// int i = * reinterpret_cast<int*>(&f); // WRONG
|
||||
//
|
||||
// The address-casting method actually produces undefined behavior
|
||||
// according to ISO C++ specification section 3.10 -15 -. Roughly, this
|
||||
// section says: if an object in memory has one type, and a program
|
||||
// accesses it with a different type, then the result is undefined
|
||||
// behavior for most values of "different type".
|
||||
//
|
||||
// This is true for any cast syntax, either *(int*)&f or
|
||||
// *reinterpret_cast<int*>(&f). And it is particularly true for
|
||||
// conversions between integral lvalues and floating-point lvalues.
|
||||
//
|
||||
// The purpose of 3.10 -15- is to allow optimizing compilers to assume
|
||||
// that expressions with different types refer to different memory. gcc
|
||||
// 4.0.1 has an optimizer that takes advantage of this. So a
|
||||
// non-conforming program quietly produces wildly incorrect output.
|
||||
//
|
||||
// The problem is not the use of reinterpret_cast. The problem is type
|
||||
// punning: holding an object in memory of one type and reading its bits
|
||||
// back using a different type.
|
||||
//
|
||||
// The C++ standard is more subtle and complex than this, but that
|
||||
// is the basic idea.
|
||||
//
|
||||
// Anyways ...
|
||||
//
|
||||
// bit_cast<> calls memcpy() which is blessed by the standard,
|
||||
// especially by the example in section 3.9 . Also, of course,
|
||||
// bit_cast<> wraps up the nasty logic in one place.
|
||||
//
|
||||
// Fortunately memcpy() is very fast. In optimized mode, with a
|
||||
// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
|
||||
// code with the minimal amount of data movement. On a 32-bit system,
|
||||
// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
|
||||
// compiles to two loads and two stores.
|
||||
//
|
||||
// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
|
||||
//
|
||||
// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
|
||||
// is likely to surprise you.
|
||||
|
||||
template <class Dest, class Source>
|
||||
inline Dest bit_cast(const Source& source) {
|
||||
// Compile time assertion: sizeof(Dest) == sizeof(Source)
|
||||
// A compile error here means your Dest and Source have different sizes.
|
||||
typedef char VerifySizesAreEqual [sizeof(Dest) == sizeof(Source) ? 1 : -1];
|
||||
|
||||
Dest dest;
|
||||
memcpy(&dest, &source, sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Used to explicitly mark the return value of a function as unused. If you are
|
||||
// really sure you don't want to do anything with the return value of a function
|
||||
// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
|
||||
//
|
||||
// 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_BASICTYPES_H_
|
|
@ -0,0 +1,517 @@
|
|||
// This file was GENERATED by command:
|
||||
// pump.py bind.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#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 COMPILE_ASSERT asserts into BindState<>,
|
||||
// but it feels a little nicer to have the asserts here so people do not
|
||||
// need to crack open bind_internal.h. On the other hand, it makes Bind()
|
||||
// harder to read.
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Functor>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void()>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
typedef internal::BindState<RunnableType, RunType, void()> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor)));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
|
||||
typename P5>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
|
||||
const P5& p5) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
|
||||
p5_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
|
||||
typename P5, typename P6>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
|
||||
const P5& p5, const P6& p6) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
|
||||
p5_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
|
||||
p6_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
|
||||
typename P5, typename P6, typename P7>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType,
|
||||
typename internal::CallbackParamTraits<P7>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
|
||||
const P5& p5, const P6& p6, const P7& p7) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A7Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
|
||||
p5_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
|
||||
p6_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P7>::value,
|
||||
p7_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType,
|
||||
typename internal::CallbackParamTraits<P7>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6,
|
||||
p7));
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BIND_H_
|
|
@ -0,0 +1,544 @@
|
|||
// 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(), bass::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 f.Pass() 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 MessageLoopProxy.
|
||||
//
|
||||
//
|
||||
// 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 "base/basictypes.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/template_util.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(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 {
|
||||
typedef char Yes[1];
|
||||
typedef char No[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::*)(void)> struct Helper {};
|
||||
|
||||
template <typename C>
|
||||
static No& Check(Helper<&C::AddRef>*);
|
||||
|
||||
template <typename >
|
||||
static Yes& Check(...);
|
||||
|
||||
public:
|
||||
static const bool 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 {
|
||||
typedef char Yes[1];
|
||||
typedef char No[2];
|
||||
|
||||
template <typename U>
|
||||
static Yes& Check(typename U::IsMethod*);
|
||||
|
||||
template <typename U>
|
||||
static No& Check(...);
|
||||
|
||||
public:
|
||||
static const bool 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 "Pass()" function.
|
||||
// This is intentional. The whitelisting of which specific types we
|
||||
// support is maintained by CallbackParamTraits<>.
|
||||
// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
|
||||
// scoper to a Callback and allow the Callback to execute once.
|
||||
template <typename T>
|
||||
class PassedWrapper {
|
||||
public:
|
||||
explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
|
||||
PassedWrapper(const PassedWrapper& other)
|
||||
: is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
|
||||
}
|
||||
T Pass() const {
|
||||
CHECK(is_valid_);
|
||||
is_valid_ = false;
|
||||
return scoper_.Pass();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable bool is_valid_;
|
||||
mutable T scoper_;
|
||||
};
|
||||
|
||||
// Unwrap the stored parameters for the wrappers above.
|
||||
template <typename T>
|
||||
struct UnwrapTraits {
|
||||
typedef const T& ForwardType;
|
||||
static ForwardType Unwrap(const T& o) { return o; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<UnretainedWrapper<T> > {
|
||||
typedef T* ForwardType;
|
||||
static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
|
||||
return unretained.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<ConstRefWrapper<T> > {
|
||||
typedef const T& ForwardType;
|
||||
static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
|
||||
return const_ref.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<scoped_refptr<T> > {
|
||||
typedef T* ForwardType;
|
||||
static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<WeakPtr<T> > {
|
||||
typedef const WeakPtr<T>& ForwardType;
|
||||
static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<OwnedWrapper<T> > {
|
||||
typedef T* ForwardType;
|
||||
static ForwardType Unwrap(const OwnedWrapper<T>& o) {
|
||||
return o.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<PassedWrapper<T> > {
|
||||
typedef T ForwardType;
|
||||
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 MaybeRefcount;
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<false, T> {
|
||||
static void AddRef(const T&) {}
|
||||
static void Release(const T&) {}
|
||||
};
|
||||
|
||||
template <typename T, size_t n>
|
||||
struct MaybeRefcount<false, T[n]> {
|
||||
static void AddRef(const T*) {}
|
||||
static void Release(const T*) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, T> {
|
||||
static void AddRef(const T&) {}
|
||||
static void Release(const T&) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, T*> {
|
||||
static void AddRef(T* o) { o->AddRef(); }
|
||||
static void Release(T* o) { o->Release(); }
|
||||
};
|
||||
|
||||
// No need to additionally AddRef() and Release() since we are storing a
|
||||
// scoped_refptr<> inside the storage object already.
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, scoped_refptr<T> > {
|
||||
static void AddRef(const scoped_refptr<T>& o) {}
|
||||
static void Release(const scoped_refptr<T>& o) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, const T*> {
|
||||
static void AddRef(const T* o) { o->AddRef(); }
|
||||
static void Release(const T* o) { o->Release(); }
|
||||
};
|
||||
|
||||
// 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.
|
||||
//
|
||||
// P1 should be the type of the object that will be received of the method.
|
||||
template <bool IsMethod, typename P1>
|
||||
struct IsWeakMethod : public false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsWeakMethod<true, WeakPtr<T> > : public true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T> > > : public true_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 a temporary and
|
||||
// is best suited for use with the return value of a function. The second
|
||||
// takes a pointer to the scoper and is just syntactic sugar to avoid having
|
||||
// to write Passed(scoper.Pass()).
|
||||
template <typename T>
|
||||
static inline internal::PassedWrapper<T> Passed(T scoper) {
|
||||
return internal::PassedWrapper<T>(scoper.Pass());
|
||||
}
|
||||
template <typename T>
|
||||
static inline internal::PassedWrapper<T> Passed(T* scoper) {
|
||||
return internal::PassedWrapper<T>(scoper->Pass());
|
||||
}
|
||||
|
||||
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_
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,368 @@
|
|||
// This file was GENERATED by command:
|
||||
// pump.py bind_internal_win.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// 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_
|
||||
|
||||
// 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: Arity 0.
|
||||
template <typename R>
|
||||
class RunnableAdapter<R(__stdcall *)()> {
|
||||
public:
|
||||
typedef R (RunType)();
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)())
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run() {
|
||||
return function_();
|
||||
}
|
||||
|
||||
private:
|
||||
R (__stdcall *function_)();
|
||||
};
|
||||
|
||||
// __fastcall Function: Arity 0.
|
||||
template <typename R>
|
||||
class RunnableAdapter<R(__fastcall *)()> {
|
||||
public:
|
||||
typedef R (RunType)();
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)())
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run() {
|
||||
return function_();
|
||||
}
|
||||
|
||||
private:
|
||||
R (__fastcall *function_)();
|
||||
};
|
||||
|
||||
// __stdcall Function: Arity 1.
|
||||
template <typename R, typename A1>
|
||||
class RunnableAdapter<R(__stdcall *)(A1)> {
|
||||
public:
|
||||
typedef R (RunType)(A1);
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)(A1))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1) {
|
||||
return function_(a1);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__stdcall *function_)(A1);
|
||||
};
|
||||
|
||||
// __fastcall Function: Arity 1.
|
||||
template <typename R, typename A1>
|
||||
class RunnableAdapter<R(__fastcall *)(A1)> {
|
||||
public:
|
||||
typedef R (RunType)(A1);
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)(A1))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1) {
|
||||
return function_(a1);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__fastcall *function_)(A1);
|
||||
};
|
||||
|
||||
// __stdcall Function: Arity 2.
|
||||
template <typename R, typename A1, typename A2>
|
||||
class RunnableAdapter<R(__stdcall *)(A1, A2)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2);
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)(A1, A2))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2) {
|
||||
return function_(a1, a2);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__stdcall *function_)(A1, A2);
|
||||
};
|
||||
|
||||
// __fastcall Function: Arity 2.
|
||||
template <typename R, typename A1, typename A2>
|
||||
class RunnableAdapter<R(__fastcall *)(A1, A2)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2);
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)(A1, A2))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2) {
|
||||
return function_(a1, a2);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__fastcall *function_)(A1, A2);
|
||||
};
|
||||
|
||||
// __stdcall Function: Arity 3.
|
||||
template <typename R, typename A1, typename A2, typename A3>
|
||||
class RunnableAdapter<R(__stdcall *)(A1, A2, A3)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3);
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3) {
|
||||
return function_(a1, a2, a3);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__stdcall *function_)(A1, A2, A3);
|
||||
};
|
||||
|
||||
// __fastcall Function: Arity 3.
|
||||
template <typename R, typename A1, typename A2, typename A3>
|
||||
class RunnableAdapter<R(__fastcall *)(A1, A2, A3)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3);
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3) {
|
||||
return function_(a1, a2, a3);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__fastcall *function_)(A1, A2, A3);
|
||||
};
|
||||
|
||||
// __stdcall Function: Arity 4.
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4>
|
||||
class RunnableAdapter<R(__stdcall *)(A1, A2, A3, A4)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3, A4);
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename CallbackParamTraits<A4>::ForwardType a4) {
|
||||
return function_(a1, a2, a3, a4);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__stdcall *function_)(A1, A2, A3, A4);
|
||||
};
|
||||
|
||||
// __fastcall Function: Arity 4.
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4>
|
||||
class RunnableAdapter<R(__fastcall *)(A1, A2, A3, A4)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3, A4);
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename CallbackParamTraits<A4>::ForwardType a4) {
|
||||
return function_(a1, a2, a3, a4);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__fastcall *function_)(A1, A2, A3, A4);
|
||||
};
|
||||
|
||||
// __stdcall Function: Arity 5.
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5>
|
||||
class RunnableAdapter<R(__stdcall *)(A1, A2, A3, A4, A5)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3, A4, A5);
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4, A5))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename CallbackParamTraits<A5>::ForwardType a5) {
|
||||
return function_(a1, a2, a3, a4, a5);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__stdcall *function_)(A1, A2, A3, A4, A5);
|
||||
};
|
||||
|
||||
// __fastcall Function: Arity 5.
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5>
|
||||
class RunnableAdapter<R(__fastcall *)(A1, A2, A3, A4, A5)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3, A4, A5);
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4, A5))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename CallbackParamTraits<A5>::ForwardType a5) {
|
||||
return function_(a1, a2, a3, a4, a5);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__fastcall *function_)(A1, A2, A3, A4, A5);
|
||||
};
|
||||
|
||||
// __stdcall Function: Arity 6.
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6>
|
||||
class RunnableAdapter<R(__stdcall *)(A1, A2, A3, A4, A5, A6)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3, A4, A5, A6);
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4, A5, A6))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename CallbackParamTraits<A6>::ForwardType a6) {
|
||||
return function_(a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__stdcall *function_)(A1, A2, A3, A4, A5, A6);
|
||||
};
|
||||
|
||||
// __fastcall Function: Arity 6.
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6>
|
||||
class RunnableAdapter<R(__fastcall *)(A1, A2, A3, A4, A5, A6)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3, A4, A5, A6);
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4, A5, A6))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename CallbackParamTraits<A6>::ForwardType a6) {
|
||||
return function_(a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__fastcall *function_)(A1, A2, A3, A4, A5, A6);
|
||||
};
|
||||
|
||||
// __stdcall Function: Arity 7.
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6, typename A7>
|
||||
class RunnableAdapter<R(__stdcall *)(A1, A2, A3, A4, A5, A6, A7)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7);
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4, A5, A6, A7))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename CallbackParamTraits<A6>::ForwardType a6,
|
||||
typename CallbackParamTraits<A7>::ForwardType a7) {
|
||||
return function_(a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__stdcall *function_)(A1, A2, A3, A4, A5, A6, A7);
|
||||
};
|
||||
|
||||
// __fastcall Function: Arity 7.
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6, typename A7>
|
||||
class RunnableAdapter<R(__fastcall *)(A1, A2, A3, A4, A5, A6, A7)> {
|
||||
public:
|
||||
typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7);
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4, A5, A6, A7))
|
||||
: function_(function) {
|
||||
}
|
||||
|
||||
R Run(typename CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename CallbackParamTraits<A6>::ForwardType a6,
|
||||
typename CallbackParamTraits<A7>::ForwardType a7) {
|
||||
return function_(a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
|
||||
private:
|
||||
R (__fastcall *function_)(A1, A2, A3, A4, A5, A6, A7);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
#endif // !defined(ARCH_CPU_X86_64)
|
||||
|
||||
#endif // BASE_BIND_INTERNAL_WIN_H_
|
|
@ -0,0 +1,765 @@
|
|||
// This file was GENERATED by command:
|
||||
// pump.py callback.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#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(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(void)> 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(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(void)> cb = base::Bind(&MyFunc, 23, "hello world");
|
||||
// cb.Run();
|
||||
//
|
||||
// A callback with no unbound input parameters (base::Callback<void(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 issued if the object is destroyed at the time
|
||||
// it's issued. 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(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
|
||||
//
|
||||
// void foo(int arg) { cout << arg << endl }
|
||||
// int n = 1;
|
||||
// base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
|
||||
// n = 2;
|
||||
// has_ref.Run(); // Prints "2"
|
||||
//
|
||||
// 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.
|
||||
template <typename Sig>
|
||||
class Callback;
|
||||
|
||||
namespace internal {
|
||||
template <typename Runnable, typename RunType, typename BoundArgsType>
|
||||
struct BindState;
|
||||
} // namespace internal
|
||||
|
||||
template <typename R>
|
||||
class Callback<R(void)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)();
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run() const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get());
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1>
|
||||
class Callback<R(A1)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2>
|
||||
class Callback<R(A1, A2)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3>
|
||||
class Callback<R(A1, A2, A3)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4>
|
||||
class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5>
|
||||
class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4, A5);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType a5) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4),
|
||||
internal::CallbackForward(a5));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6>
|
||||
class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4, A5, A6);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType a6) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4),
|
||||
internal::CallbackForward(a5),
|
||||
internal::CallbackForward(a6));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6, typename A7>
|
||||
class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4, A5, A6, A7);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType a6,
|
||||
typename internal::CallbackParamTraits<A7>::ForwardType a7) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4),
|
||||
internal::CallbackForward(a5),
|
||||
internal::CallbackForward(a6),
|
||||
internal::CallbackForward(a7));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A7>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Syntactic sugar to make Callbacks<void(void)> easier to declare since it
|
||||
// will be used in a lot of APIs with delayed execution.
|
||||
typedef Callback<void(void)> Closure;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CALLBACK_H
|
|
@ -0,0 +1,17 @@
|
|||
// 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;
|
||||
|
||||
typedef Callback<void(void)> Closure;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CALLBACK_FORWARD_H
|
|
@ -0,0 +1,38 @@
|
|||
// 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 {
|
||||
|
||||
bool CallbackBase::is_null() const {
|
||||
return bind_state_.get() == NULL;
|
||||
}
|
||||
|
||||
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_->HasOneRef());
|
||||
}
|
||||
|
||||
CallbackBase::~CallbackBase() {
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
|
@ -0,0 +1,184 @@
|
|||
// 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 "base/base_export.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
|
||||
template <typename T>
|
||||
class ScopedVector;
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
// 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."
|
||||
class BindStateBase : public RefCountedThreadSafe<BindStateBase> {
|
||||
protected:
|
||||
friend class RefCountedThreadSafe<BindStateBase>;
|
||||
virtual ~BindStateBase() {}
|
||||
};
|
||||
|
||||
// Holds the Callback methods that don't require specialization to reduce
|
||||
// template bloat.
|
||||
class BASE_EXPORT CallbackBase {
|
||||
public:
|
||||
// Returns true if Callback is null (doesn't refer to anything).
|
||||
bool is_null() const;
|
||||
|
||||
// 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.
|
||||
typedef void(*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_;
|
||||
};
|
||||
|
||||
// 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 {
|
||||
typedef const T& ForwardType;
|
||||
typedef T StorageType;
|
||||
};
|
||||
|
||||
// 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 CallbackParamTraits<T&> {
|
||||
typedef T& ForwardType;
|
||||
typedef T StorageType;
|
||||
};
|
||||
|
||||
// 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 CallbackParamTraits<T[n]> {
|
||||
typedef const T* ForwardType;
|
||||
typedef const T* StorageType;
|
||||
};
|
||||
|
||||
// See comment for CallbackParamTraits<T[n]>.
|
||||
template <typename T>
|
||||
struct CallbackParamTraits<T[]> {
|
||||
typedef const T* ForwardType;
|
||||
typedef const T* StorageType;
|
||||
};
|
||||
|
||||
// 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().
|
||||
//
|
||||
// TODO(ajwong): We might be able to use SFINAE to search for the existence of
|
||||
// a Pass() function in the type and avoid the whitelist in CallbackParamTraits
|
||||
// and CallbackForward.
|
||||
template <typename T, typename D>
|
||||
struct CallbackParamTraits<scoped_ptr<T, D> > {
|
||||
typedef scoped_ptr<T, D> ForwardType;
|
||||
typedef scoped_ptr<T, D> StorageType;
|
||||
};
|
||||
|
||||
template <typename T, typename R>
|
||||
struct CallbackParamTraits<scoped_ptr_malloc<T, R> > {
|
||||
typedef scoped_ptr_malloc<T, R> ForwardType;
|
||||
typedef scoped_ptr_malloc<T, R> StorageType;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CallbackParamTraits<ScopedVector<T> > {
|
||||
typedef ScopedVector<T> ForwardType;
|
||||
typedef ScopedVector<T> StorageType;
|
||||
};
|
||||
|
||||
// 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 with 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>
|
||||
T& CallbackForward(T& t) { return t; }
|
||||
|
||||
template <typename T, typename D>
|
||||
scoped_ptr<T, D> CallbackForward(scoped_ptr<T, D>& p) { return p.Pass(); }
|
||||
|
||||
template <typename T, typename R>
|
||||
scoped_ptr_malloc<T, R> CallbackForward(scoped_ptr_malloc<T, R>& p) {
|
||||
return p.Pass();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ScopedVector<T> CallbackForward(ScopedVector<T>& p) { return p.Pass(); }
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CALLBACK_INTERNAL_H_
|
|
@ -0,0 +1,424 @@
|
|||
// 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/command_line.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
using base::FilePath;
|
||||
|
||||
CommandLine* CommandLine::current_process_commandline_ = NULL;
|
||||
|
||||
namespace {
|
||||
const CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--");
|
||||
const CommandLine::CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("=");
|
||||
// Since we use a lazy match, make sure that longer versions (like "--") are
|
||||
// listed before shorter versions (like "-") of similar prefixes.
|
||||
#if defined(OS_WIN)
|
||||
const CommandLine::CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
|
||||
#elif defined(OS_POSIX)
|
||||
// Unixes don't use slash as a switch.
|
||||
const CommandLine::CharType* const kSwitchPrefixes[] = {"--", "-"};
|
||||
#endif
|
||||
|
||||
size_t GetSwitchPrefixLength(const CommandLine::StringType& string) {
|
||||
for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
|
||||
CommandLine::StringType prefix(kSwitchPrefixes[i]);
|
||||
if (string.compare(0, prefix.length(), prefix) == 0)
|
||||
return prefix.length();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fills in |switch_string| and |switch_value| if |string| is a switch.
|
||||
// This will preserve the input switch prefix in the output |switch_string|.
|
||||
bool IsSwitch(const CommandLine::StringType& string,
|
||||
CommandLine::StringType* switch_string,
|
||||
CommandLine::StringType* switch_value) {
|
||||
switch_string->clear();
|
||||
switch_value->clear();
|
||||
size_t prefix_length = GetSwitchPrefixLength(string);
|
||||
if (prefix_length == 0 || prefix_length == string.length())
|
||||
return false;
|
||||
|
||||
const size_t equals_position = string.find(kSwitchValueSeparator);
|
||||
*switch_string = string.substr(0, equals_position);
|
||||
if (equals_position != CommandLine::StringType::npos)
|
||||
*switch_value = string.substr(equals_position + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append switches and arguments, keeping switches before arguments.
|
||||
void AppendSwitchesAndArguments(CommandLine& command_line,
|
||||
const CommandLine::StringVector& argv) {
|
||||
bool parse_switches = true;
|
||||
for (size_t i = 1; i < argv.size(); ++i) {
|
||||
CommandLine::StringType arg = argv[i];
|
||||
TrimWhitespace(arg, TRIM_ALL, &arg);
|
||||
|
||||
CommandLine::StringType switch_string;
|
||||
CommandLine::StringType switch_value;
|
||||
parse_switches &= (arg != kSwitchTerminator);
|
||||
if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
|
||||
#if defined(OS_WIN)
|
||||
command_line.AppendSwitchNative(WideToASCII(switch_string), switch_value);
|
||||
#elif defined(OS_POSIX)
|
||||
command_line.AppendSwitchNative(switch_string, switch_value);
|
||||
#endif
|
||||
} else {
|
||||
command_line.AppendArgNative(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lowercase switches for backwards compatiblity *on Windows*.
|
||||
std::string LowerASCIIOnWindows(const std::string& string) {
|
||||
#if defined(OS_WIN)
|
||||
return StringToLowerASCII(string);
|
||||
#elif defined(OS_POSIX)
|
||||
return string;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
|
||||
std::wstring QuoteForCommandLineToArgvW(const std::wstring& arg) {
|
||||
// We follow the quoting rules of CommandLineToArgvW.
|
||||
// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
|
||||
if (arg.find_first_of(L" \\\"") == std::wstring::npos) {
|
||||
// No quoting necessary.
|
||||
return arg;
|
||||
}
|
||||
|
||||
std::wstring out;
|
||||
out.push_back(L'"');
|
||||
for (size_t i = 0; i < arg.size(); ++i) {
|
||||
if (arg[i] == '\\') {
|
||||
// Find the extent of this run of backslashes.
|
||||
size_t start = i, end = start + 1;
|
||||
for (; end < arg.size() && arg[end] == '\\'; ++end)
|
||||
/* empty */;
|
||||
size_t backslash_count = end - start;
|
||||
|
||||
// Backslashes are escapes only if the run is followed by a double quote.
|
||||
// Since we also will end the string with a double quote, we escape for
|
||||
// either a double quote or the end of the string.
|
||||
if (end == arg.size() || arg[end] == '"') {
|
||||
// To quote, we need to output 2x as many backslashes.
|
||||
backslash_count *= 2;
|
||||
}
|
||||
for (size_t j = 0; j < backslash_count; ++j)
|
||||
out.push_back('\\');
|
||||
|
||||
// Advance i to one before the end to balance i++ in loop.
|
||||
i = end - 1;
|
||||
} else if (arg[i] == '"') {
|
||||
out.push_back('\\');
|
||||
out.push_back('"');
|
||||
} else {
|
||||
out.push_back(arg[i]);
|
||||
}
|
||||
}
|
||||
out.push_back('"');
|
||||
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
CommandLine::CommandLine(NoProgram no_program)
|
||||
: argv_(1),
|
||||
begin_args_(1) {
|
||||
}
|
||||
|
||||
CommandLine::CommandLine(const FilePath& program)
|
||||
: argv_(1),
|
||||
begin_args_(1) {
|
||||
SetProgram(program);
|
||||
}
|
||||
|
||||
CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv)
|
||||
: argv_(1),
|
||||
begin_args_(1) {
|
||||
InitFromArgv(argc, argv);
|
||||
}
|
||||
|
||||
CommandLine::CommandLine(const StringVector& argv)
|
||||
: argv_(1),
|
||||
begin_args_(1) {
|
||||
InitFromArgv(argv);
|
||||
}
|
||||
|
||||
CommandLine::~CommandLine() {
|
||||
}
|
||||
|
||||
// static
|
||||
bool CommandLine::Init(int argc, const char* const* argv) {
|
||||
if (current_process_commandline_) {
|
||||
// If this is intentional, Reset() must be called first. If we are using
|
||||
// the shared build mode, we have to share a single object across multiple
|
||||
// shared libraries.
|
||||
return false;
|
||||
}
|
||||
|
||||
current_process_commandline_ = new CommandLine(NO_PROGRAM);
|
||||
#if defined(OS_WIN)
|
||||
current_process_commandline_->ParseFromString(::GetCommandLineW());
|
||||
#elif defined(OS_POSIX)
|
||||
current_process_commandline_->InitFromArgv(argc, argv);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void CommandLine::Reset() {
|
||||
DCHECK(current_process_commandline_);
|
||||
delete current_process_commandline_;
|
||||
current_process_commandline_ = NULL;
|
||||
}
|
||||
|
||||
// static
|
||||
CommandLine* CommandLine::ForCurrentProcess() {
|
||||
DCHECK(current_process_commandline_);
|
||||
return current_process_commandline_;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CommandLine::InitializedForCurrentProcess() {
|
||||
return !!current_process_commandline_;
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// static
|
||||
CommandLine CommandLine::FromString(const std::wstring& command_line) {
|
||||
CommandLine cmd(NO_PROGRAM);
|
||||
cmd.ParseFromString(command_line);
|
||||
return cmd;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CommandLine::InitFromArgv(int argc,
|
||||
const CommandLine::CharType* const* argv) {
|
||||
StringVector new_argv;
|
||||
for (int i = 0; i < argc; ++i)
|
||||
new_argv.push_back(argv[i]);
|
||||
InitFromArgv(new_argv);
|
||||
}
|
||||
|
||||
void CommandLine::InitFromArgv(const StringVector& argv) {
|
||||
argv_ = StringVector(1);
|
||||
switches_.clear();
|
||||
begin_args_ = 1;
|
||||
SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
|
||||
AppendSwitchesAndArguments(*this, argv);
|
||||
}
|
||||
|
||||
CommandLine::StringType CommandLine::GetCommandLineString() const {
|
||||
StringType string(argv_[0]);
|
||||
#if defined(OS_WIN)
|
||||
string = QuoteForCommandLineToArgvW(string);
|
||||
#endif
|
||||
StringType params(GetArgumentsString());
|
||||
if (!params.empty()) {
|
||||
string.append(StringType(FILE_PATH_LITERAL(" ")));
|
||||
string.append(params);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
CommandLine::StringType CommandLine::GetArgumentsString() const {
|
||||
StringType params;
|
||||
// Append switches and arguments.
|
||||
bool parse_switches = true;
|
||||
for (size_t i = 1; i < argv_.size(); ++i) {
|
||||
StringType arg = argv_[i];
|
||||
StringType switch_string;
|
||||
StringType switch_value;
|
||||
parse_switches &= arg != kSwitchTerminator;
|
||||
if (i > 1)
|
||||
params.append(StringType(FILE_PATH_LITERAL(" ")));
|
||||
if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
|
||||
params.append(switch_string);
|
||||
if (!switch_value.empty()) {
|
||||
#if defined(OS_WIN)
|
||||
switch_value = QuoteForCommandLineToArgvW(switch_value);
|
||||
#endif
|
||||
params.append(kSwitchValueSeparator + switch_value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if defined(OS_WIN)
|
||||
arg = QuoteForCommandLineToArgvW(arg);
|
||||
#endif
|
||||
params.append(arg);
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
FilePath CommandLine::GetProgram() const {
|
||||
return FilePath(argv_[0]);
|
||||
}
|
||||
|
||||
void CommandLine::SetProgram(const FilePath& program) {
|
||||
TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]);
|
||||
}
|
||||
|
||||
bool CommandLine::HasSwitch(const std::string& switch_string) const {
|
||||
return switches_.find(LowerASCIIOnWindows(switch_string)) != switches_.end();
|
||||
}
|
||||
|
||||
std::string CommandLine::GetSwitchValueASCII(
|
||||
const std::string& switch_string) const {
|
||||
StringType value = GetSwitchValueNative(switch_string);
|
||||
if (!IsStringASCII(value)) {
|
||||
DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII.";
|
||||
return std::string();
|
||||
}
|
||||
#if defined(OS_WIN)
|
||||
return WideToASCII(value);
|
||||
#else
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
FilePath CommandLine::GetSwitchValuePath(
|
||||
const std::string& switch_string) const {
|
||||
return FilePath(GetSwitchValueNative(switch_string));
|
||||
}
|
||||
|
||||
CommandLine::StringType CommandLine::GetSwitchValueNative(
|
||||
const std::string& switch_string) const {
|
||||
SwitchMap::const_iterator result = switches_.end();
|
||||
result = switches_.find(LowerASCIIOnWindows(switch_string));
|
||||
return result == switches_.end() ? StringType() : result->second;
|
||||
}
|
||||
|
||||
void CommandLine::AppendSwitch(const std::string& switch_string) {
|
||||
AppendSwitchNative(switch_string, StringType());
|
||||
}
|
||||
|
||||
void CommandLine::AppendSwitchPath(const std::string& switch_string,
|
||||
const FilePath& path) {
|
||||
AppendSwitchNative(switch_string, path.value());
|
||||
}
|
||||
|
||||
void CommandLine::AppendSwitchNative(const std::string& switch_string,
|
||||
const CommandLine::StringType& value) {
|
||||
std::string switch_key(LowerASCIIOnWindows(switch_string));
|
||||
#if defined(OS_WIN)
|
||||
StringType combined_switch_string(ASCIIToWide(switch_key));
|
||||
#elif defined(OS_POSIX)
|
||||
StringType combined_switch_string(switch_string);
|
||||
#endif
|
||||
size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
|
||||
switches_[switch_key.substr(prefix_length)] = value;
|
||||
// Preserve existing switch prefixes in |argv_|; only append one if necessary.
|
||||
if (prefix_length == 0)
|
||||
combined_switch_string = kSwitchPrefixes[0] + combined_switch_string;
|
||||
if (!value.empty())
|
||||
combined_switch_string += kSwitchValueSeparator + value;
|
||||
// Append the switch and update the switches/arguments divider |begin_args_|.
|
||||
argv_.insert(argv_.begin() + begin_args_++, combined_switch_string);
|
||||
}
|
||||
|
||||
void CommandLine::AppendSwitchASCII(const std::string& switch_string,
|
||||
const std::string& value_string) {
|
||||
#if defined(OS_WIN)
|
||||
AppendSwitchNative(switch_string, ASCIIToWide(value_string));
|
||||
#elif defined(OS_POSIX)
|
||||
AppendSwitchNative(switch_string, value_string);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CommandLine::CopySwitchesFrom(const CommandLine& source,
|
||||
const char* const switches[],
|
||||
size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if (source.HasSwitch(switches[i]))
|
||||
AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i]));
|
||||
}
|
||||
}
|
||||
|
||||
CommandLine::StringVector CommandLine::GetArgs() const {
|
||||
// Gather all arguments after the last switch (may include kSwitchTerminator).
|
||||
StringVector args(argv_.begin() + begin_args_, argv_.end());
|
||||
// Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?)
|
||||
StringVector::iterator switch_terminator =
|
||||
std::find(args.begin(), args.end(), kSwitchTerminator);
|
||||
if (switch_terminator != args.end())
|
||||
args.erase(switch_terminator);
|
||||
return args;
|
||||
}
|
||||
|
||||
void CommandLine::AppendArg(const std::string& value) {
|
||||
#if defined(OS_WIN)
|
||||
DCHECK(IsStringUTF8(value));
|
||||
AppendArgNative(UTF8ToWide(value));
|
||||
#elif defined(OS_POSIX)
|
||||
AppendArgNative(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CommandLine::AppendArgPath(const FilePath& path) {
|
||||
AppendArgNative(path.value());
|
||||
}
|
||||
|
||||
void CommandLine::AppendArgNative(const CommandLine::StringType& value) {
|
||||
argv_.push_back(value);
|
||||
}
|
||||
|
||||
void CommandLine::AppendArguments(const CommandLine& other,
|
||||
bool include_program) {
|
||||
if (include_program)
|
||||
SetProgram(other.GetProgram());
|
||||
AppendSwitchesAndArguments(*this, other.argv());
|
||||
}
|
||||
|
||||
void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
|
||||
if (wrapper.empty())
|
||||
return;
|
||||
// The wrapper may have embedded arguments (like "gdb --args"). In this case,
|
||||
// we don't pretend to do anything fancy, we just split on spaces.
|
||||
StringVector wrapper_argv;
|
||||
base::SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv);
|
||||
// Prepend the wrapper and update the switches/arguments |begin_args_|.
|
||||
argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end());
|
||||
begin_args_ += wrapper_argv.size();
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void CommandLine::ParseFromString(const std::wstring& command_line) {
|
||||
std::wstring command_line_string;
|
||||
TrimWhitespace(command_line, TRIM_ALL, &command_line_string);
|
||||
if (command_line_string.empty())
|
||||
return;
|
||||
|
||||
int num_args = 0;
|
||||
wchar_t** args = NULL;
|
||||
args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args);
|
||||
|
||||
DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: "
|
||||
<< command_line;
|
||||
InitFromArgv(num_args, args);
|
||||
LocalFree(args);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,178 @@
|
|||
// 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 class works with command lines: building and parsing.
|
||||
// Arguments with prefixes ('--', '-', and on Windows, '/') are switches.
|
||||
// Switches will precede all other arguments without switch prefixes.
|
||||
// Switches can optionally have values, delimited by '=', e.g., "-switch=value".
|
||||
// An argument of "--" will terminate switch parsing during initialization,
|
||||
// interpreting subsequent tokens as non-switch arguments, regardless of prefix.
|
||||
|
||||
// There is a singleton read-only CommandLine that represents the command line
|
||||
// that the current process was started with. It must be initialized in main().
|
||||
|
||||
#ifndef BASE_COMMAND_LINE_H_
|
||||
#define BASE_COMMAND_LINE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
class BASE_EXPORT CommandLine {
|
||||
public:
|
||||
#if defined(OS_WIN)
|
||||
// The native command line string type.
|
||||
typedef std::wstring StringType;
|
||||
#elif defined(OS_POSIX)
|
||||
typedef std::string StringType;
|
||||
#endif
|
||||
|
||||
typedef StringType::value_type CharType;
|
||||
typedef std::vector<StringType> StringVector;
|
||||
typedef std::map<std::string, StringType> SwitchMap;
|
||||
|
||||
// A constructor for CommandLines that only carry switches and arguments.
|
||||
enum NoProgram { NO_PROGRAM };
|
||||
explicit CommandLine(NoProgram no_program);
|
||||
|
||||
// Construct a new command line with |program| as argv[0].
|
||||
explicit CommandLine(const base::FilePath& program);
|
||||
|
||||
// Construct a new command line from an argument list.
|
||||
CommandLine(int argc, const CharType* const* argv);
|
||||
explicit CommandLine(const StringVector& argv);
|
||||
|
||||
~CommandLine();
|
||||
|
||||
// Initialize the current process CommandLine singleton. On Windows, ignores
|
||||
// its arguments (we instead parse GetCommandLineW() directly) because we
|
||||
// don't trust the CRT's parsing of the command line, but it still must be
|
||||
// called to set up the command line. Returns false if initialization has
|
||||
// already occurred, and true otherwise. Only the caller receiving a 'true'
|
||||
// return value should take responsibility for calling Reset.
|
||||
static bool Init(int argc, const char* const* argv);
|
||||
|
||||
// Destroys the current process CommandLine singleton. This is necessary if
|
||||
// you want to reset the base library to its initial state (for example, in an
|
||||
// outer library that needs to be able to terminate, and be re-initialized).
|
||||
// If Init is called only once, as in main(), Reset() is not necessary.
|
||||
static void Reset();
|
||||
|
||||
// Get the singleton CommandLine representing the current process's
|
||||
// command line. Note: returned value is mutable, but not thread safe;
|
||||
// only mutate if you know what you're doing!
|
||||
static CommandLine* ForCurrentProcess();
|
||||
|
||||
// Returns true if the CommandLine has been initialized for the given process.
|
||||
static bool InitializedForCurrentProcess();
|
||||
|
||||
#if defined(OS_WIN)
|
||||
static CommandLine FromString(const std::wstring& command_line);
|
||||
#endif
|
||||
|
||||
// Initialize from an argv vector.
|
||||
void InitFromArgv(int argc, const CharType* const* argv);
|
||||
void InitFromArgv(const StringVector& argv);
|
||||
|
||||
// Constructs and returns the represented command line string.
|
||||
// CAUTION! This should be avoided on POSIX because quoting behavior is
|
||||
// unclear.
|
||||
StringType GetCommandLineString() const;
|
||||
|
||||
// Constructs and returns the represented arguments string.
|
||||
// CAUTION! This should be avoided on POSIX because quoting behavior is
|
||||
// unclear.
|
||||
StringType GetArgumentsString() const;
|
||||
|
||||
// Returns the original command line string as a vector of strings.
|
||||
const StringVector& argv() const { return argv_; }
|
||||
|
||||
// Get and Set the program part of the command line string (the first item).
|
||||
base::FilePath GetProgram() const;
|
||||
void SetProgram(const base::FilePath& program);
|
||||
|
||||
// Returns true if this command line contains the given switch.
|
||||
// (Switch names are case-insensitive).
|
||||
bool HasSwitch(const std::string& switch_string) const;
|
||||
|
||||
// Returns the value associated with the given switch. If the switch has no
|
||||
// value or isn't present, this method returns the empty string.
|
||||
std::string GetSwitchValueASCII(const std::string& switch_string) const;
|
||||
base::FilePath GetSwitchValuePath(const std::string& switch_string) const;
|
||||
StringType GetSwitchValueNative(const std::string& switch_string) const;
|
||||
|
||||
// Get a copy of all switches, along with their values.
|
||||
const SwitchMap& GetSwitches() const { return switches_; }
|
||||
|
||||
// Append a switch [with optional value] to the command line.
|
||||
// Note: Switches will precede arguments regardless of appending order.
|
||||
void AppendSwitch(const std::string& switch_string);
|
||||
void AppendSwitchPath(const std::string& switch_string,
|
||||
const base::FilePath& path);
|
||||
void AppendSwitchNative(const std::string& switch_string,
|
||||
const StringType& value);
|
||||
void AppendSwitchASCII(const std::string& switch_string,
|
||||
const std::string& value);
|
||||
|
||||
// Copy a set of switches (and any values) from another command line.
|
||||
// Commonly used when launching a subprocess.
|
||||
void CopySwitchesFrom(const CommandLine& source,
|
||||
const char* const switches[],
|
||||
size_t count);
|
||||
|
||||
// Get the remaining arguments to the command.
|
||||
StringVector GetArgs() const;
|
||||
|
||||
// Append an argument to the command line. Note that the argument is quoted
|
||||
// properly such that it is interpreted as one argument to the target command.
|
||||
// AppendArg is primarily for ASCII; non-ASCII input is interpreted as UTF-8.
|
||||
// Note: Switches will precede arguments regardless of appending order.
|
||||
void AppendArg(const std::string& value);
|
||||
void AppendArgPath(const base::FilePath& value);
|
||||
void AppendArgNative(const StringType& value);
|
||||
|
||||
// Append the switches and arguments from another command line to this one.
|
||||
// If |include_program| is true, include |other|'s program as well.
|
||||
void AppendArguments(const CommandLine& other, bool include_program);
|
||||
|
||||
// Insert a command before the current command.
|
||||
// Common for debuggers, like "valgrind" or "gdb --args".
|
||||
void PrependWrapper(const StringType& wrapper);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Initialize by parsing the given command line string.
|
||||
// The program name is assumed to be the first item in the string.
|
||||
void ParseFromString(const std::wstring& command_line);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Disallow default constructor; a program name must be explicitly specified.
|
||||
CommandLine();
|
||||
// Allow the copy constructor. A common pattern is to copy of the current
|
||||
// process's command line and then add some flags to it. For example:
|
||||
// CommandLine cl(*CommandLine::ForCurrentProcess());
|
||||
// cl.AppendSwitch(...);
|
||||
|
||||
// The singleton CommandLine representing the current process's command line.
|
||||
static CommandLine* current_process_commandline_;
|
||||
|
||||
// The argv array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* }
|
||||
StringVector argv_;
|
||||
|
||||
// Parsed-out switch keys and values.
|
||||
SwitchMap switches_;
|
||||
|
||||
// The index after the program and switches, any arguments start here.
|
||||
size_t begin_args_;
|
||||
};
|
||||
|
||||
#endif // BASE_COMMAND_LINE_H_
|
|
@ -0,0 +1,184 @@
|
|||
// 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)
|
||||
|
||||
// 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 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 = ...;
|
||||
#if defined(COMPILER_GCC)
|
||||
#define ALLOW_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define ALLOW_UNUSED
|
||||
#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
|
||||
// sizeof(type) prior to checking __alignof to workaround Visual C++ bug:
|
||||
// http://goo.gl/isH0C
|
||||
// Use like:
|
||||
// ALIGNOF(int32) // this would be 4
|
||||
#if defined(COMPILER_MSVC)
|
||||
#define ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type))
|
||||
#elif defined(COMPILER_GCC)
|
||||
#define ALIGNOF(type) __alignof__(type)
|
||||
#endif
|
||||
|
||||
// Annotate a virtual method indicating it must be overriding a virtual
|
||||
// method in the parent class.
|
||||
// Use like:
|
||||
// virtual void foo() OVERRIDE;
|
||||
#if defined(COMPILER_MSVC)
|
||||
#define OVERRIDE override
|
||||
#elif defined(__clang__)
|
||||
#define OVERRIDE override
|
||||
#else
|
||||
#define OVERRIDE
|
||||
#endif
|
||||
|
||||
// Annotate a virtual method indicating that subclasses must not override it,
|
||||
// or annotate a class to indicate that it cannot be subclassed.
|
||||
// Use like:
|
||||
// virtual void foo() FINAL;
|
||||
// class B FINAL : public A {};
|
||||
#if defined(COMPILER_MSVC)
|
||||
// TODO(jered): Change this to "final" when chromium no longer uses MSVC 2010.
|
||||
#define FINAL sealed
|
||||
#elif defined(__clang__)
|
||||
#define FINAL final
|
||||
#else
|
||||
#define FINAL
|
||||
#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/basictypes.h>.
|
||||
#if defined(COMPILER_GCC)
|
||||
#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.
|
||||
#ifdef MEMORY_SANITIZER
|
||||
extern "C" {
|
||||
void __msan_unpoison(const void *p, unsigned long s);
|
||||
} // extern "C"
|
||||
|
||||
// Mark a memory region fully initialized.
|
||||
// Use this to annotate code that deliberately reads uninitialized data, for
|
||||
// example a GC scavenging root set pointers from the stack.
|
||||
#define MSAN_UNPOISON(p, s) __msan_unpoison(p, s)
|
||||
#else // MEMORY_SANITIZER
|
||||
#define MSAN_UNPOISON(p, s)
|
||||
#endif // MEMORY_SANITIZER
|
||||
|
||||
#endif // BASE_COMPILER_SPECIFIC_H_
|
|
@ -0,0 +1,264 @@
|
|||
// 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 <utility>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
|
||||
#define BASE_HASH_NAMESPACE stdext
|
||||
|
||||
#elif defined(COMPILER_GCC)
|
||||
#if defined(OS_ANDROID)
|
||||
#define BASE_HASH_NAMESPACE std
|
||||
#else
|
||||
#define BASE_HASH_NAMESPACE __gnu_cxx
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#else
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef CHROME_OLD__DEPRECATED
|
||||
#define __DEPRECATED CHROME_OLD__DEPRECATED
|
||||
#undef CHROME_OLD__DEPRECATED
|
||||
#endif
|
||||
|
||||
namespace BASE_HASH_NAMESPACE {
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
// The GNU C++ library provides identity hash functions for many integral types,
|
||||
// but not for |long long|. This hash function will truncate if |size_t| is
|
||||
// narrower than |long long|. This is probably good enough for what we will
|
||||
// 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
|
||||
#endif // !defined(OS_ANDROID)
|
||||
|
||||
// Implement string hash functions so that strings of various flavors can
|
||||
// be used as keys in STL maps and sets. The hash algorithm comes from the
|
||||
// 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(string16);
|
||||
|
||||
#undef DEFINE_STRING_HASH
|
||||
|
||||
} // namespace BASE_HASH_NAMESPACE
|
||||
|
||||
#else // COMPILER
|
||||
#error define BASE_HASH_NAMESPACE for your compiler
|
||||
#endif // COMPILER
|
||||
|
||||
namespace base {
|
||||
using BASE_HASH_NAMESPACE::hash_map;
|
||||
using BASE_HASH_NAMESPACE::hash_multimap;
|
||||
using BASE_HASH_NAMESPACE::hash_multiset;
|
||||
using BASE_HASH_NAMESPACE::hash_set;
|
||||
|
||||
// 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 value1, uint32 value2) {
|
||||
uint64 value1_64 = value1;
|
||||
uint64 hash64 = (value1_64 << 32) | value2;
|
||||
|
||||
if (sizeof(std::size_t) >= sizeof(uint64))
|
||||
return static_cast<std::size_t>(hash64);
|
||||
|
||||
uint64 odd_random = 481046412LL << 32 | 1025306955LL;
|
||||
uint32 shift_random = 10121U << 16;
|
||||
|
||||
hash64 = hash64 * odd_random + shift_random;
|
||||
std::size_t high_bits = static_cast<std::size_t>(
|
||||
hash64 >> (sizeof(uint64) - 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 value1, uint64 value2) {
|
||||
uint32 short_random1 = 842304669U;
|
||||
uint32 short_random2 = 619063811U;
|
||||
uint32 short_random3 = 937041849U;
|
||||
uint32 short_random4 = 3309708029U;
|
||||
|
||||
uint32 value1a = static_cast<uint32>(value1 & 0xffffffff);
|
||||
uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff);
|
||||
uint32 value2a = static_cast<uint32>(value2 & 0xffffffff);
|
||||
uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff);
|
||||
|
||||
uint64 product1 = static_cast<uint64>(value1a) * short_random1;
|
||||
uint64 product2 = static_cast<uint64>(value1b) * short_random2;
|
||||
uint64 product3 = static_cast<uint64>(value2a) * short_random3;
|
||||
uint64 product4 = static_cast<uint64>(value2b) * short_random4;
|
||||
|
||||
uint64 hash64 = product1 + product2 + product3 + product4;
|
||||
|
||||
if (sizeof(std::size_t) >= sizeof(uint64))
|
||||
return static_cast<std::size_t>(hash64);
|
||||
|
||||
uint64 odd_random = 1578233944LL << 32 | 194370989LL;
|
||||
uint32 shift_random = 20591U << 16;
|
||||
|
||||
hash64 = hash64 * odd_random + shift_random;
|
||||
std::size_t high_bits = static_cast<std::size_t>(
|
||||
hash64 >> (sizeof(uint64) - sizeof(std::size_t)));
|
||||
return high_bits;
|
||||
}
|
||||
|
||||
#define DEFINE_32BIT_PAIR_HASH(Type1, Type2) \
|
||||
inline std::size_t HashPair(Type1 value1, Type2 value2) { \
|
||||
return HashInts32(value1, value2); \
|
||||
}
|
||||
|
||||
DEFINE_32BIT_PAIR_HASH(int16, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(int16, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(int16, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(int16, uint32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, uint32);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, uint32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, uint32);
|
||||
|
||||
#undef DEFINE_32BIT_PAIR_HASH
|
||||
|
||||
#define DEFINE_64BIT_PAIR_HASH(Type1, Type2) \
|
||||
inline std::size_t HashPair(Type1 value1, Type2 value2) { \
|
||||
return HashInts64(value1, value2); \
|
||||
}
|
||||
|
||||
DEFINE_64BIT_PAIR_HASH(int16, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(int16, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint16, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint16, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(int32, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(int32, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint32, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint32, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, int16);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, uint16);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, int32);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, uint32);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, int16);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, uint16);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, int32);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, uint32);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, uint64);
|
||||
|
||||
#undef DEFINE_64BIT_PAIR_HASH
|
||||
} // namespace base
|
||||
|
||||
namespace BASE_HASH_NAMESPACE {
|
||||
|
||||
// Implement methods for hashing a pair of integers, so they can be used as
|
||||
// keys in STL containers.
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
|
||||
template<typename Type1, typename Type2>
|
||||
inline std::size_t hash_value(const std::pair<Type1, Type2>& value) {
|
||||
return base::HashPair(value.first, value.second);
|
||||
}
|
||||
|
||||
#elif defined(COMPILER_GCC)
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
#error define hash<std::pair<Type1, Type2> > for your compiler
|
||||
#endif // COMPILER
|
||||
|
||||
}
|
||||
|
||||
#undef DEFINE_PAIR_HASH_FUNCTION_START
|
||||
#undef DEFINE_PAIR_HASH_FUNCTION_END
|
||||
|
||||
#endif // BASE_CONTAINERS_HASH_TABLES_H_
|
|
@ -0,0 +1,162 @@
|
|||
// 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 <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#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_non_stop_time_stamp_counter_(false),
|
||||
cpu_vendor_("unknown") {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#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)
|
||||
);
|
||||
}
|
||||
|
||||
void __cpuidex(int cpu_info[4], int info_type, int info_index) {
|
||||
__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), "c"(info_index)
|
||||
);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void __cpuid(int cpu_info[4], int info_type) {
|
||||
__asm__ volatile (
|
||||
"cpuid \n\t"
|
||||
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
|
||||
: "a"(info_type)
|
||||
);
|
||||
}
|
||||
|
||||
void __cpuidex(int cpu_info[4], int info_type, int info_index) {
|
||||
__asm__ volatile (
|
||||
"cpuid \n\t"
|
||||
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
|
||||
: "a"(info_type), "c"(info_index)
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // _MSC_VER
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
||||
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) {
|
||||
__cpuid(cpu_info, 1);
|
||||
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;
|
||||
has_avx_ = (cpu_info[2] & 0x10000000) != 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;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
|
||||
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
|
|
@ -0,0 +1,81 @@
|
|||
// 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,
|
||||
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_non_stop_time_stamp_counter() const {
|
||||
return has_non_stop_time_stamp_counter_;
|
||||
}
|
||||
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_non_stop_time_stamp_counter_;
|
||||
std::string cpu_vendor_;
|
||||
std::string cpu_brand_;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CPU_H_
|
|
@ -0,0 +1,37 @@
|
|||
// 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_CRITICAL_CLOSURE_H_
|
||||
#define BASE_CRITICAL_CLOSURE_H_
|
||||
|
||||
#include "base/callback.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Returns a closure that will continue to run for a period of time when the
|
||||
// application goes to the background if possible on platforms where
|
||||
// applications don't execute while backgrounded, otherwise the original task is
|
||||
// returned.
|
||||
//
|
||||
// Example:
|
||||
// file_message_loop_proxy_->PostTask(
|
||||
// FROM_HERE,
|
||||
// MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data)));
|
||||
//
|
||||
// Note new closures might be posted in this closure. If the new closures need
|
||||
// background running time, |MakeCriticalClosure| should be applied on them
|
||||
// before posting.
|
||||
#if defined(OS_IOS)
|
||||
base::Closure MakeCriticalClosure(const base::Closure& closure);
|
||||
#else
|
||||
inline base::Closure MakeCriticalClosure(const base::Closure& closure) {
|
||||
// No-op for platforms where the application does not need to acquire
|
||||
// background time for closures to finish when it goes into the background.
|
||||
return closure;
|
||||
}
|
||||
#endif // !defined(OS_IOS)
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CRITICAL_CLOSURE_H_
|
|
@ -0,0 +1,23 @@
|
|||
// 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
|
|
@ -0,0 +1,21 @@
|
|||
// 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_
|
|
@ -0,0 +1,48 @@
|
|||
// 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 {
|
||||
|
||||
// Starts the registered system-wide JIT debugger to attach it to specified
|
||||
// process.
|
||||
BASE_EXPORT bool SpawnDebuggerOnProcess(unsigned process_id);
|
||||
|
||||
// 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
|
|
@ -0,0 +1,65 @@
|
|||
// 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 "build/build_config.h"
|
||||
|
||||
// This file defines macros which can be used to annotate intentional memory
|
||||
// leaks. Support for annotations is implemented in HeapChecker and
|
||||
// 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.
|
||||
//
|
||||
// Note that HeapChecker will report a fatal error if an object which has been
|
||||
// annotated with ANNOTATE_LEAKING_OBJECT_PTR is later deleted (but
|
||||
// LeakSanitizer won't).
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL) && \
|
||||
defined(USE_HEAPCHECKER)
|
||||
|
||||
#include "third_party/tcmalloc/chromium/src/gperftools/heap-checker.h"
|
||||
|
||||
#define ANNOTATE_SCOPED_MEMORY_LEAK \
|
||||
HeapLeakChecker::Disabler heap_leak_checker_disabler; static_cast<void>(0)
|
||||
|
||||
#define ANNOTATE_LEAKING_OBJECT_PTR(X) \
|
||||
HeapLeakChecker::IgnoreObject(X)
|
||||
|
||||
#elif defined(LEAK_SANITIZER) && !defined(OS_NACL)
|
||||
|
||||
extern "C" {
|
||||
void __lsan_disable();
|
||||
void __lsan_enable();
|
||||
void __lsan_ignore_object(const void *p);
|
||||
} // extern "C"
|
||||
|
||||
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
|
||||
|
||||
// If neither HeapChecker nor LSan are used, the annotations should be no-ops.
|
||||
#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
|
||||
#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BASE_DEBUG_LEAK_ANNOTATIONS_H_
|
|
@ -0,0 +1,217 @@
|
|||
// 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/process/process_handle.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/pe_image.h"
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
|
||||
#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC)
|
||||
|
||||
static int profile_count = 0;
|
||||
|
||||
void StartProfiling(const std::string& name) {
|
||||
++profile_count;
|
||||
std::string full_name(name);
|
||||
std::string pid = StringPrintf("%d", GetCurrentProcId());
|
||||
std::string count = StringPrintf("%d", profile_count);
|
||||
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
|
|
@ -0,0 +1,90 @@
|
|||
// 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 <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
// The Profiler functions allow usage of the underlying sampling based
|
||||
// profiler. If the application has not been built with the necessary
|
||||
// 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_DEBUGGER_H
|
|
@ -0,0 +1,90 @@
|
|||
// 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_ENVIRONMENT_H_
|
||||
#define BASE_ENVIRONMENT_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace env_vars {
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
BASE_EXPORT extern const char kHome[];
|
||||
#endif
|
||||
|
||||
} // namespace env_vars
|
||||
|
||||
class BASE_EXPORT Environment {
|
||||
public:
|
||||
virtual ~Environment();
|
||||
|
||||
// Static factory method that returns the implementation that provide the
|
||||
// appropriate platform-specific instance.
|
||||
static Environment* Create();
|
||||
|
||||
// Gets an environment variable's value and stores it in |result|.
|
||||
// Returns false if the key is unset.
|
||||
virtual bool GetVar(const char* variable_name, std::string* result) = 0;
|
||||
|
||||
// Syntactic sugar for GetVar(variable_name, NULL);
|
||||
virtual bool HasVar(const char* variable_name);
|
||||
|
||||
// Returns true on success, otherwise returns false.
|
||||
virtual bool SetVar(const char* variable_name,
|
||||
const std::string& new_value) = 0;
|
||||
|
||||
// Returns true on success, otherwise returns false.
|
||||
virtual bool UnSetVar(const char* variable_name) = 0;
|
||||
};
|
||||
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
typedef string16 NativeEnvironmentString;
|
||||
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
|
||||
EnvironmentMap;
|
||||
|
||||
// Returns a modified environment vector constructed from the given environment
|
||||
// and the list of changes given in |changes|. Each key in the environment is
|
||||
// matched against the first element of the pairs. In the event of a match, the
|
||||
// value is replaced by the second of the pair, unless the second is empty, in
|
||||
// which case the key-value is removed.
|
||||
//
|
||||
// This Windows version takes and returns a Windows-style environment block
|
||||
// which is a concatenated list of null-terminated 16-bit strings. The end is
|
||||
// marked by a double-null terminator. The size of the returned string will
|
||||
// include the terminators.
|
||||
BASE_EXPORT string16 AlterEnvironment(const wchar_t* env,
|
||||
const EnvironmentMap& changes);
|
||||
|
||||
#elif defined(OS_POSIX)
|
||||
|
||||
typedef std::string NativeEnvironmentString;
|
||||
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
|
||||
EnvironmentMap;
|
||||
|
||||
// See general comments for the Windows version above.
|
||||
//
|
||||
// This Posix version takes and returns a Posix-style environment block, which
|
||||
// is a null-terminated list of pointers to null-terminated strings. The
|
||||
// returned array will have appended to it the storage for the array itself so
|
||||
// there is only one pointer to manage, but this means that you can't copy the
|
||||
// array without keeping the original around.
|
||||
BASE_EXPORT scoped_ptr<char*[]> AlterEnvironment(
|
||||
const char* const* env,
|
||||
const EnvironmentMap& changes);
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ENVIRONMENT_H_
|
|
@ -0,0 +1,45 @@
|
|||
// 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_
|
||||
|
||||
namespace base {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// We introduct a special structure for file descriptors in order that we are
|
||||
// able to use template specialisation to special-case their handling.
|
||||
//
|
||||
// WARNING: (Chromium only) There are subtleties to consider if serialising
|
||||
// these objects over IPC. See comments in ipc/ipc_message_utils.h
|
||||
// above the template specialisation for this structure.
|
||||
// -----------------------------------------------------------------------------
|
||||
struct FileDescriptor {
|
||||
FileDescriptor()
|
||||
: fd(-1),
|
||||
auto_close(false) { }
|
||||
|
||||
FileDescriptor(int ifd, bool iauto_close)
|
||||
: fd(ifd),
|
||||
auto_close(iauto_close) { }
|
||||
|
||||
bool operator==(const FileDescriptor& other) const {
|
||||
return (fd == other.fd && auto_close == other.auto_close);
|
||||
}
|
||||
|
||||
// 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_
|
|
@ -0,0 +1,264 @@
|
|||
// 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/file_util.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "base/files/file_enumerator.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
|
||||
|
||||
// The maximum number of 'uniquified' files we will try to create.
|
||||
// This is used when the filename we're trying to download is already in use,
|
||||
// so we create a new unique filename by appending " (nnn)" before the
|
||||
// extension, where 1 <= nnn <= kMaxUniqueFiles.
|
||||
// Also used by code that cleans up said files.
|
||||
static const int kMaxUniqueFiles = 100;
|
||||
|
||||
} // namespace
|
||||
|
||||
bool g_bug108724_debug = false;
|
||||
|
||||
int64 ComputeDirectorySize(const FilePath& root_path) {
|
||||
int64 running_size = 0;
|
||||
FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
|
||||
while (!file_iter.Next().empty())
|
||||
running_size += file_iter.GetInfo().GetSize();
|
||||
return running_size;
|
||||
}
|
||||
|
||||
bool Move(const FilePath& from_path, const FilePath& to_path) {
|
||||
if (from_path.ReferencesParent() || to_path.ReferencesParent())
|
||||
return false;
|
||||
return internal::MoveUnsafe(from_path, to_path);
|
||||
}
|
||||
|
||||
bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
|
||||
if (from_path.ReferencesParent() || to_path.ReferencesParent())
|
||||
return false;
|
||||
return internal::CopyFileUnsafe(from_path, to_path);
|
||||
}
|
||||
|
||||
bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
|
||||
// We open the file in binary format even if they are text files because
|
||||
// we are just comparing that bytes are exactly same in both files and not
|
||||
// doing anything smart with text formatting.
|
||||
std::ifstream file1(filename1.value().c_str(),
|
||||
std::ios::in | std::ios::binary);
|
||||
std::ifstream file2(filename2.value().c_str(),
|
||||
std::ios::in | std::ios::binary);
|
||||
|
||||
// Even if both files aren't openable (and thus, in some sense, "equal"),
|
||||
// any unusable file yields a result of "false".
|
||||
if (!file1.is_open() || !file2.is_open())
|
||||
return false;
|
||||
|
||||
const int BUFFER_SIZE = 2056;
|
||||
char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
|
||||
do {
|
||||
file1.read(buffer1, BUFFER_SIZE);
|
||||
file2.read(buffer2, BUFFER_SIZE);
|
||||
|
||||
if ((file1.eof() != file2.eof()) ||
|
||||
(file1.gcount() != file2.gcount()) ||
|
||||
(memcmp(buffer1, buffer2, file1.gcount()))) {
|
||||
file1.close();
|
||||
file2.close();
|
||||
return false;
|
||||
}
|
||||
} while (!file1.eof() || !file2.eof());
|
||||
|
||||
file1.close();
|
||||
file2.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
|
||||
std::ifstream file1(filename1.value().c_str(), std::ios::in);
|
||||
std::ifstream file2(filename2.value().c_str(), std::ios::in);
|
||||
|
||||
// Even if both files aren't openable (and thus, in some sense, "equal"),
|
||||
// any unusable file yields a result of "false".
|
||||
if (!file1.is_open() || !file2.is_open())
|
||||
return false;
|
||||
|
||||
do {
|
||||
std::string line1, line2;
|
||||
getline(file1, line1);
|
||||
getline(file2, line2);
|
||||
|
||||
// Check for mismatched EOF states, or any error state.
|
||||
if ((file1.eof() != file2.eof()) ||
|
||||
file1.bad() || file2.bad()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trim all '\r' and '\n' characters from the end of the line.
|
||||
std::string::size_type end1 = line1.find_last_not_of("\r\n");
|
||||
if (end1 == std::string::npos)
|
||||
line1.clear();
|
||||
else if (end1 + 1 < line1.length())
|
||||
line1.erase(end1 + 1);
|
||||
|
||||
std::string::size_type end2 = line2.find_last_not_of("\r\n");
|
||||
if (end2 == std::string::npos)
|
||||
line2.clear();
|
||||
else if (end2 + 1 < line2.length())
|
||||
line2.erase(end2 + 1);
|
||||
|
||||
if (line1 != line2)
|
||||
return false;
|
||||
} while (!file1.eof() || !file2.eof());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFileToString(const FilePath& path, std::string* contents) {
|
||||
if (path.ReferencesParent())
|
||||
return false;
|
||||
FILE* file = file_util::OpenFile(path, "rb");
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buf[1 << 16];
|
||||
size_t len;
|
||||
while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
|
||||
if (contents)
|
||||
contents->append(buf, len);
|
||||
}
|
||||
file_util::CloseFile(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace file_util {
|
||||
|
||||
using base::FileEnumerator;
|
||||
using base::FilePath;
|
||||
using base::kExtensionSeparator;
|
||||
using base::kMaxUniqueFiles;
|
||||
|
||||
bool IsDirectoryEmpty(const FilePath& dir_path) {
|
||||
FileEnumerator files(dir_path, false,
|
||||
FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
|
||||
if (files.Next().empty())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* CreateAndOpenTemporaryFile(FilePath* path) {
|
||||
FilePath directory;
|
||||
if (!GetTempDir(&directory))
|
||||
return NULL;
|
||||
|
||||
return CreateAndOpenTemporaryFileInDir(directory, path);
|
||||
}
|
||||
|
||||
bool CreateDirectory(const base::FilePath& full_path) {
|
||||
return CreateDirectoryAndGetError(full_path, NULL);
|
||||
}
|
||||
|
||||
bool GetFileSize(const FilePath& file_path, int64* file_size) {
|
||||
base::PlatformFileInfo info;
|
||||
if (!GetFileInfo(file_path, &info))
|
||||
return false;
|
||||
*file_size = info.size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TouchFile(const FilePath& path,
|
||||
const base::Time& last_accessed,
|
||||
const base::Time& last_modified) {
|
||||
int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
|
||||
if (DirectoryExists(path))
|
||||
flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
|
||||
#endif // OS_WIN
|
||||
|
||||
const base::PlatformFile file =
|
||||
base::CreatePlatformFile(path, flags, NULL, NULL);
|
||||
if (file != base::kInvalidPlatformFileValue) {
|
||||
bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
|
||||
base::ClosePlatformFile(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SetLastModifiedTime(const FilePath& path,
|
||||
const base::Time& last_modified) {
|
||||
return TouchFile(path, last_modified, last_modified);
|
||||
}
|
||||
|
||||
bool CloseFile(FILE* file) {
|
||||
if (file == NULL)
|
||||
return true;
|
||||
return fclose(file) == 0;
|
||||
}
|
||||
|
||||
bool TruncateFile(FILE* file) {
|
||||
if (file == NULL)
|
||||
return false;
|
||||
long current_offset = ftell(file);
|
||||
if (current_offset == -1)
|
||||
return false;
|
||||
#if defined(OS_WIN)
|
||||
int fd = _fileno(file);
|
||||
if (_chsize(fd, current_offset) != 0)
|
||||
return false;
|
||||
#else
|
||||
int fd = fileno(file);
|
||||
if (ftruncate(fd, current_offset) != 0)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int GetUniquePathNumber(
|
||||
const FilePath& path,
|
||||
const FilePath::StringType& suffix) {
|
||||
bool have_suffix = !suffix.empty();
|
||||
if (!PathExists(path) &&
|
||||
(!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
FilePath new_path;
|
||||
for (int count = 1; count <= kMaxUniqueFiles; ++count) {
|
||||
new_path =
|
||||
path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
|
||||
if (!PathExists(new_path) &&
|
||||
(!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace file_util
|
|
@ -0,0 +1,463 @@
|
|||
// 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 for dealing with the local
|
||||
// filesystem.
|
||||
|
||||
#ifndef BASE_FILE_UTIL_H_
|
||||
#define BASE_FILE_UTIL_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#elif defined(OS_POSIX)
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/platform_file.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include "base/file_descriptor_posix.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
class Time;
|
||||
|
||||
extern bool g_bug108724_debug;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Functions that involve filesystem access or modification:
|
||||
|
||||
// Returns an absolute version of a relative path. Returns an empty path on
|
||||
// error. On POSIX, this function fails if the path does not exist. This
|
||||
// function can result in I/O so it can be slow.
|
||||
BASE_EXPORT FilePath MakeAbsoluteFilePath(const FilePath& input);
|
||||
|
||||
// Returns the total number of bytes used by all the files under |root_path|.
|
||||
// If the path does not exist the function returns 0.
|
||||
//
|
||||
// This function is implemented using the FileEnumerator class so it is not
|
||||
// particularly speedy in any platform.
|
||||
BASE_EXPORT int64 ComputeDirectorySize(const FilePath& root_path);
|
||||
|
||||
// Deletes the given path, whether it's a file or a directory.
|
||||
// If it's a directory, it's perfectly happy to delete all of the
|
||||
// directory's contents. Passing true to recursive deletes
|
||||
// subdirectories and their contents as well.
|
||||
// Returns true if successful, false otherwise. It is considered successful
|
||||
// to attempt to delete a file that does not exist.
|
||||
//
|
||||
// In posix environment and if |path| is a symbolic link, this deletes only
|
||||
// the symlink. (even if the symlink points to a non-existent file)
|
||||
//
|
||||
// WARNING: USING THIS WITH recursive==true IS EQUIVALENT
|
||||
// TO "rm -rf", SO USE WITH CAUTION.
|
||||
BASE_EXPORT bool DeleteFile(const FilePath& path, bool recursive);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Schedules to delete the given path, whether it's a file or a directory, until
|
||||
// the operating system is restarted.
|
||||
// Note:
|
||||
// 1) The file/directory to be deleted should exist in a temp folder.
|
||||
// 2) The directory to be deleted must be empty.
|
||||
BASE_EXPORT bool DeleteFileAfterReboot(const FilePath& path);
|
||||
#endif
|
||||
|
||||
// Moves the given path, whether it's a file or a directory.
|
||||
// If a simple rename is not possible, such as in the case where the paths are
|
||||
// on different volumes, this will attempt to copy and delete. Returns
|
||||
// true for success.
|
||||
// This function fails if either path contains traversal components ('..').
|
||||
BASE_EXPORT bool Move(const FilePath& from_path, const FilePath& to_path);
|
||||
|
||||
// Renames file |from_path| to |to_path|. Both paths must be on the same
|
||||
// volume, or the function will fail. Destination file will be created
|
||||
// if it doesn't exist. Prefer this function over Move when dealing with
|
||||
// temporary files. On Windows it preserves attributes of the target file.
|
||||
// Returns true on success, leaving *error unchanged.
|
||||
// Returns false on failure and sets *error appropriately, if it is non-NULL.
|
||||
BASE_EXPORT bool ReplaceFile(const FilePath& from_path,
|
||||
const FilePath& to_path,
|
||||
PlatformFileError* error);
|
||||
|
||||
// Copies a single file. Use CopyDirectory to copy directories.
|
||||
// This function fails if either path contains traversal components ('..').
|
||||
BASE_EXPORT bool CopyFile(const FilePath& from_path, const FilePath& to_path);
|
||||
|
||||
// Copies the given path, and optionally all subdirectories and their contents
|
||||
// as well.
|
||||
//
|
||||
// If there are files existing under to_path, always overwrite. Returns true
|
||||
// if successful, false otherwise. Wildcards on the names are not supported.
|
||||
//
|
||||
// If you only need to copy a file use CopyFile, it's faster.
|
||||
BASE_EXPORT bool CopyDirectory(const FilePath& from_path,
|
||||
const FilePath& to_path,
|
||||
bool recursive);
|
||||
|
||||
// Returns true if the given path exists on the local filesystem,
|
||||
// false otherwise.
|
||||
BASE_EXPORT bool PathExists(const FilePath& path);
|
||||
|
||||
// Returns true if the given path is writable by the user, false otherwise.
|
||||
BASE_EXPORT bool PathIsWritable(const FilePath& path);
|
||||
|
||||
// Returns true if the given path exists and is a directory, false otherwise.
|
||||
BASE_EXPORT bool DirectoryExists(const FilePath& path);
|
||||
|
||||
// Returns true if the contents of the two files given are equal, false
|
||||
// otherwise. If either file can't be read, returns false.
|
||||
BASE_EXPORT bool ContentsEqual(const FilePath& filename1,
|
||||
const FilePath& filename2);
|
||||
|
||||
// Returns true if the contents of the two text files given are equal, false
|
||||
// otherwise. This routine treats "\r\n" and "\n" as equivalent.
|
||||
BASE_EXPORT bool TextContentsEqual(const FilePath& filename1,
|
||||
const FilePath& filename2);
|
||||
|
||||
// Read the file at |path| into |contents|, returning true on success.
|
||||
// This function fails if the |path| contains path traversal components ('..').
|
||||
// |contents| may be NULL, in which case this function is useful for its
|
||||
// side effect of priming the disk cache.
|
||||
// Useful for unit tests.
|
||||
BASE_EXPORT bool ReadFileToString(const FilePath& path, std::string* contents);
|
||||
|
||||
} // namespace base
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace file_util {
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// Read exactly |bytes| bytes from file descriptor |fd|, storing the result
|
||||
// in |buffer|. This function is protected against EINTR and partial reads.
|
||||
// Returns true iff |bytes| bytes have been successfully read from |fd|.
|
||||
BASE_EXPORT bool ReadFromFD(int fd, char* buffer, size_t bytes);
|
||||
|
||||
// Creates a symbolic link at |symlink| pointing to |target|. Returns
|
||||
// false on failure.
|
||||
BASE_EXPORT bool CreateSymbolicLink(const base::FilePath& target,
|
||||
const base::FilePath& symlink);
|
||||
|
||||
// Reads the given |symlink| and returns where it points to in |target|.
|
||||
// Returns false upon failure.
|
||||
BASE_EXPORT bool ReadSymbolicLink(const base::FilePath& symlink,
|
||||
base::FilePath* target);
|
||||
|
||||
// Bits ans masks of the file permission.
|
||||
enum FilePermissionBits {
|
||||
FILE_PERMISSION_MASK = S_IRWXU | S_IRWXG | S_IRWXO,
|
||||
FILE_PERMISSION_USER_MASK = S_IRWXU,
|
||||
FILE_PERMISSION_GROUP_MASK = S_IRWXG,
|
||||
FILE_PERMISSION_OTHERS_MASK = S_IRWXO,
|
||||
|
||||
FILE_PERMISSION_READ_BY_USER = S_IRUSR,
|
||||
FILE_PERMISSION_WRITE_BY_USER = S_IWUSR,
|
||||
FILE_PERMISSION_EXECUTE_BY_USER = S_IXUSR,
|
||||
FILE_PERMISSION_READ_BY_GROUP = S_IRGRP,
|
||||
FILE_PERMISSION_WRITE_BY_GROUP = S_IWGRP,
|
||||
FILE_PERMISSION_EXECUTE_BY_GROUP = S_IXGRP,
|
||||
FILE_PERMISSION_READ_BY_OTHERS = S_IROTH,
|
||||
FILE_PERMISSION_WRITE_BY_OTHERS = S_IWOTH,
|
||||
FILE_PERMISSION_EXECUTE_BY_OTHERS = S_IXOTH,
|
||||
};
|
||||
|
||||
// Reads the permission of the given |path|, storing the file permission
|
||||
// bits in |mode|. If |path| is symbolic link, |mode| is the permission of
|
||||
// a file which the symlink points to.
|
||||
BASE_EXPORT bool GetPosixFilePermissions(const base::FilePath& path,
|
||||
int* mode);
|
||||
// Sets the permission of the given |path|. If |path| is symbolic link, sets
|
||||
// the permission of a file which the symlink points to.
|
||||
BASE_EXPORT bool SetPosixFilePermissions(const base::FilePath& path,
|
||||
int mode);
|
||||
#endif // defined(OS_POSIX)
|
||||
|
||||
// Return true if the given directory is empty
|
||||
BASE_EXPORT bool IsDirectoryEmpty(const base::FilePath& dir_path);
|
||||
|
||||
// Get the temporary directory provided by the system.
|
||||
// WARNING: DON'T USE THIS. If you want to create a temporary file, use one of
|
||||
// the functions below.
|
||||
BASE_EXPORT bool GetTempDir(base::FilePath* path);
|
||||
// Get a temporary directory for shared memory files.
|
||||
// Only useful on POSIX; redirects to GetTempDir() on Windows.
|
||||
BASE_EXPORT bool GetShmemTempDir(base::FilePath* path, bool executable);
|
||||
|
||||
// Get the home directory. This is more complicated than just getenv("HOME")
|
||||
// as it knows to fall back on getpwent() etc.
|
||||
BASE_EXPORT base::FilePath GetHomeDir();
|
||||
|
||||
// Creates a temporary file. The full path is placed in |path|, and the
|
||||
// function returns true if was successful in creating the file. The file will
|
||||
// be empty and all handles closed after this function returns.
|
||||
BASE_EXPORT bool CreateTemporaryFile(base::FilePath* path);
|
||||
|
||||
// Same as CreateTemporaryFile but the file is created in |dir|.
|
||||
BASE_EXPORT bool CreateTemporaryFileInDir(const base::FilePath& dir,
|
||||
base::FilePath* temp_file);
|
||||
|
||||
// Create and open a temporary file. File is opened for read/write.
|
||||
// The full path is placed in |path|.
|
||||
// Returns a handle to the opened file or NULL if an error occurred.
|
||||
BASE_EXPORT FILE* CreateAndOpenTemporaryFile(base::FilePath* path);
|
||||
// Like above but for shmem files. Only useful for POSIX.
|
||||
// The executable flag says the file needs to support using
|
||||
// mprotect with PROT_EXEC after mapping.
|
||||
BASE_EXPORT FILE* CreateAndOpenTemporaryShmemFile(base::FilePath* path,
|
||||
bool executable);
|
||||
// Similar to CreateAndOpenTemporaryFile, but the file is created in |dir|.
|
||||
BASE_EXPORT FILE* CreateAndOpenTemporaryFileInDir(const base::FilePath& dir,
|
||||
base::FilePath* path);
|
||||
|
||||
// Create a new directory. If prefix is provided, the new directory name is in
|
||||
// the format of prefixyyyy.
|
||||
// NOTE: prefix is ignored in the POSIX implementation.
|
||||
// If success, return true and output the full path of the directory created.
|
||||
BASE_EXPORT bool CreateNewTempDirectory(
|
||||
const base::FilePath::StringType& prefix,
|
||||
base::FilePath* new_temp_path);
|
||||
|
||||
// Create a directory within another directory.
|
||||
// Extra characters will be appended to |prefix| to ensure that the
|
||||
// new directory does not have the same name as an existing directory.
|
||||
BASE_EXPORT bool CreateTemporaryDirInDir(
|
||||
const base::FilePath& base_dir,
|
||||
const base::FilePath::StringType& prefix,
|
||||
base::FilePath* new_dir);
|
||||
|
||||
// Creates a directory, as well as creating any parent directories, if they
|
||||
// don't exist. Returns 'true' on successful creation, or if the directory
|
||||
// already exists. The directory is only readable by the current user.
|
||||
// Returns true on success, leaving *error unchanged.
|
||||
// Returns false on failure and sets *error appropriately, if it is non-NULL.
|
||||
BASE_EXPORT bool CreateDirectoryAndGetError(const base::FilePath& full_path,
|
||||
base::PlatformFileError* error);
|
||||
|
||||
// Backward-compatible convenience method for the above.
|
||||
BASE_EXPORT bool CreateDirectory(const base::FilePath& full_path);
|
||||
|
||||
// Returns the file size. Returns true on success.
|
||||
BASE_EXPORT bool GetFileSize(const base::FilePath& file_path, int64* file_size);
|
||||
|
||||
// Sets |real_path| to |path| with symbolic links and junctions expanded.
|
||||
// On windows, make sure the path starts with a lettered drive.
|
||||
// |path| must reference a file. Function will fail if |path| points to
|
||||
// a directory or to a nonexistent path. On windows, this function will
|
||||
// fail if |path| is a junction or symlink that points to an empty file,
|
||||
// or if |real_path| would be longer than MAX_PATH characters.
|
||||
BASE_EXPORT bool NormalizeFilePath(const base::FilePath& path,
|
||||
base::FilePath* real_path);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
// Given a path in NT native form ("\Device\HarddiskVolumeXX\..."),
|
||||
// return in |drive_letter_path| the equivalent path that starts with
|
||||
// a drive letter ("C:\..."). Return false if no such path exists.
|
||||
BASE_EXPORT bool DevicePathToDriveLetterPath(const base::FilePath& device_path,
|
||||
base::FilePath* drive_letter_path);
|
||||
|
||||
// Given an existing file in |path|, set |real_path| to the path
|
||||
// in native NT format, of the form "\Device\HarddiskVolumeXX\..".
|
||||
// Returns false if the path can not be found. Empty files cannot
|
||||
// be resolved with this function.
|
||||
BASE_EXPORT bool NormalizeToNativeFilePath(const base::FilePath& path,
|
||||
base::FilePath* nt_path);
|
||||
#endif
|
||||
|
||||
// This function will return if the given file is a symlink or not.
|
||||
BASE_EXPORT bool IsLink(const base::FilePath& file_path);
|
||||
|
||||
// Returns information about the given file path.
|
||||
BASE_EXPORT bool GetFileInfo(const base::FilePath& file_path,
|
||||
base::PlatformFileInfo* info);
|
||||
|
||||
// Sets the time of the last access and the time of the last modification.
|
||||
BASE_EXPORT bool TouchFile(const base::FilePath& path,
|
||||
const base::Time& last_accessed,
|
||||
const base::Time& last_modified);
|
||||
|
||||
// Set the time of the last modification. Useful for unit tests.
|
||||
BASE_EXPORT bool SetLastModifiedTime(const base::FilePath& path,
|
||||
const base::Time& last_modified);
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// Store inode number of |path| in |inode|. Return true on success.
|
||||
BASE_EXPORT bool GetInode(const base::FilePath& path, ino_t* inode);
|
||||
#endif
|
||||
|
||||
// Wrapper for fopen-like calls. Returns non-NULL FILE* on success.
|
||||
BASE_EXPORT FILE* OpenFile(const base::FilePath& filename, const char* mode);
|
||||
|
||||
// Closes file opened by OpenFile. Returns true on success.
|
||||
BASE_EXPORT bool CloseFile(FILE* file);
|
||||
|
||||
// Truncates an open file to end at the location of the current file pointer.
|
||||
// This is a cross-platform analog to Windows' SetEndOfFile() function.
|
||||
BASE_EXPORT bool TruncateFile(FILE* file);
|
||||
|
||||
// Reads the given number of bytes from the file into the buffer. Returns
|
||||
// the number of read bytes, or -1 on error.
|
||||
BASE_EXPORT int ReadFile(const base::FilePath& filename, char* data, int size);
|
||||
|
||||
// Writes the given buffer into the file, overwriting any data that was
|
||||
// previously there. Returns the number of bytes written, or -1 on error.
|
||||
BASE_EXPORT int WriteFile(const base::FilePath& filename, const char* data,
|
||||
int size);
|
||||
#if defined(OS_POSIX)
|
||||
// Append the data to |fd|. Does not close |fd| when done.
|
||||
BASE_EXPORT int WriteFileDescriptor(const int fd, const char* data, int size);
|
||||
#endif
|
||||
// Append the given buffer into the file. Returns the number of bytes written,
|
||||
// or -1 on error.
|
||||
BASE_EXPORT int AppendToFile(const base::FilePath& filename,
|
||||
const char* data, int size);
|
||||
|
||||
// Gets the current working directory for the process.
|
||||
BASE_EXPORT bool GetCurrentDirectory(base::FilePath* path);
|
||||
|
||||
// Sets the current working directory for the process.
|
||||
BASE_EXPORT bool SetCurrentDirectory(const base::FilePath& path);
|
||||
|
||||
// Attempts to find a number that can be appended to the |path| to make it
|
||||
// unique. If |path| does not exist, 0 is returned. If it fails to find such
|
||||
// a number, -1 is returned. If |suffix| is not empty, also checks the
|
||||
// existence of it with the given suffix.
|
||||
BASE_EXPORT int GetUniquePathNumber(const base::FilePath& path,
|
||||
const base::FilePath::StringType& suffix);
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// Creates a directory with a guaranteed unique name based on |path|, returning
|
||||
// the pathname if successful, or an empty path if there was an error creating
|
||||
// the directory. Does not create parent directories.
|
||||
BASE_EXPORT base::FilePath MakeUniqueDirectory(const base::FilePath& path);
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// Test that |path| can only be changed by a given user and members of
|
||||
// a given set of groups.
|
||||
// Specifically, test that all parts of |path| under (and including) |base|:
|
||||
// * Exist.
|
||||
// * Are owned by a specific user.
|
||||
// * Are not writable by all users.
|
||||
// * Are owned by a member of a given set of groups, or are not writable by
|
||||
// their group.
|
||||
// * Are not symbolic links.
|
||||
// This is useful for checking that a config file is administrator-controlled.
|
||||
// |base| must contain |path|.
|
||||
BASE_EXPORT bool VerifyPathControlledByUser(const base::FilePath& base,
|
||||
const base::FilePath& path,
|
||||
uid_t owner_uid,
|
||||
const std::set<gid_t>& group_gids);
|
||||
#endif // defined(OS_POSIX)
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
// Is |path| writable only by a user with administrator privileges?
|
||||
// This function uses Mac OS conventions. The super user is assumed to have
|
||||
// uid 0, and the administrator group is assumed to be named "admin".
|
||||
// Testing that |path|, and every parent directory including the root of
|
||||
// the filesystem, are owned by the superuser, controlled by the group
|
||||
// "admin", are not writable by all users, and contain no symbolic links.
|
||||
// Will return false if |path| does not exist.
|
||||
BASE_EXPORT bool VerifyPathControlledByAdmin(const base::FilePath& path);
|
||||
#endif // defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
|
||||
// Returns the maximum length of path component on the volume containing
|
||||
// the directory |path|, in the number of FilePath::CharType, or -1 on failure.
|
||||
BASE_EXPORT int GetMaximumPathComponentLength(const base::FilePath& path);
|
||||
|
||||
// A class to handle auto-closing of FILE*'s.
|
||||
class ScopedFILEClose {
|
||||
public:
|
||||
inline void operator()(FILE* x) const {
|
||||
if (x) {
|
||||
fclose(x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef scoped_ptr_malloc<FILE, ScopedFILEClose> ScopedFILE;
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// A class to handle auto-closing of FDs.
|
||||
class ScopedFDClose {
|
||||
public:
|
||||
inline void operator()(int* x) const {
|
||||
if (x && *x >= 0) {
|
||||
if (HANDLE_EINTR(close(*x)) < 0)
|
||||
DPLOG(ERROR) << "close";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef scoped_ptr_malloc<int, ScopedFDClose> ScopedFD;
|
||||
#endif // OS_POSIX
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// Broad categories of file systems as returned by statfs() on Linux.
|
||||
enum FileSystemType {
|
||||
FILE_SYSTEM_UNKNOWN, // statfs failed.
|
||||
FILE_SYSTEM_0, // statfs.f_type == 0 means unknown, may indicate AFS.
|
||||
FILE_SYSTEM_ORDINARY, // on-disk filesystem like ext2
|
||||
FILE_SYSTEM_NFS,
|
||||
FILE_SYSTEM_SMB,
|
||||
FILE_SYSTEM_CODA,
|
||||
FILE_SYSTEM_MEMORY, // in-memory file system
|
||||
FILE_SYSTEM_CGROUP, // cgroup control.
|
||||
FILE_SYSTEM_OTHER, // any other value.
|
||||
FILE_SYSTEM_TYPE_COUNT
|
||||
};
|
||||
|
||||
// Attempts determine the FileSystemType for |path|.
|
||||
// Returns false if |path| doesn't exist.
|
||||
BASE_EXPORT bool GetFileSystemType(const base::FilePath& path,
|
||||
FileSystemType* type);
|
||||
#endif
|
||||
|
||||
} // namespace file_util
|
||||
|
||||
// Internal --------------------------------------------------------------------
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
// Same as Move but allows paths with traversal components.
|
||||
// Use only with extreme care.
|
||||
BASE_EXPORT bool MoveUnsafe(const FilePath& from_path,
|
||||
const FilePath& to_path);
|
||||
|
||||
// Same as CopyFile but allows paths with traversal components.
|
||||
// Use only with extreme care.
|
||||
BASE_EXPORT bool CopyFileUnsafe(const FilePath& from_path,
|
||||
const FilePath& to_path);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Copy from_path to to_path recursively and then delete from_path recursively.
|
||||
// Returns true if all operations succeed.
|
||||
// This function simulates Move(), but unlike Move() it works across volumes.
|
||||
// This function is not transactional.
|
||||
BASE_EXPORT bool CopyAndDeleteDirectory(const FilePath& from_path,
|
||||
const FilePath& to_path);
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_FILE_UTIL_H_
|
|
@ -0,0 +1,759 @@
|
|||
// 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/file_util.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/metrics/histogram.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
const DWORD kFileShareAll =
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
|
||||
bool ShellCopy(const FilePath& from_path,
|
||||
const FilePath& to_path,
|
||||
bool recursive) {
|
||||
// WinXP SHFileOperation doesn't like trailing separators.
|
||||
FilePath stripped_from = from_path.StripTrailingSeparators();
|
||||
FilePath stripped_to = to_path.StripTrailingSeparators();
|
||||
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
// NOTE: I suspect we could support longer paths, but that would involve
|
||||
// analyzing all our usage of files.
|
||||
if (stripped_from.value().length() >= MAX_PATH ||
|
||||
stripped_to.value().length() >= MAX_PATH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
|
||||
// so we have to use wcscpy because wcscpy_s writes non-NULLs
|
||||
// into the rest of the buffer.
|
||||
wchar_t double_terminated_path_from[MAX_PATH + 1] = {0};
|
||||
wchar_t double_terminated_path_to[MAX_PATH + 1] = {0};
|
||||
#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
|
||||
wcscpy(double_terminated_path_from, stripped_from.value().c_str());
|
||||
#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
|
||||
wcscpy(double_terminated_path_to, stripped_to.value().c_str());
|
||||
|
||||
SHFILEOPSTRUCT file_operation = {0};
|
||||
file_operation.wFunc = FO_COPY;
|
||||
file_operation.pFrom = double_terminated_path_from;
|
||||
file_operation.pTo = double_terminated_path_to;
|
||||
file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION |
|
||||
FOF_NOCONFIRMMKDIR;
|
||||
if (!recursive)
|
||||
file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
|
||||
|
||||
return (SHFileOperation(&file_operation) == 0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
FilePath MakeAbsoluteFilePath(const FilePath& input) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
wchar_t file_path[MAX_PATH];
|
||||
if (!_wfullpath(file_path, input.value().c_str(), MAX_PATH))
|
||||
return FilePath();
|
||||
return FilePath(file_path);
|
||||
}
|
||||
|
||||
bool DeleteFile(const FilePath& path, bool recursive) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
if (path.value().length() >= MAX_PATH)
|
||||
return false;
|
||||
|
||||
if (!recursive) {
|
||||
// If not recursing, then first check to see if |path| is a directory.
|
||||
// If it is, then remove it with RemoveDirectory.
|
||||
PlatformFileInfo file_info;
|
||||
if (file_util::GetFileInfo(path, &file_info) && file_info.is_directory)
|
||||
return RemoveDirectory(path.value().c_str()) != 0;
|
||||
|
||||
// Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first
|
||||
// because it should be faster. If DeleteFile fails, then we fall through
|
||||
// to SHFileOperation, which will do the right thing.
|
||||
if (::DeleteFile(path.value().c_str()) != 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
// SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
|
||||
// so we have to use wcscpy because wcscpy_s writes non-NULLs
|
||||
// into the rest of the buffer.
|
||||
wchar_t double_terminated_path[MAX_PATH + 1] = {0};
|
||||
#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
|
||||
if (g_bug108724_debug)
|
||||
LOG(WARNING) << "copying ";
|
||||
wcscpy(double_terminated_path, path.value().c_str());
|
||||
|
||||
SHFILEOPSTRUCT file_operation = {0};
|
||||
file_operation.wFunc = FO_DELETE;
|
||||
file_operation.pFrom = double_terminated_path;
|
||||
file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
|
||||
if (!recursive)
|
||||
file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
|
||||
if (g_bug108724_debug)
|
||||
LOG(WARNING) << "Performing shell operation";
|
||||
int err = SHFileOperation(&file_operation);
|
||||
if (g_bug108724_debug)
|
||||
LOG(WARNING) << "Done: " << err;
|
||||
|
||||
// Since we're passing flags to the operation telling it to be silent,
|
||||
// it's possible for the operation to be aborted/cancelled without err
|
||||
// being set (although MSDN doesn't give any scenarios for how this can
|
||||
// happen). See MSDN for SHFileOperation and SHFILEOPTSTRUCT.
|
||||
if (file_operation.fAnyOperationsAborted)
|
||||
return false;
|
||||
|
||||
// Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
|
||||
// an empty directory and some return 0x402 when they should be returning
|
||||
// ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402.
|
||||
return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402);
|
||||
}
|
||||
|
||||
bool DeleteFileAfterReboot(const FilePath& path) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
if (path.value().length() >= MAX_PATH)
|
||||
return false;
|
||||
|
||||
return MoveFileEx(path.value().c_str(), NULL,
|
||||
MOVEFILE_DELAY_UNTIL_REBOOT |
|
||||
MOVEFILE_REPLACE_EXISTING) != FALSE;
|
||||
}
|
||||
|
||||
bool ReplaceFile(const FilePath& from_path,
|
||||
const FilePath& to_path,
|
||||
PlatformFileError* error) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
// Try a simple move first. It will only succeed when |to_path| doesn't
|
||||
// already exist.
|
||||
if (::MoveFile(from_path.value().c_str(), to_path.value().c_str()))
|
||||
return true;
|
||||
// Try the full-blown replace if the move fails, as ReplaceFile will only
|
||||
// succeed when |to_path| does exist. When writing to a network share, we may
|
||||
// not be able to change the ACLs. Ignore ACL errors then
|
||||
// (REPLACEFILE_IGNORE_MERGE_ERRORS).
|
||||
if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL,
|
||||
REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) {
|
||||
return true;
|
||||
}
|
||||
if (error)
|
||||
*error = LastErrorToPlatformFileError(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
|
||||
bool recursive) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
if (recursive)
|
||||
return ShellCopy(from_path, to_path, true);
|
||||
|
||||
// The following code assumes that from path is a directory.
|
||||
DCHECK(DirectoryExists(from_path));
|
||||
|
||||
// Instead of creating a new directory, we copy the old one to include the
|
||||
// security information of the folder as part of the copy.
|
||||
if (!PathExists(to_path)) {
|
||||
// Except that Vista fails to do that, and instead do a recursive copy if
|
||||
// the target directory doesn't exist.
|
||||
if (base::win::GetVersion() >= base::win::VERSION_VISTA)
|
||||
file_util::CreateDirectory(to_path);
|
||||
else
|
||||
ShellCopy(from_path, to_path, false);
|
||||
}
|
||||
|
||||
FilePath directory = from_path.Append(L"*.*");
|
||||
return ShellCopy(directory, to_path, false);
|
||||
}
|
||||
|
||||
bool PathExists(const FilePath& path) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES);
|
||||
}
|
||||
|
||||
bool PathIsWritable(const FilePath& path) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
HANDLE dir =
|
||||
CreateFile(path.value().c_str(), FILE_ADD_FILE, kFileShareAll,
|
||||
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
|
||||
if (dir == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
CloseHandle(dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DirectoryExists(const FilePath& path) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
DWORD fileattr = GetFileAttributes(path.value().c_str());
|
||||
if (fileattr != INVALID_FILE_ATTRIBUTES)
|
||||
return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace file_util {
|
||||
|
||||
using base::DirectoryExists;
|
||||
using base::FilePath;
|
||||
using base::kFileShareAll;
|
||||
|
||||
bool GetTempDir(FilePath* path) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
wchar_t temp_path[MAX_PATH + 1];
|
||||
DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
|
||||
if (path_len >= MAX_PATH || path_len <= 0)
|
||||
return false;
|
||||
// TODO(evanm): the old behavior of this function was to always strip the
|
||||
// trailing slash. We duplicate this here, but it shouldn't be necessary
|
||||
// when everyone is using the appropriate FilePath APIs.
|
||||
*path = FilePath(temp_path).StripTrailingSeparators();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetShmemTempDir(FilePath* path, bool executable) {
|
||||
return GetTempDir(path);
|
||||
}
|
||||
|
||||
bool CreateTemporaryFile(FilePath* path) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
FilePath temp_file;
|
||||
|
||||
if (!GetTempDir(path))
|
||||
return false;
|
||||
|
||||
if (CreateTemporaryFileInDir(*path, &temp_file)) {
|
||||
*path = temp_file;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
return CreateAndOpenTemporaryFile(path);
|
||||
}
|
||||
|
||||
// On POSIX we have semantics to create and open a temporary file
|
||||
// atomically.
|
||||
// TODO(jrg): is there equivalent call to use on Windows instead of
|
||||
// going 2-step?
|
||||
FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
if (!CreateTemporaryFileInDir(dir, path)) {
|
||||
return NULL;
|
||||
}
|
||||
// Open file in binary mode, to avoid problems with fwrite. On Windows
|
||||
// it replaces \n's with \r\n's, which may surprise you.
|
||||
// Reference: http://msdn.microsoft.com/en-us/library/h9t88zwz(VS.71).aspx
|
||||
return OpenFile(*path, "wb+");
|
||||
}
|
||||
|
||||
bool CreateTemporaryFileInDir(const FilePath& dir,
|
||||
FilePath* temp_file) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
wchar_t temp_name[MAX_PATH + 1];
|
||||
|
||||
if (!GetTempFileName(dir.value().c_str(), L"", 0, temp_name)) {
|
||||
DPLOG(WARNING) << "Failed to get temporary file name in " << dir.value();
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t long_temp_name[MAX_PATH + 1];
|
||||
DWORD long_name_len = GetLongPathName(temp_name, long_temp_name, MAX_PATH);
|
||||
if (long_name_len > MAX_PATH || long_name_len == 0) {
|
||||
// GetLongPathName() failed, but we still have a temporary file.
|
||||
*temp_file = FilePath(temp_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
FilePath::StringType long_temp_name_str;
|
||||
long_temp_name_str.assign(long_temp_name, long_name_len);
|
||||
*temp_file = FilePath(long_temp_name_str);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateTemporaryDirInDir(const FilePath& base_dir,
|
||||
const FilePath::StringType& prefix,
|
||||
FilePath* new_dir) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
FilePath path_to_create;
|
||||
|
||||
for (int count = 0; count < 50; ++count) {
|
||||
// Try create a new temporary directory with random generated name. If
|
||||
// the one exists, keep trying another path name until we reach some limit.
|
||||
string16 new_dir_name;
|
||||
new_dir_name.assign(prefix);
|
||||
new_dir_name.append(base::IntToString16(::base::GetCurrentProcId()));
|
||||
new_dir_name.push_back('_');
|
||||
new_dir_name.append(base::IntToString16(base::RandInt(0, kint16max)));
|
||||
|
||||
path_to_create = base_dir.Append(new_dir_name);
|
||||
if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
|
||||
*new_dir = path_to_create;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CreateNewTempDirectory(const FilePath::StringType& prefix,
|
||||
FilePath* new_temp_path) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
FilePath system_temp_dir;
|
||||
if (!GetTempDir(&system_temp_dir))
|
||||
return false;
|
||||
|
||||
return CreateTemporaryDirInDir(system_temp_dir, prefix, new_temp_path);
|
||||
}
|
||||
|
||||
bool CreateDirectoryAndGetError(const FilePath& full_path,
|
||||
base::PlatformFileError* error) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
// If the path exists, we've succeeded if it's a directory, failed otherwise.
|
||||
const wchar_t* full_path_str = full_path.value().c_str();
|
||||
DWORD fileattr = ::GetFileAttributes(full_path_str);
|
||||
if (fileattr != INVALID_FILE_ATTRIBUTES) {
|
||||
if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
|
||||
DVLOG(1) << "CreateDirectory(" << full_path_str << "), "
|
||||
<< "directory already exists.";
|
||||
return true;
|
||||
}
|
||||
DLOG(WARNING) << "CreateDirectory(" << full_path_str << "), "
|
||||
<< "conflicts with existing file.";
|
||||
if (error) {
|
||||
*error = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Invariant: Path does not exist as file or directory.
|
||||
|
||||
// Attempt to create the parent recursively. This will immediately return
|
||||
// true if it already exists, otherwise will create all required parent
|
||||
// directories starting with the highest-level missing parent.
|
||||
FilePath parent_path(full_path.DirName());
|
||||
if (parent_path.value() == full_path.value()) {
|
||||
if (error) {
|
||||
*error = base::PLATFORM_FILE_ERROR_NOT_FOUND;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!CreateDirectoryAndGetError(parent_path, error)) {
|
||||
DLOG(WARNING) << "Failed to create one of the parent directories.";
|
||||
if (error) {
|
||||
DCHECK(*error != base::PLATFORM_FILE_OK);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!::CreateDirectory(full_path_str, NULL)) {
|
||||
DWORD error_code = ::GetLastError();
|
||||
if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) {
|
||||
// This error code ERROR_ALREADY_EXISTS doesn't indicate whether we
|
||||
// were racing with someone creating the same directory, or a file
|
||||
// with the same path. If DirectoryExists() returns true, we lost the
|
||||
// race to create the same directory.
|
||||
return true;
|
||||
} else {
|
||||
if (error)
|
||||
*error = base::LastErrorToPlatformFileError(error_code);
|
||||
DLOG(WARNING) << "Failed to create directory " << full_path_str
|
||||
<< ", last error is " << error_code << ".";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle
|
||||
// them if we do decide to.
|
||||
bool IsLink(const FilePath& file_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA attr;
|
||||
if (!GetFileAttributesEx(file_path.value().c_str(),
|
||||
GetFileExInfoStandard, &attr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ULARGE_INTEGER size;
|
||||
size.HighPart = attr.nFileSizeHigh;
|
||||
size.LowPart = attr.nFileSizeLow;
|
||||
results->size = size.QuadPart;
|
||||
|
||||
results->is_directory =
|
||||
(attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
results->last_modified = base::Time::FromFileTime(attr.ftLastWriteTime);
|
||||
results->last_accessed = base::Time::FromFileTime(attr.ftLastAccessTime);
|
||||
results->creation_time = base::Time::FromFileTime(attr.ftCreationTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE* OpenFile(const FilePath& filename, const char* mode) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
std::wstring w_mode = ASCIIToWide(std::string(mode));
|
||||
return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
|
||||
}
|
||||
|
||||
FILE* OpenFile(const std::string& filename, const char* mode) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
return _fsopen(filename.c_str(), mode, _SH_DENYNO);
|
||||
}
|
||||
|
||||
int ReadFile(const FilePath& filename, char* data, int size) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN,
|
||||
NULL));
|
||||
if (!file)
|
||||
return -1;
|
||||
|
||||
DWORD read;
|
||||
if (::ReadFile(file, data, size, &read, NULL) &&
|
||||
static_cast<int>(read) == size)
|
||||
return read;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WriteFile(const FilePath& filename, const char* data, int size) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
0,
|
||||
NULL));
|
||||
if (!file) {
|
||||
DLOG_GETLASTERROR(WARNING) << "CreateFile failed for path "
|
||||
<< filename.value();
|
||||
return -1;
|
||||
}
|
||||
|
||||
DWORD written;
|
||||
BOOL result = ::WriteFile(file, data, size, &written, NULL);
|
||||
if (result && static_cast<int>(written) == size)
|
||||
return written;
|
||||
|
||||
if (!result) {
|
||||
// WriteFile failed.
|
||||
DLOG_GETLASTERROR(WARNING) << "writing file " << filename.value()
|
||||
<< " failed";
|
||||
} else {
|
||||
// Didn't write all the bytes.
|
||||
DLOG(WARNING) << "wrote" << written << " bytes to "
|
||||
<< filename.value() << " expected " << size;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int AppendToFile(const FilePath& filename, const char* data, int size) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
|
||||
FILE_APPEND_DATA,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL));
|
||||
if (!file) {
|
||||
DLOG_GETLASTERROR(WARNING) << "CreateFile failed for path "
|
||||
<< filename.value();
|
||||
return -1;
|
||||
}
|
||||
|
||||
DWORD written;
|
||||
BOOL result = ::WriteFile(file, data, size, &written, NULL);
|
||||
if (result && static_cast<int>(written) == size)
|
||||
return written;
|
||||
|
||||
if (!result) {
|
||||
// WriteFile failed.
|
||||
DLOG_GETLASTERROR(WARNING) << "writing file " << filename.value()
|
||||
<< " failed";
|
||||
} else {
|
||||
// Didn't write all the bytes.
|
||||
DLOG(WARNING) << "wrote" << written << " bytes to "
|
||||
<< filename.value() << " expected " << size;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Gets the current working directory for the process.
|
||||
bool GetCurrentDirectory(FilePath* dir) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
wchar_t system_buffer[MAX_PATH];
|
||||
system_buffer[0] = 0;
|
||||
DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
|
||||
if (len == 0 || len > MAX_PATH)
|
||||
return false;
|
||||
// TODO(evanm): the old behavior of this function was to always strip the
|
||||
// trailing slash. We duplicate this here, but it shouldn't be necessary
|
||||
// when everyone is using the appropriate FilePath APIs.
|
||||
std::wstring dir_str(system_buffer);
|
||||
*dir = FilePath(dir_str).StripTrailingSeparators();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sets the current working directory for the process.
|
||||
bool SetCurrentDirectory(const FilePath& directory) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
BOOL ret = ::SetCurrentDirectory(directory.value().c_str());
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
FilePath mapped_file;
|
||||
if (!NormalizeToNativeFilePath(path, &mapped_file))
|
||||
return false;
|
||||
// NormalizeToNativeFilePath() will return a path that starts with
|
||||
// "\Device\Harddisk...". Helper DevicePathToDriveLetterPath()
|
||||
// will find a drive letter which maps to the path's device, so
|
||||
// that we return a path starting with a drive letter.
|
||||
return DevicePathToDriveLetterPath(mapped_file, real_path);
|
||||
}
|
||||
|
||||
bool DevicePathToDriveLetterPath(const FilePath& nt_device_path,
|
||||
FilePath* out_drive_letter_path) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
// Get the mapping of drive letters to device paths.
|
||||
const int kDriveMappingSize = 1024;
|
||||
wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
|
||||
if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) {
|
||||
DLOG(ERROR) << "Failed to get drive mapping.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// The drive mapping is a sequence of null terminated strings.
|
||||
// The last string is empty.
|
||||
wchar_t* drive_map_ptr = drive_mapping;
|
||||
wchar_t device_path_as_string[MAX_PATH];
|
||||
wchar_t drive[] = L" :";
|
||||
|
||||
// For each string in the drive mapping, get the junction that links
|
||||
// to it. If that junction is a prefix of |device_path|, then we
|
||||
// know that |drive| is the real path prefix.
|
||||
while (*drive_map_ptr) {
|
||||
drive[0] = drive_map_ptr[0]; // Copy the drive letter.
|
||||
|
||||
if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) {
|
||||
FilePath device_path(device_path_as_string);
|
||||
if (device_path == nt_device_path ||
|
||||
device_path.IsParent(nt_device_path)) {
|
||||
*out_drive_letter_path = FilePath(drive +
|
||||
nt_device_path.value().substr(wcslen(device_path_as_string)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Move to the next drive letter string, which starts one
|
||||
// increment after the '\0' that terminates the current string.
|
||||
while (*drive_map_ptr++);
|
||||
}
|
||||
|
||||
// No drive matched. The path does not start with a device junction
|
||||
// that is mounted as a drive letter. This means there is no drive
|
||||
// letter path to the volume that holds |device_path|, so fail.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
// In Vista, GetFinalPathNameByHandle() would give us the real path
|
||||
// from a file handle. If we ever deprecate XP, consider changing the
|
||||
// code below to a call to GetFinalPathNameByHandle(). The method this
|
||||
// function uses is explained in the following msdn article:
|
||||
// http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
|
||||
base::win::ScopedHandle file_handle(
|
||||
::CreateFile(path.value().c_str(),
|
||||
GENERIC_READ,
|
||||
kFileShareAll,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL));
|
||||
if (!file_handle)
|
||||
return false;
|
||||
|
||||
// Create a file mapping object. Can't easily use MemoryMappedFile, because
|
||||
// we only map the first byte, and need direct access to the handle. You can
|
||||
// not map an empty file, this call fails in that case.
|
||||
base::win::ScopedHandle file_map_handle(
|
||||
::CreateFileMapping(file_handle.Get(),
|
||||
NULL,
|
||||
PAGE_READONLY,
|
||||
0,
|
||||
1, // Just one byte. No need to look at the data.
|
||||
NULL));
|
||||
if (!file_map_handle)
|
||||
return false;
|
||||
|
||||
// Use a view of the file to get the path to the file.
|
||||
void* file_view = MapViewOfFile(file_map_handle.Get(),
|
||||
FILE_MAP_READ, 0, 0, 1);
|
||||
if (!file_view)
|
||||
return false;
|
||||
|
||||
// The expansion of |path| into a full path may make it longer.
|
||||
// GetMappedFileName() will fail if the result is longer than MAX_PATH.
|
||||
// Pad a bit to be safe. If kMaxPathLength is ever changed to be less
|
||||
// than MAX_PATH, it would be nessisary to test that GetMappedFileName()
|
||||
// not return kMaxPathLength. This would mean that only part of the
|
||||
// path fit in |mapped_file_path|.
|
||||
const int kMaxPathLength = MAX_PATH + 10;
|
||||
wchar_t mapped_file_path[kMaxPathLength];
|
||||
bool success = false;
|
||||
HANDLE cp = GetCurrentProcess();
|
||||
if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) {
|
||||
*nt_path = FilePath(mapped_file_path);
|
||||
success = true;
|
||||
}
|
||||
::UnmapViewOfFile(file_view);
|
||||
return success;
|
||||
}
|
||||
|
||||
int GetMaximumPathComponentLength(const FilePath& path) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
wchar_t volume_path[MAX_PATH];
|
||||
if (!GetVolumePathNameW(path.NormalizePathSeparators().value().c_str(),
|
||||
volume_path,
|
||||
arraysize(volume_path))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DWORD max_length = 0;
|
||||
if (!GetVolumeInformationW(volume_path, NULL, 0, NULL, &max_length, NULL,
|
||||
NULL, 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Length of |path| with path separator appended.
|
||||
size_t prefix = path.StripTrailingSeparators().value().size() + 1;
|
||||
// The whole path string must be shorter than MAX_PATH. That is, it must be
|
||||
// prefix + component_length < MAX_PATH (or equivalently, <= MAX_PATH - 1).
|
||||
int whole_path_limit = std::max(0, MAX_PATH - 1 - static_cast<int>(prefix));
|
||||
return std::min(whole_path_limit, static_cast<int>(max_length));
|
||||
}
|
||||
|
||||
} // namespace file_util
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
// NOTE: I suspect we could support longer paths, but that would involve
|
||||
// analyzing all our usage of files.
|
||||
if (from_path.value().length() >= MAX_PATH ||
|
||||
to_path.value().length() >= MAX_PATH) {
|
||||
return false;
|
||||
}
|
||||
if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(),
|
||||
MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0)
|
||||
return true;
|
||||
|
||||
// Keep the last error value from MoveFileEx around in case the below
|
||||
// fails.
|
||||
bool ret = false;
|
||||
DWORD last_error = ::GetLastError();
|
||||
|
||||
if (DirectoryExists(from_path)) {
|
||||
// MoveFileEx fails if moving directory across volumes. We will simulate
|
||||
// the move by using Copy and Delete. Ideally we could check whether
|
||||
// from_path and to_path are indeed in different volumes.
|
||||
ret = internal::CopyAndDeleteDirectory(from_path, to_path);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
// Leave a clue about what went wrong so that it can be (at least) picked
|
||||
// up by a PLOG entry.
|
||||
::SetLastError(last_error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
// NOTE: I suspect we could support longer paths, but that would involve
|
||||
// analyzing all our usage of files.
|
||||
if (from_path.value().length() >= MAX_PATH ||
|
||||
to_path.value().length() >= MAX_PATH) {
|
||||
return false;
|
||||
}
|
||||
return (::CopyFile(from_path.value().c_str(), to_path.value().c_str(),
|
||||
false) != 0);
|
||||
}
|
||||
|
||||
bool CopyAndDeleteDirectory(const FilePath& from_path,
|
||||
const FilePath& to_path) {
|
||||
ThreadRestrictions::AssertIOAllowed();
|
||||
if (CopyDirectory(from_path, to_path, true)) {
|
||||
if (DeleteFile(from_path, true))
|
||||
return true;
|
||||
|
||||
// Like Move, this function is not transactional, so we just
|
||||
// leave the copied bits behind if deleting from_path fails.
|
||||
// If to_path exists previously then we have already overwritten
|
||||
// it by now, we don't get better off by deleting the new bits.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
|
@ -0,0 +1,87 @@
|
|||
// 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_FILE_VERSION_INFO_H__
|
||||
#define BASE_FILE_VERSION_INFO_H__
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
#endif // OS_WIN
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
// Provides an interface for accessing the version information for a file. This
|
||||
// is the information you access when you select a file in the Windows Explorer,
|
||||
// right-click select Properties, then click the Version tab, and on the Mac
|
||||
// when you select a file in the Finder and do a Get Info.
|
||||
//
|
||||
// This list of properties is straight out of Win32's VerQueryValue
|
||||
// <http://msdn.microsoft.com/en-us/library/ms647464.aspx> and the Mac
|
||||
// version returns values from the Info.plist as appropriate. TODO(avi): make
|
||||
// this a less-obvious Windows-ism.
|
||||
|
||||
class FileVersionInfo {
|
||||
public:
|
||||
virtual ~FileVersionInfo() {}
|
||||
#if defined(OS_WIN) || defined(OS_MACOSX)
|
||||
// Creates a FileVersionInfo for the specified path. Returns NULL if something
|
||||
// goes wrong (typically the file does not exit or cannot be opened). The
|
||||
// returned object should be deleted when you are done with it.
|
||||
BASE_EXPORT static FileVersionInfo* CreateFileVersionInfo(
|
||||
const base::FilePath& file_path);
|
||||
#endif // OS_WIN || OS_MACOSX
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Creates a FileVersionInfo for the specified module. Returns NULL in case
|
||||
// of error. The returned object should be deleted when you are done with it.
|
||||
BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForModule(
|
||||
HMODULE module);
|
||||
|
||||
// Creates a FileVersionInfo for the current module. Returns NULL in case
|
||||
// of error. The returned object should be deleted when you are done with it.
|
||||
// This function should be inlined so that the "current module" is evaluated
|
||||
// correctly, instead of being the module that contains base.
|
||||
__forceinline static FileVersionInfo*
|
||||
CreateFileVersionInfoForCurrentModule() {
|
||||
HMODULE module = reinterpret_cast<HMODULE>(&__ImageBase);
|
||||
return CreateFileVersionInfoForModule(module);
|
||||
}
|
||||
#else
|
||||
// Creates a FileVersionInfo for the current module. Returns NULL in case
|
||||
// of error. The returned object should be deleted when you are done with it.
|
||||
BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForCurrentModule();
|
||||
#endif // OS_WIN
|
||||
|
||||
// Accessors to the different version properties.
|
||||
// Returns an empty string if the property is not found.
|
||||
virtual string16 company_name() = 0;
|
||||
virtual string16 company_short_name() = 0;
|
||||
virtual string16 product_name() = 0;
|
||||
virtual string16 product_short_name() = 0;
|
||||
virtual string16 internal_name() = 0;
|
||||
virtual string16 product_version() = 0;
|
||||
virtual string16 private_build() = 0;
|
||||
virtual string16 special_build() = 0;
|
||||
virtual string16 comments() = 0;
|
||||
virtual string16 original_filename() = 0;
|
||||
virtual string16 file_description() = 0;
|
||||
virtual string16 file_version() = 0;
|
||||
virtual string16 legal_copyright() = 0;
|
||||
virtual string16 legal_trademarks() = 0;
|
||||
virtual string16 last_change() = 0;
|
||||
virtual bool is_official_build() = 0;
|
||||
};
|
||||
|
||||
#endif // BASE_FILE_VERSION_INFO_H__
|
|
@ -0,0 +1,62 @@
|
|||
// 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_FILE_VERSION_INFO_WIN_H_
|
||||
#define BASE_FILE_VERSION_INFO_WIN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/file_version_info.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
|
||||
struct tagVS_FIXEDFILEINFO;
|
||||
typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
|
||||
|
||||
class FileVersionInfoWin : public FileVersionInfo {
|
||||
public:
|
||||
BASE_EXPORT FileVersionInfoWin(void* data, int language, int code_page);
|
||||
BASE_EXPORT ~FileVersionInfoWin();
|
||||
|
||||
// Accessors to the different version properties.
|
||||
// Returns an empty string if the property is not found.
|
||||
virtual string16 company_name() OVERRIDE;
|
||||
virtual string16 company_short_name() OVERRIDE;
|
||||
virtual string16 product_name() OVERRIDE;
|
||||
virtual string16 product_short_name() OVERRIDE;
|
||||
virtual string16 internal_name() OVERRIDE;
|
||||
virtual string16 product_version() OVERRIDE;
|
||||
virtual string16 private_build() OVERRIDE;
|
||||
virtual string16 special_build() OVERRIDE;
|
||||
virtual string16 comments() OVERRIDE;
|
||||
virtual string16 original_filename() OVERRIDE;
|
||||
virtual string16 file_description() OVERRIDE;
|
||||
virtual string16 file_version() OVERRIDE;
|
||||
virtual string16 legal_copyright() OVERRIDE;
|
||||
virtual string16 legal_trademarks() OVERRIDE;
|
||||
virtual string16 last_change() OVERRIDE;
|
||||
virtual bool is_official_build() OVERRIDE;
|
||||
|
||||
// Lets you access other properties not covered above.
|
||||
BASE_EXPORT bool GetValue(const wchar_t* name, std::wstring* value);
|
||||
|
||||
// Similar to GetValue but returns a wstring (empty string if the property
|
||||
// does not exist).
|
||||
BASE_EXPORT std::wstring GetStringValue(const wchar_t* name);
|
||||
|
||||
// Get the fixed file info if it exists. Otherwise NULL
|
||||
VS_FIXEDFILEINFO* fixed_file_info() { return fixed_file_info_; }
|
||||
|
||||
private:
|
||||
scoped_ptr_malloc<char> data_;
|
||||
int language_;
|
||||
int code_page_;
|
||||
// This is a pointer into the data_ if it exists. Otherwise NULL.
|
||||
VS_FIXEDFILEINFO* fixed_file_info_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FileVersionInfoWin);
|
||||
};
|
||||
|
||||
#endif // BASE_FILE_VERSION_INFO_WIN_H_
|
|
@ -0,0 +1,458 @@
|
|||
// 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.
|
||||
//
|
||||
// Paths can't contain NULs as a precaution agaist premature truncation.
|
||||
//
|
||||
// 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.266 ("Pathname")
|
||||
// and 4.12 ("Pathname Resolution"), available at:
|
||||
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_266
|
||||
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/string_piece.h" // For implicit conversions.
|
||||
#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
|
||||
|
||||
class Pickle;
|
||||
class PickleIterator;
|
||||
|
||||
namespace base {
|
||||
|
||||
// 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 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(const StringType& 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.
|
||||
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.
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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(
|
||||
const StringType& suffix) const WARN_UNUSED_RESULT;
|
||||
FilePath InsertBeforeExtensionASCII(
|
||||
const base::StringPiece& suffix) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Adds |extension| to |file_name|. Returns the current FilePath if
|
||||
// |extension| is empty. Returns "" if BaseName() == "." or "..".
|
||||
FilePath AddExtension(
|
||||
const StringType& extension) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Replaces the extension of |file_name| with |extension|. If |file_name|
|
||||
// does not have an extension, then |extension| is added. If |extension| is
|
||||
// empty, then the extension is removed from |file_name|.
|
||||
// Returns "" if BaseName() == "." or "..".
|
||||
FilePath ReplaceExtension(
|
||||
const StringType& extension) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns true if the file path matches the specified extension. The test is
|
||||
// case insensitive. Don't forget the leading period if appropriate.
|
||||
bool MatchesExtension(const StringType& extension) const;
|
||||
|
||||
// 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(const StringType& 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(const base::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 any attempt to reference a parent
|
||||
// directory (i.e. 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;
|
||||
|
||||
// Older Chromium code assumes that paths are always wstrings.
|
||||
// This function converts wstrings to FilePaths, and is
|
||||
// useful to smooth porting that old code to the FilePath API.
|
||||
// It has "Hack" its name so people feel bad about using it.
|
||||
// http://code.google.com/p/chromium/issues/detail?id=24672
|
||||
//
|
||||
// If you are trying to be a good citizen and remove these, ask yourself:
|
||||
// - Am I interacting with other Chrome code that deals with files? Then
|
||||
// try to convert the API into using FilePath.
|
||||
// - Am I interacting with OS-native calls? Then use value() to get at an
|
||||
// OS-native string format.
|
||||
// - Am I using well-known file names, like "config.ini"? Then use the
|
||||
// ASCII functions (we require paths to always be supersets of ASCII).
|
||||
// - Am I displaying a string to the user in some UI? Then use the
|
||||
// LossyDisplayName() function, but keep in mind that you can't
|
||||
// ever use the result of that again as a path.
|
||||
static FilePath FromWStringHack(const std::wstring& wstring);
|
||||
|
||||
// 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;
|
||||
|
||||
// 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(const StringType& string1,
|
||||
const StringType& string2);
|
||||
static bool CompareEqualIgnoreCase(const StringType& string1,
|
||||
const StringType& string2) {
|
||||
return CompareIgnoreCase(string1, string2) == 0;
|
||||
}
|
||||
static bool CompareLessIgnoreCase(const StringType& string1,
|
||||
const StringType& 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(const FilePath::StringType& string);
|
||||
|
||||
// Special UTF-8 version of FastUnicodeCompare. Cf:
|
||||
// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
|
||||
// IMPORTANT: The input strings must be in the special HFS decomposed form!
|
||||
// (cf. above GetHFSDecomposedForm method)
|
||||
static int HFSFastUnicodeCompare(const StringType& string1,
|
||||
const StringType& string2);
|
||||
#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_;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
// This is required by googletest to print a readable output on test failures.
|
||||
BASE_EXPORT extern void PrintTo(const base::FilePath& path, std::ostream* out);
|
||||
|
||||
// Macros for string literal initialization of FilePath::CharType[], and for
|
||||
// using a FilePath::CharType[] in a printf-style format string.
|
||||
#if defined(OS_POSIX)
|
||||
#define FILE_PATH_LITERAL(x) x
|
||||
#define PRFilePath "s"
|
||||
#define PRFilePathLiteral "%s"
|
||||
#elif defined(OS_WIN)
|
||||
#define FILE_PATH_LITERAL(x) L ## x
|
||||
#define PRFilePath "ls"
|
||||
#define PRFilePathLiteral L"%ls"
|
||||
#endif // OS_WIN
|
||||
|
||||
// Provide a hash function so that hash_sets and maps can contain FilePath
|
||||
// objects.
|
||||
namespace BASE_HASH_NAMESPACE {
|
||||
#if defined(COMPILER_GCC)
|
||||
|
||||
template<>
|
||||
struct hash<base::FilePath> {
|
||||
size_t operator()(const base::FilePath& f) const {
|
||||
return hash<base::FilePath::StringType>()(f.value());
|
||||
}
|
||||
};
|
||||
|
||||
#elif defined(COMPILER_MSVC)
|
||||
|
||||
inline size_t hash_value(const base::FilePath& f) {
|
||||
return hash_value(f.value());
|
||||
}
|
||||
|
||||
#endif // COMPILER
|
||||
|
||||
} // namespace BASE_HASH_NAMESPACE
|
||||
|
||||
#endif // BASE_FILES_FILE_PATH_H_
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_FLOAT_UTIL_H_
|
||||
#define BASE_FLOAT_UTIL_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Float>
|
||||
inline bool IsFinite(const Float& number) {
|
||||
#if defined(OS_POSIX)
|
||||
return std::isfinite(number) != 0;
|
||||
#elif defined(OS_WIN)
|
||||
return _finite(number) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Float>
|
||||
inline bool IsNaN(const Float& number) {
|
||||
#if defined(OS_POSIX)
|
||||
return std::isnan(number) != 0;
|
||||
#elif defined(OS_WIN)
|
||||
return _isnan(number) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_FLOAT_UTIL_H_
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 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_FORMAT_MACROS_H_
|
||||
#define BASE_FORMAT_MACROS_H_
|
||||
|
||||
// This file defines the format macros for some integer types.
|
||||
|
||||
// To print a 64-bit value in a portable way:
|
||||
// int64_t value;
|
||||
// printf("xyz:%" PRId64, value);
|
||||
// The "d" in the macro corresponds to %d; you can also use PRIu64 etc.
|
||||
//
|
||||
// For wide strings, prepend "Wide" to the macro:
|
||||
// int64_t value;
|
||||
// StringPrintf(L"xyz: %" WidePRId64, value);
|
||||
//
|
||||
// To print a size_t value in a portable way:
|
||||
// size_t size;
|
||||
// printf("xyz: %" PRIuS, size);
|
||||
// The "u" in the macro corresponds to %u, and S is for "size".
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
|
||||
#if (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && !defined(PRId64)
|
||||
#error "inttypes.h has already been included before this header file, but "
|
||||
#error "without __STDC_FORMAT_MACROS defined."
|
||||
#endif
|
||||
|
||||
#if !defined(__STDC_FORMAT_MACROS)
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
// GCC will concatenate wide and narrow strings correctly, so nothing needs to
|
||||
// be done here.
|
||||
#define WidePRId64 PRId64
|
||||
#define WidePRIu64 PRIu64
|
||||
#define WidePRIx64 PRIx64
|
||||
|
||||
#if !defined(PRIuS)
|
||||
#define PRIuS "zu"
|
||||
#endif
|
||||
|
||||
#else // OS_WIN
|
||||
|
||||
#if !defined(PRId64)
|
||||
#define PRId64 "I64d"
|
||||
#endif
|
||||
|
||||
#if !defined(PRIu64)
|
||||
#define PRIu64 "I64u"
|
||||
#endif
|
||||
|
||||
#if !defined(PRIx64)
|
||||
#define PRIx64 "I64x"
|
||||
#endif
|
||||
|
||||
#define WidePRId64 L"I64d"
|
||||
#define WidePRIu64 L"I64u"
|
||||
#define WidePRIx64 L"I64x"
|
||||
|
||||
#if !defined(PRIuS)
|
||||
#define PRIuS "Iu"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BASE_FORMAT_MACROS_H_
|
|
@ -0,0 +1,32 @@
|
|||
// 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 <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.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 psuedo 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 bytes[2]);
|
||||
#endif
|
||||
|
||||
} // namespace guid
|
||||
|
||||
#endif // BASE_GUID_H_
|
|
@ -0,0 +1,59 @@
|
|||
// 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/basictypes.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "base/third_party/dynamic_annotations/dynamic_annotations.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*)) {
|
||||
// See the comment to the corresponding HAPPENS_AFTER in Pointer().
|
||||
ANNOTATE_HAPPENS_BEFORE(state);
|
||||
|
||||
// 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
|
|
@ -0,0 +1,212 @@
|
|||
// 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/basictypes.h"
|
||||
#include "base/debug/leak_annotations.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/aligned_memory.h"
|
||||
#include "base/third_party/dynamic_annotations/dynamic_annotations.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;
|
||||
static const bool kAllowedToAccessOnNonjoinableThread = false;
|
||||
|
||||
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;
|
||||
static const bool kAllowedToAccessOnNonjoinableThread = true;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// This annotation helps race detectors recognize correct lock-less
|
||||
// synchronization between different threads calling Pointer().
|
||||
// We suggest dynamic race detection tool that "Traits::New" above
|
||||
// and CompleteLazyInstance(...) happens before "return instance()" below.
|
||||
// See the corresponding HAPPENS_BEFORE in CompleteLazyInstance(...).
|
||||
ANNOTATE_HAPPENS_AFTER(&private_instance_);
|
||||
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_
|
|
@ -0,0 +1,102 @@
|
|||
// 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)
|
||||
// MSDN says to #include <intrin.h>, but that breaks the VS2005 build.
|
||||
extern "C" {
|
||||
void* _ReturnAddress();
|
||||
}
|
||||
#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) {
|
||||
}
|
||||
|
||||
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)
|
||||
return __builtin_extract_return_addr(__builtin_return_address(0));
|
||||
#endif // COMPILER_GCC
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace tracked_objects
|
|
@ -0,0 +1,94 @@
|
|||
// 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 <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.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();
|
||||
|
||||
// Comparison operator for insertion into a std::map<> hash tables.
|
||||
// All we need is *some* (any) hashing distinction. Strings should already
|
||||
// be unique, so we don't bother with strcmp or such.
|
||||
// Use line number as the primary key (because it is fast, and usually gets us
|
||||
// a difference), and then pointers as secondary keys (just to get some
|
||||
// distinctions).
|
||||
bool operator < (const Location& other) const {
|
||||
if (line_number_ != other.line_number_)
|
||||
return line_number_ < other.line_number_;
|
||||
if (file_name_ != other.file_name_)
|
||||
return file_name_ < other.file_name_;
|
||||
return function_name_ < other.function_name_;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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_
|
|
@ -0,0 +1,866 @@
|
|||
// 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/logging.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
typedef HANDLE FileHandle;
|
||||
typedef HANDLE MutexHandle;
|
||||
// Windows warns on using write(). It prefers _write().
|
||||
#define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count))
|
||||
// Windows doesn't define STDERR_FILENO. Define it here.
|
||||
#define STDERR_FILENO 2
|
||||
#elif defined(OS_MACOSX)
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#elif defined(OS_POSIX)
|
||||
#if defined(OS_NACL)
|
||||
#include <sys/time.h> // timespec doesn't seem to be in <time.h>
|
||||
#else
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#define MAX_PATH PATH_MAX
|
||||
typedef FILE* FileHandle;
|
||||
typedef pthread_mutex_t* MutexHandle;
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
|
||||
#include "base/base_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/debug/alias.h"
|
||||
#include "base/debug/debugger.h"
|
||||
#include "base/debug/stack_trace.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/synchronization/lock_impl.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "base/vlog.h"
|
||||
#if defined(OS_POSIX)
|
||||
#include "base/safe_strerror_posix.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
namespace logging {
|
||||
|
||||
DcheckState g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
|
||||
|
||||
DcheckState get_dcheck_state() {
|
||||
return g_dcheck_state;
|
||||
}
|
||||
|
||||
void set_dcheck_state(DcheckState state) {
|
||||
g_dcheck_state = state;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
VlogInfo* g_vlog_info = NULL;
|
||||
VlogInfo* g_vlog_info_prev = NULL;
|
||||
|
||||
const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
|
||||
"INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
|
||||
|
||||
int min_log_level = 0;
|
||||
|
||||
LoggingDestination logging_destination = LOG_DEFAULT;
|
||||
|
||||
// For LOG_ERROR and above, always print to stderr.
|
||||
const int kAlwaysPrintErrorLevel = LOG_ERROR;
|
||||
|
||||
// Which log file to use? This is initialized by InitLogging or
|
||||
// will be lazily initialized to the default value when it is
|
||||
// first needed.
|
||||
#if defined(OS_WIN)
|
||||
typedef std::wstring PathString;
|
||||
#else
|
||||
typedef std::string PathString;
|
||||
#endif
|
||||
PathString* log_file_name = NULL;
|
||||
|
||||
// this file is lazily opened and the handle may be NULL
|
||||
FileHandle log_file = NULL;
|
||||
|
||||
// what should be prepended to each message?
|
||||
bool log_process_id = false;
|
||||
bool log_thread_id = false;
|
||||
bool log_timestamp = true;
|
||||
bool log_tickcount = false;
|
||||
|
||||
// Should we pop up fatal debug messages in a dialog?
|
||||
bool show_error_dialogs = false;
|
||||
|
||||
// An assert handler override specified by the client to be called instead of
|
||||
// the debug message dialog and process termination.
|
||||
LogAssertHandlerFunction log_assert_handler = NULL;
|
||||
// An report handler override specified by the client to be called instead of
|
||||
// the debug message dialog.
|
||||
LogReportHandlerFunction log_report_handler = NULL;
|
||||
// A log message handler that gets notified of every log message we process.
|
||||
LogMessageHandlerFunction log_message_handler = NULL;
|
||||
|
||||
// Helper functions to wrap platform differences.
|
||||
|
||||
int32 CurrentProcessId() {
|
||||
#if defined(OS_WIN)
|
||||
return GetCurrentProcessId();
|
||||
#elif defined(OS_POSIX)
|
||||
return getpid();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64 TickCount() {
|
||||
#if defined(OS_WIN)
|
||||
return GetTickCount();
|
||||
#elif defined(OS_MACOSX)
|
||||
return mach_absolute_time();
|
||||
#elif defined(OS_NACL)
|
||||
// NaCl sadly does not have _POSIX_TIMERS enabled in sys/features.h
|
||||
// So we have to use clock() for now.
|
||||
return clock();
|
||||
#elif defined(OS_POSIX)
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
uint64 absolute_micro =
|
||||
static_cast<int64>(ts.tv_sec) * 1000000 +
|
||||
static_cast<int64>(ts.tv_nsec) / 1000;
|
||||
|
||||
return absolute_micro;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DeleteFilePath(const PathString& log_name) {
|
||||
#if defined(OS_WIN)
|
||||
DeleteFile(log_name.c_str());
|
||||
#elif defined (OS_NACL)
|
||||
// Do nothing; unlink() isn't supported on NaCl.
|
||||
#else
|
||||
unlink(log_name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
PathString GetDefaultLogFile() {
|
||||
#if defined(OS_WIN)
|
||||
// On Windows we use the same path as the exe.
|
||||
wchar_t module_name[MAX_PATH];
|
||||
GetModuleFileName(NULL, module_name, MAX_PATH);
|
||||
|
||||
PathString log_file = module_name;
|
||||
PathString::size_type last_backslash =
|
||||
log_file.rfind('\\', log_file.size());
|
||||
if (last_backslash != PathString::npos)
|
||||
log_file.erase(last_backslash + 1);
|
||||
log_file += L"debug.log";
|
||||
return log_file;
|
||||
#elif defined(OS_POSIX)
|
||||
// On other platforms we just use the current directory.
|
||||
return PathString("debug.log");
|
||||
#endif
|
||||
}
|
||||
|
||||
// This class acts as a wrapper for locking the logging files.
|
||||
// LoggingLock::Init() should be called from the main thread before any logging
|
||||
// is done. Then whenever logging, be sure to have a local LoggingLock
|
||||
// instance on the stack. This will ensure that the lock is unlocked upon
|
||||
// exiting the frame.
|
||||
// LoggingLocks can not be nested.
|
||||
class LoggingLock {
|
||||
public:
|
||||
LoggingLock() {
|
||||
LockLogging();
|
||||
}
|
||||
|
||||
~LoggingLock() {
|
||||
UnlockLogging();
|
||||
}
|
||||
|
||||
static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
|
||||
if (initialized)
|
||||
return;
|
||||
lock_log_file = lock_log;
|
||||
if (lock_log_file == LOCK_LOG_FILE) {
|
||||
#if defined(OS_WIN)
|
||||
if (!log_mutex) {
|
||||
std::wstring safe_name;
|
||||
if (new_log_file)
|
||||
safe_name = new_log_file;
|
||||
else
|
||||
safe_name = GetDefaultLogFile();
|
||||
// \ is not a legal character in mutex names so we replace \ with /
|
||||
std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
|
||||
std::wstring t(L"Global\\");
|
||||
t.append(safe_name);
|
||||
log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
|
||||
|
||||
if (log_mutex == NULL) {
|
||||
#if DEBUG
|
||||
// Keep the error code for debugging
|
||||
int error = GetLastError(); // NOLINT
|
||||
base::debug::BreakDebugger();
|
||||
#endif
|
||||
// Return nicely without putting initialized to true.
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
log_lock = new base::internal::LockImpl();
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private:
|
||||
static void LockLogging() {
|
||||
if (lock_log_file == LOCK_LOG_FILE) {
|
||||
#if defined(OS_WIN)
|
||||
::WaitForSingleObject(log_mutex, INFINITE);
|
||||
// WaitForSingleObject could have returned WAIT_ABANDONED. We don't
|
||||
// abort the process here. UI tests might be crashy sometimes,
|
||||
// and aborting the test binary only makes the problem worse.
|
||||
// We also don't use LOG macros because that might lead to an infinite
|
||||
// loop. For more info see http://crbug.com/18028.
|
||||
#elif defined(OS_POSIX)
|
||||
pthread_mutex_lock(&log_mutex);
|
||||
#endif
|
||||
} else {
|
||||
// use the lock
|
||||
log_lock->Lock();
|
||||
}
|
||||
}
|
||||
|
||||
static void UnlockLogging() {
|
||||
if (lock_log_file == LOCK_LOG_FILE) {
|
||||
#if defined(OS_WIN)
|
||||
ReleaseMutex(log_mutex);
|
||||
#elif defined(OS_POSIX)
|
||||
pthread_mutex_unlock(&log_mutex);
|
||||
#endif
|
||||
} else {
|
||||
log_lock->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// The lock is used if log file locking is false. It helps us avoid problems
|
||||
// with multiple threads writing to the log file at the same time. Use
|
||||
// LockImpl directly instead of using Lock, because Lock makes logging calls.
|
||||
static base::internal::LockImpl* log_lock;
|
||||
|
||||
// When we don't use a lock, we are using a global mutex. We need to do this
|
||||
// because LockFileEx is not thread safe.
|
||||
#if defined(OS_WIN)
|
||||
static MutexHandle log_mutex;
|
||||
#elif defined(OS_POSIX)
|
||||
static pthread_mutex_t log_mutex;
|
||||
#endif
|
||||
|
||||
static bool initialized;
|
||||
static LogLockingState lock_log_file;
|
||||
};
|
||||
|
||||
// static
|
||||
bool LoggingLock::initialized = false;
|
||||
// static
|
||||
base::internal::LockImpl* LoggingLock::log_lock = NULL;
|
||||
// static
|
||||
LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// static
|
||||
MutexHandle LoggingLock::log_mutex = NULL;
|
||||
#elif defined(OS_POSIX)
|
||||
pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
// Called by logging functions to ensure that debug_file is initialized
|
||||
// and can be used for writing. Returns false if the file could not be
|
||||
// initialized. debug_file will be NULL in this case.
|
||||
bool InitializeLogFileHandle() {
|
||||
if (log_file)
|
||||
return true;
|
||||
|
||||
if (!log_file_name) {
|
||||
// Nobody has called InitLogging to specify a debug log file, so here we
|
||||
// initialize the log file name to a default.
|
||||
log_file_name = new PathString(GetDefaultLogFile());
|
||||
}
|
||||
|
||||
if ((logging_destination & LOG_TO_FILE) != 0) {
|
||||
#if defined(OS_WIN)
|
||||
log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
|
||||
// try the current directory
|
||||
log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
|
||||
log_file = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SetFilePointer(log_file, 0, 0, FILE_END);
|
||||
#elif defined(OS_POSIX)
|
||||
log_file = fopen(log_file_name->c_str(), "a");
|
||||
if (log_file == NULL)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CloseFile(FileHandle log) {
|
||||
#if defined(OS_WIN)
|
||||
CloseHandle(log);
|
||||
#else
|
||||
fclose(log);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CloseLogFileUnlocked() {
|
||||
if (!log_file)
|
||||
return;
|
||||
|
||||
CloseFile(log_file);
|
||||
log_file = NULL;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
LoggingSettings::LoggingSettings()
|
||||
: logging_dest(LOG_DEFAULT),
|
||||
log_file(NULL),
|
||||
lock_log(LOCK_LOG_FILE),
|
||||
delete_old(APPEND_TO_OLD_LOG_FILE),
|
||||
dcheck_state(DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) {}
|
||||
|
||||
bool BaseInitLoggingImpl(const LoggingSettings& settings) {
|
||||
#if defined(OS_NACL)
|
||||
// Can log only to the system debug log.
|
||||
CHECK_EQ(settings.logging_dest & ~LOG_TO_SYSTEM_DEBUG_LOG, 0);
|
||||
#endif
|
||||
g_dcheck_state = settings.dcheck_state;
|
||||
CommandLine* command_line = CommandLine::ForCurrentProcess();
|
||||
// Don't bother initializing g_vlog_info unless we use one of the
|
||||
// vlog switches.
|
||||
if (command_line->HasSwitch(switches::kV) ||
|
||||
command_line->HasSwitch(switches::kVModule)) {
|
||||
// NOTE: If g_vlog_info has already been initialized, it might be in use
|
||||
// by another thread. Don't delete the old VLogInfo, just create a second
|
||||
// one. We keep track of both to avoid memory leak warnings.
|
||||
CHECK(!g_vlog_info_prev);
|
||||
g_vlog_info_prev = g_vlog_info;
|
||||
|
||||
g_vlog_info =
|
||||
new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
|
||||
command_line->GetSwitchValueASCII(switches::kVModule),
|
||||
&min_log_level);
|
||||
}
|
||||
|
||||
logging_destination = settings.logging_dest;
|
||||
|
||||
// ignore file options unless logging to file is set.
|
||||
if ((logging_destination & LOG_TO_FILE) == 0)
|
||||
return true;
|
||||
|
||||
LoggingLock::Init(settings.lock_log, settings.log_file);
|
||||
LoggingLock logging_lock;
|
||||
|
||||
// Calling InitLogging twice or after some log call has already opened the
|
||||
// default log file will re-initialize to the new options.
|
||||
CloseLogFileUnlocked();
|
||||
|
||||
if (!log_file_name)
|
||||
log_file_name = new PathString();
|
||||
*log_file_name = settings.log_file;
|
||||
if (settings.delete_old == DELETE_OLD_LOG_FILE)
|
||||
DeleteFilePath(*log_file_name);
|
||||
|
||||
return InitializeLogFileHandle();
|
||||
}
|
||||
|
||||
void SetMinLogLevel(int level) {
|
||||
min_log_level = std::min(LOG_ERROR_REPORT, level);
|
||||
}
|
||||
|
||||
int GetMinLogLevel() {
|
||||
return min_log_level;
|
||||
}
|
||||
|
||||
int GetVlogVerbosity() {
|
||||
return std::max(-1, LOG_INFO - GetMinLogLevel());
|
||||
}
|
||||
|
||||
int GetVlogLevelHelper(const char* file, size_t N) {
|
||||
DCHECK_GT(N, 0U);
|
||||
// Note: g_vlog_info may change on a different thread during startup
|
||||
// (but will always be valid or NULL).
|
||||
VlogInfo* vlog_info = g_vlog_info;
|
||||
return vlog_info ?
|
||||
vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) :
|
||||
GetVlogVerbosity();
|
||||
}
|
||||
|
||||
void SetLogItems(bool enable_process_id, bool enable_thread_id,
|
||||
bool enable_timestamp, bool enable_tickcount) {
|
||||
log_process_id = enable_process_id;
|
||||
log_thread_id = enable_thread_id;
|
||||
log_timestamp = enable_timestamp;
|
||||
log_tickcount = enable_tickcount;
|
||||
}
|
||||
|
||||
void SetShowErrorDialogs(bool enable_dialogs) {
|
||||
show_error_dialogs = enable_dialogs;
|
||||
}
|
||||
|
||||
void SetLogAssertHandler(LogAssertHandlerFunction handler) {
|
||||
log_assert_handler = handler;
|
||||
}
|
||||
|
||||
void SetLogReportHandler(LogReportHandlerFunction handler) {
|
||||
log_report_handler = handler;
|
||||
}
|
||||
|
||||
void SetLogMessageHandler(LogMessageHandlerFunction handler) {
|
||||
log_message_handler = handler;
|
||||
}
|
||||
|
||||
LogMessageHandlerFunction GetLogMessageHandler() {
|
||||
return log_message_handler;
|
||||
}
|
||||
|
||||
// MSVC doesn't like complex extern templates and DLLs.
|
||||
#if !defined(COMPILER_MSVC)
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// Displays a message box to the user with the error message in it.
|
||||
// Used for fatal messages, where we close the app simultaneously.
|
||||
// This is for developers only; we don't use this in circumstances
|
||||
// (like release builds) where users could see it, since users don't
|
||||
// understand these messages anyway.
|
||||
void DisplayDebugMessageInDialog(const std::string& str) {
|
||||
if (str.empty())
|
||||
return;
|
||||
|
||||
if (!show_error_dialogs)
|
||||
return;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// For Windows programs, it's possible that the message loop is
|
||||
// messed up on a fatal error, and creating a MessageBox will cause
|
||||
// that message loop to be run. Instead, we try to spawn another
|
||||
// process that displays its command line. We look for "Debug
|
||||
// Message.exe" in the same directory as the application. If it
|
||||
// exists, we use it, otherwise, we use a regular message box.
|
||||
wchar_t prog_name[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, prog_name, MAX_PATH);
|
||||
wchar_t* backslash = wcsrchr(prog_name, '\\');
|
||||
if (backslash)
|
||||
backslash[1] = 0;
|
||||
wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
|
||||
|
||||
std::wstring cmdline = UTF8ToWide(str);
|
||||
if (cmdline.empty())
|
||||
return;
|
||||
|
||||
STARTUPINFO startup_info;
|
||||
memset(&startup_info, 0, sizeof(startup_info));
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL,
|
||||
NULL, &startup_info, &process_info)) {
|
||||
WaitForSingleObject(process_info.hProcess, INFINITE);
|
||||
CloseHandle(process_info.hThread);
|
||||
CloseHandle(process_info.hProcess);
|
||||
} else {
|
||||
// debug process broken, let's just do a message box
|
||||
MessageBoxW(NULL, &cmdline[0], L"Fatal error",
|
||||
MB_OK | MB_ICONHAND | MB_TOPMOST);
|
||||
}
|
||||
#else
|
||||
// We intentionally don't implement a dialog on other platforms.
|
||||
// You can just look at stderr.
|
||||
#endif
|
||||
}
|
||||
|
||||
#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,
|
||||
int ctr)
|
||||
: severity_(severity), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line)
|
||||
: severity_(LOG_INFO), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
|
||||
: severity_(severity), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, std::string* result)
|
||||
: severity_(LOG_FATAL), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
stream_ << "Check failed: " << *result;
|
||||
delete result;
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
|
||||
std::string* result)
|
||||
: severity_(severity), file_(file), line_(line) {
|
||||
Init(file, line);
|
||||
stream_ << "Check failed: " << *result;
|
||||
delete result;
|
||||
}
|
||||
|
||||
LogMessage::~LogMessage() {
|
||||
#if !defined(NDEBUG) && !defined(OS_NACL)
|
||||
if (severity_ == LOG_FATAL) {
|
||||
// Include a stack trace on a fatal.
|
||||
base::debug::StackTrace trace;
|
||||
stream_ << std::endl; // Newline to separate from log message.
|
||||
trace.OutputToStream(&stream_);
|
||||
}
|
||||
#endif
|
||||
stream_ << std::endl;
|
||||
std::string str_newline(stream_.str());
|
||||
|
||||
// Give any log message handler first dibs on the message.
|
||||
if (log_message_handler &&
|
||||
log_message_handler(severity_, file_, line_,
|
||||
message_start_, str_newline)) {
|
||||
// The handler took care of it, no further processing.
|
||||
return;
|
||||
}
|
||||
|
||||
if ((logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
|
||||
#if defined(OS_WIN)
|
||||
OutputDebugStringA(str_newline.c_str());
|
||||
#elif defined(OS_ANDROID)
|
||||
android_LogPriority priority =
|
||||
(severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
|
||||
switch (severity_) {
|
||||
case LOG_INFO:
|
||||
priority = ANDROID_LOG_INFO;
|
||||
break;
|
||||
case LOG_WARNING:
|
||||
priority = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case LOG_ERROR:
|
||||
case LOG_ERROR_REPORT:
|
||||
priority = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
case LOG_FATAL:
|
||||
priority = ANDROID_LOG_FATAL;
|
||||
break;
|
||||
}
|
||||
__android_log_write(priority, "chromium", str_newline.c_str());
|
||||
#endif
|
||||
fprintf(stderr, "%s", str_newline.c_str());
|
||||
fflush(stderr);
|
||||
} else if (severity_ >= kAlwaysPrintErrorLevel) {
|
||||
// When we're only outputting to a log file, above a certain log level, we
|
||||
// should still output to stderr so that we can better detect and diagnose
|
||||
// problems with unit tests, especially on the buildbots.
|
||||
fprintf(stderr, "%s", str_newline.c_str());
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
// write to log file
|
||||
if ((logging_destination & LOG_TO_FILE) != 0) {
|
||||
// We can have multiple threads and/or processes, so try to prevent them
|
||||
// from clobbering each other's writes.
|
||||
// If the client app did not call InitLogging, and the lock has not
|
||||
// been created do it now. We do this on demand, but if two threads try
|
||||
// to do this at the same time, there will be a race condition to create
|
||||
// the lock. This is why InitLogging should be called from the main
|
||||
// thread at the beginning of execution.
|
||||
LoggingLock::Init(LOCK_LOG_FILE, NULL);
|
||||
LoggingLock logging_lock;
|
||||
if (InitializeLogFileHandle()) {
|
||||
#if defined(OS_WIN)
|
||||
SetFilePointer(log_file, 0, 0, SEEK_END);
|
||||
DWORD num_written;
|
||||
WriteFile(log_file,
|
||||
static_cast<const void*>(str_newline.c_str()),
|
||||
static_cast<DWORD>(str_newline.length()),
|
||||
&num_written,
|
||||
NULL);
|
||||
#else
|
||||
fprintf(log_file, "%s", str_newline.c_str());
|
||||
fflush(log_file);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (severity_ == LOG_FATAL) {
|
||||
// Ensure the first characters of the string are on the stack so they
|
||||
// are contained in minidumps for diagnostic purposes.
|
||||
char str_stack[1024];
|
||||
str_newline.copy(str_stack, arraysize(str_stack));
|
||||
base::debug::Alias(str_stack);
|
||||
|
||||
// display a message or break into the debugger on a fatal error
|
||||
if (base::debug::BeingDebugged()) {
|
||||
base::debug::BreakDebugger();
|
||||
} else {
|
||||
if (log_assert_handler) {
|
||||
// make a copy of the string for the handler out of paranoia
|
||||
log_assert_handler(std::string(stream_.str()));
|
||||
} else {
|
||||
// Don't use the string with the newline, get a fresh version to send to
|
||||
// the debug message process. We also don't display assertions to the
|
||||
// user in release mode. The enduser can't do anything with this
|
||||
// information, and displaying message boxes when the application is
|
||||
// hosed can cause additional problems.
|
||||
#ifndef NDEBUG
|
||||
DisplayDebugMessageInDialog(stream_.str());
|
||||
#endif
|
||||
// Crash the process to generate a dump.
|
||||
base::debug::BreakDebugger();
|
||||
}
|
||||
}
|
||||
} else if (severity_ == LOG_ERROR_REPORT) {
|
||||
// We are here only if the user runs with --enable-dcheck in release mode.
|
||||
if (log_report_handler) {
|
||||
log_report_handler(std::string(stream_.str()));
|
||||
} else {
|
||||
DisplayDebugMessageInDialog(stream_.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// writes the common header info to the stream
|
||||
void LogMessage::Init(const char* file, int line) {
|
||||
base::StringPiece filename(file);
|
||||
size_t last_slash_pos = filename.find_last_of("\\/");
|
||||
if (last_slash_pos != base::StringPiece::npos)
|
||||
filename.remove_prefix(last_slash_pos + 1);
|
||||
|
||||
// TODO(darin): It might be nice if the columns were fixed width.
|
||||
|
||||
stream_ << '[';
|
||||
if (log_process_id)
|
||||
stream_ << CurrentProcessId() << ':';
|
||||
if (log_thread_id)
|
||||
stream_ << base::PlatformThread::CurrentId() << ':';
|
||||
if (log_timestamp) {
|
||||
time_t t = time(NULL);
|
||||
struct tm local_time = {0};
|
||||
#if _MSC_VER >= 1400
|
||||
localtime_s(&local_time, &t);
|
||||
#else
|
||||
localtime_r(&t, &local_time);
|
||||
#endif
|
||||
struct tm* tm_time = &local_time;
|
||||
stream_ << std::setfill('0')
|
||||
<< std::setw(2) << 1 + tm_time->tm_mon
|
||||
<< std::setw(2) << tm_time->tm_mday
|
||||
<< '/'
|
||||
<< std::setw(2) << tm_time->tm_hour
|
||||
<< std::setw(2) << tm_time->tm_min
|
||||
<< std::setw(2) << tm_time->tm_sec
|
||||
<< ':';
|
||||
}
|
||||
if (log_tickcount)
|
||||
stream_ << TickCount() << ':';
|
||||
if (severity_ >= 0)
|
||||
stream_ << log_severity_names[severity_];
|
||||
else
|
||||
stream_ << "VERBOSE" << -severity_;
|
||||
|
||||
stream_ << ":" << filename << "(" << line << ")] ";
|
||||
|
||||
message_start_ = stream_.tellp();
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// This has already been defined in the header, but defining it again as DWORD
|
||||
// ensures that the type used in the header is equivalent to DWORD. If not,
|
||||
// the redefinition is a compile error.
|
||||
typedef DWORD SystemErrorCode;
|
||||
#endif
|
||||
|
||||
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,
|
||||
const char* module)
|
||||
: err_(err),
|
||||
module_(module),
|
||||
log_message_(file, line, severity) {
|
||||
}
|
||||
|
||||
Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
|
||||
int line,
|
||||
LogSeverity severity,
|
||||
SystemErrorCode err)
|
||||
: err_(err),
|
||||
module_(NULL),
|
||||
log_message_(file, line, severity) {
|
||||
}
|
||||
|
||||
Win32ErrorLogMessage::~Win32ErrorLogMessage() {
|
||||
const int error_message_buffer_size = 256;
|
||||
char msgbuf[error_message_buffer_size];
|
||||
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
HMODULE hmod;
|
||||
if (module_) {
|
||||
hmod = GetModuleHandleA(module_);
|
||||
if (hmod) {
|
||||
flags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||||
} else {
|
||||
// This makes a nested Win32ErrorLogMessage. It will have module_ of NULL
|
||||
// so it will not call GetModuleHandle, so recursive errors are
|
||||
// impossible.
|
||||
DPLOG(WARNING) << "Couldn't open module " << module_
|
||||
<< " for error message query";
|
||||
}
|
||||
} else {
|
||||
hmod = NULL;
|
||||
}
|
||||
DWORD len = FormatMessageA(flags,
|
||||
hmod,
|
||||
err_,
|
||||
0,
|
||||
msgbuf,
|
||||
sizeof(msgbuf) / sizeof(msgbuf[0]),
|
||||
NULL);
|
||||
if (len) {
|
||||
while ((len > 0) &&
|
||||
isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
|
||||
msgbuf[--len] = 0;
|
||||
}
|
||||
stream() << ": " << msgbuf;
|
||||
} else {
|
||||
stream() << ": Error " << GetLastError() << " while retrieving error "
|
||||
<< err_;
|
||||
}
|
||||
// We're about to crash (CHECK). Put |err_| on the stack (by placing it in a
|
||||
// field) and use Alias in hopes that it makes it into crash dumps.
|
||||
DWORD last_error = err_;
|
||||
base::debug::Alias(&last_error);
|
||||
}
|
||||
#elif defined(OS_POSIX)
|
||||
ErrnoLogMessage::ErrnoLogMessage(const char* file,
|
||||
int line,
|
||||
LogSeverity severity,
|
||||
SystemErrorCode err)
|
||||
: err_(err),
|
||||
log_message_(file, line, severity) {
|
||||
}
|
||||
|
||||
ErrnoLogMessage::~ErrnoLogMessage() {
|
||||
stream() << ": " << safe_strerror(err_);
|
||||
}
|
||||
#endif // OS_WIN
|
||||
|
||||
void CloseLogFile() {
|
||||
LoggingLock logging_lock;
|
||||
CloseLogFileUnlocked();
|
||||
}
|
||||
|
||||
void RawLog(int level, const char* message) {
|
||||
if (level >= min_log_level) {
|
||||
size_t bytes_written = 0;
|
||||
const size_t message_len = strlen(message);
|
||||
int rv;
|
||||
while (bytes_written < message_len) {
|
||||
rv = HANDLE_EINTR(
|
||||
write(STDERR_FILENO, message + bytes_written,
|
||||
message_len - bytes_written));
|
||||
if (rv < 0) {
|
||||
// Give up, nothing we can do now.
|
||||
break;
|
||||
}
|
||||
bytes_written += rv;
|
||||
}
|
||||
|
||||
if (message_len > 0 && message[message_len - 1] != '\n') {
|
||||
do {
|
||||
rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
|
||||
if (rv < 0) {
|
||||
// Give up, nothing we can do now.
|
||||
break;
|
||||
}
|
||||
} while (rv != 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (level == LOG_FATAL)
|
||||
base::debug::BreakDebugger();
|
||||
}
|
||||
|
||||
// This was defined at the beginning of this file.
|
||||
#undef write
|
||||
|
||||
#if defined(OS_WIN)
|
||||
std::wstring GetLogFileFullPath() {
|
||||
if (log_file_name)
|
||||
return *log_file_name;
|
||||
return std::wstring();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace logging
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
|
||||
return out << WideToUTF8(std::wstring(wstr));
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,139 @@
|
|||
// 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/logging_win.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include <initguid.h> // NOLINT
|
||||
|
||||
namespace logging {
|
||||
|
||||
using base::win::EtwEventLevel;
|
||||
using base::win::EtwMofEvent;
|
||||
|
||||
DEFINE_GUID(kLogEventId,
|
||||
0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7);
|
||||
|
||||
LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) {
|
||||
}
|
||||
|
||||
LogEventProvider* LogEventProvider::GetInstance() {
|
||||
return Singleton<LogEventProvider,
|
||||
StaticMemorySingletonTraits<LogEventProvider> >::get();
|
||||
}
|
||||
|
||||
bool LogEventProvider::LogMessage(logging::LogSeverity severity,
|
||||
const char* file, int line, size_t message_start,
|
||||
const std::string& message) {
|
||||
EtwEventLevel level = TRACE_LEVEL_NONE;
|
||||
|
||||
// Convert the log severity to the most appropriate ETW trace level.
|
||||
if (severity >= 0) {
|
||||
switch (severity) {
|
||||
case LOG_INFO:
|
||||
level = TRACE_LEVEL_INFORMATION;
|
||||
break;
|
||||
case LOG_WARNING:
|
||||
level = TRACE_LEVEL_WARNING;
|
||||
break;
|
||||
case LOG_ERROR:
|
||||
case LOG_ERROR_REPORT:
|
||||
level = TRACE_LEVEL_ERROR;
|
||||
break;
|
||||
case LOG_FATAL:
|
||||
level = TRACE_LEVEL_FATAL;
|
||||
break;
|
||||
}
|
||||
} else { // severity < 0 is VLOG verbosity levels.
|
||||
level = TRACE_LEVEL_INFORMATION - severity;
|
||||
}
|
||||
|
||||
// Bail if we're not logging, not at that level,
|
||||
// or if we're post-atexit handling.
|
||||
LogEventProvider* provider = LogEventProvider::GetInstance();
|
||||
if (provider == NULL || level > provider->enable_level())
|
||||
return false;
|
||||
|
||||
// And now log the event.
|
||||
if (provider->enable_flags() & ENABLE_LOG_MESSAGE_ONLY) {
|
||||
EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level);
|
||||
event.SetField(0, message.length() + 1 - message_start,
|
||||
message.c_str() + message_start);
|
||||
|
||||
provider->Log(event.get());
|
||||
} else {
|
||||
const size_t kMaxBacktraceDepth = 32;
|
||||
void* backtrace[kMaxBacktraceDepth];
|
||||
DWORD depth = 0;
|
||||
|
||||
// Capture a stack trace if one is requested.
|
||||
// requested per our enable flags.
|
||||
if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE)
|
||||
depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL);
|
||||
|
||||
EtwMofEvent<5> event(kLogEventId, LOG_MESSAGE_FULL, level);
|
||||
if (file == NULL)
|
||||
file = "";
|
||||
|
||||
// Add the stack trace.
|
||||
event.SetField(0, sizeof(depth), &depth);
|
||||
event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace);
|
||||
// The line.
|
||||
event.SetField(2, sizeof(line), &line);
|
||||
// The file.
|
||||
event.SetField(3, strlen(file) + 1, file);
|
||||
// And finally the message.
|
||||
event.SetField(4, message.length() + 1 - message_start,
|
||||
message.c_str() + message_start);
|
||||
|
||||
provider->Log(event.get());
|
||||
}
|
||||
|
||||
// Don't increase verbosity in other log destinations.
|
||||
if (severity < provider->old_log_level_)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LogEventProvider::Initialize(const GUID& provider_name) {
|
||||
LogEventProvider* provider = LogEventProvider::GetInstance();
|
||||
|
||||
provider->set_provider_name(provider_name);
|
||||
provider->Register();
|
||||
|
||||
// Register our message handler with logging.
|
||||
SetLogMessageHandler(LogMessage);
|
||||
}
|
||||
|
||||
void LogEventProvider::Uninitialize() {
|
||||
LogEventProvider::GetInstance()->Unregister();
|
||||
}
|
||||
|
||||
void LogEventProvider::OnEventsEnabled() {
|
||||
// Grab the old log level so we can restore it later.
|
||||
old_log_level_ = GetMinLogLevel();
|
||||
|
||||
// Convert the new trace level to a logging severity
|
||||
// and enable logging at that level.
|
||||
EtwEventLevel level = enable_level();
|
||||
if (level == TRACE_LEVEL_NONE || level == TRACE_LEVEL_FATAL) {
|
||||
SetMinLogLevel(LOG_FATAL);
|
||||
} else if (level == TRACE_LEVEL_ERROR) {
|
||||
SetMinLogLevel(LOG_ERROR);
|
||||
} else if (level == TRACE_LEVEL_WARNING) {
|
||||
SetMinLogLevel(LOG_WARNING);
|
||||
} else if (level == TRACE_LEVEL_INFORMATION) {
|
||||
SetMinLogLevel(LOG_INFO);
|
||||
} else if (level >= TRACE_LEVEL_VERBOSE) {
|
||||
// Above INFO, we enable verbose levels with negative severities.
|
||||
SetMinLogLevel(TRACE_LEVEL_INFORMATION - level);
|
||||
}
|
||||
}
|
||||
|
||||
void LogEventProvider::OnEventsDisabled() {
|
||||
// Restore the old log level.
|
||||
SetMinLogLevel(old_log_level_);
|
||||
}
|
||||
|
||||
} // namespace logging
|
|
@ -0,0 +1,80 @@
|
|||
// 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_WIN_H_
|
||||
#define BASE_LOGGING_WIN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/win/event_trace_provider.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
template <typename Type>
|
||||
struct StaticMemorySingletonTraits;
|
||||
|
||||
namespace logging {
|
||||
|
||||
// Event ID for the log messages we generate.
|
||||
EXTERN_C BASE_EXPORT const GUID kLogEventId;
|
||||
|
||||
// Feature enable mask for LogEventProvider.
|
||||
enum LogEnableMask {
|
||||
// If this bit is set in our provider enable mask, we will include
|
||||
// a stack trace with every log message.
|
||||
ENABLE_STACK_TRACE_CAPTURE = 0x0001,
|
||||
// If this bit is set in our provider enable mask, the provider will log
|
||||
// a LOG message with only the textual content of the message, and no
|
||||
// stack trace.
|
||||
ENABLE_LOG_MESSAGE_ONLY = 0x0002,
|
||||
};
|
||||
|
||||
// The message types our log event provider generates.
|
||||
// ETW likes user message types to start at 10.
|
||||
enum LogMessageTypes {
|
||||
// A textual only log message, contains a zero-terminated string.
|
||||
LOG_MESSAGE = 10,
|
||||
// A message with a stack trace, followed by the zero-terminated
|
||||
// message text.
|
||||
LOG_MESSAGE_WITH_STACKTRACE = 11,
|
||||
// A message with:
|
||||
// a stack trace,
|
||||
// the line number as a four byte integer,
|
||||
// the file as a zero terminated UTF8 string,
|
||||
// the zero-terminated UTF8 message text.
|
||||
LOG_MESSAGE_FULL = 12,
|
||||
};
|
||||
|
||||
// Trace provider class to drive log control and transport
|
||||
// with Event Tracing for Windows.
|
||||
class BASE_EXPORT LogEventProvider : public base::win::EtwTraceProvider {
|
||||
public:
|
||||
static LogEventProvider* GetInstance();
|
||||
|
||||
static bool LogMessage(logging::LogSeverity severity, const char* file,
|
||||
int line, size_t message_start, const std::string& str);
|
||||
|
||||
static void Initialize(const GUID& provider_name);
|
||||
static void Uninitialize();
|
||||
|
||||
protected:
|
||||
// Overridden to manipulate the log level on ETW control callbacks.
|
||||
virtual void OnEventsEnabled();
|
||||
virtual void OnEventsDisabled();
|
||||
|
||||
private:
|
||||
LogEventProvider();
|
||||
|
||||
// The log severity prior to OnEventsEnabled,
|
||||
// restored in OnEventsDisabled.
|
||||
logging::LogSeverity old_log_level_;
|
||||
|
||||
friend struct StaticMemorySingletonTraits<LogEventProvider>;
|
||||
DISALLOW_COPY_AND_ASSIGN(LogEventProvider);
|
||||
};
|
||||
|
||||
} // namespace logging
|
||||
|
||||
#endif // BASE_LOGGING_WIN_H_
|
|
@ -0,0 +1,114 @@
|
|||
// 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_malloc:
|
||||
//
|
||||
// scoped_ptr_malloc<float, ScopedPtrAlignedFree> my_array(
|
||||
// static_cast<float*>(AlignedAlloc(size, alignment)));
|
||||
|
||||
#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
|
||||
#define BASE_MEMORY_ALIGNED_MEMORY_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.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 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
|
||||
}
|
||||
|
||||
// Helper class for use with scoped_ptr_malloc.
|
||||
class BASE_EXPORT ScopedPtrAlignedFree {
|
||||
public:
|
||||
inline void operator()(void* ptr) const {
|
||||
AlignedFree(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_ALIGNED_MEMORY_H_
|
|
@ -0,0 +1,129 @@
|
|||
// 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<Tuple0> {
|
||||
enum { value = 1 };
|
||||
};
|
||||
|
||||
template <typename A>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple1<A> > {
|
||||
enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple2<A, B> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple3<A, B, C> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple4<A, B, C, D> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple5<A, B, C, D, E> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<E>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E,
|
||||
typename F>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple6<A, B, C, D, E, F> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<E>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<F>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E,
|
||||
typename F, typename G>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple7<A, B, C, D, E, F, G> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<E>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<F>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<G>::value) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E,
|
||||
typename F, typename G, typename H>
|
||||
struct ParamsUseScopedRefptrCorrectly<Tuple8<A, B, C, D, E, F, G, H> > {
|
||||
enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<B>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<C>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<D>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<E>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<F>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<G>::value ||
|
||||
NeedsScopedRefptrButGetsRawPtr<H>::value) };
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
|
|
@ -0,0 +1,95 @@
|
|||
// 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/logging.h"
|
||||
#include "base/threading/thread_collision_warner.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace subtle {
|
||||
|
||||
RefCountedBase::RefCountedBase()
|
||||
: ref_count_(0)
|
||||
#ifndef NDEBUG
|
||||
, in_dtor_(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
RefCountedBase::~RefCountedBase() {
|
||||
#ifndef NDEBUG
|
||||
DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
|
||||
#endif
|
||||
}
|
||||
|
||||
void RefCountedBase::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_;
|
||||
}
|
||||
|
||||
bool RefCountedBase::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;
|
||||
}
|
||||
|
||||
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
|
|
@ -0,0 +1,301 @@
|
|||
// 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 "base/atomic_ref_count.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/threading/thread_collision_warner.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace subtle {
|
||||
|
||||
class BASE_EXPORT RefCountedBase {
|
||||
public:
|
||||
bool HasOneRef() const { return ref_count_ == 1; }
|
||||
|
||||
protected:
|
||||
RefCountedBase();
|
||||
~RefCountedBase();
|
||||
|
||||
void AddRef() const;
|
||||
|
||||
// Returns true if the object should self-delete.
|
||||
bool Release() const;
|
||||
|
||||
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 private, 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_)
|
||||
ptr_->AddRef();
|
||||
}
|
||||
|
||||
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
|
||||
if (ptr_)
|
||||
ptr_->AddRef();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
|
||||
if (ptr_)
|
||||
ptr_->AddRef();
|
||||
}
|
||||
|
||||
~scoped_refptr() {
|
||||
if (ptr_)
|
||||
ptr_->Release();
|
||||
}
|
||||
|
||||
T* get() const { return ptr_; }
|
||||
operator T*() const { 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)
|
||||
p->AddRef();
|
||||
T* old_ptr = ptr_;
|
||||
ptr_ = p;
|
||||
if (old_ptr)
|
||||
old_ptr->Release();
|
||||
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();
|
||||
}
|
||||
|
||||
void swap(T** pp) {
|
||||
T* p = ptr_;
|
||||
ptr_ = *pp;
|
||||
*pp = p;
|
||||
}
|
||||
|
||||
void swap(scoped_refptr<T>& r) {
|
||||
swap(&r.ptr_);
|
||||
}
|
||||
|
||||
protected:
|
||||
T* ptr_;
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
#endif // BASE_MEMORY_REF_COUNTED_H_
|
|
@ -0,0 +1,709 @@
|
|||
// 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 the
|
||||
// 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 the result of an analogous
|
||||
// scoper's Pass() function or another function that generates a temporary;
|
||||
// passing by copy will NOT work. Here is an example using scoped_ptr:
|
||||
//
|
||||
// void TakesOwnership(scoped_ptr<Foo> arg) {
|
||||
// // Do something with arg
|
||||
// }
|
||||
// scoped_ptr<Foo> CreateFoo() {
|
||||
// // No need for calling Pass() because we are constructing a temporary
|
||||
// // for the return value.
|
||||
// return scoped_ptr<Foo>(new Foo("new"));
|
||||
// }
|
||||
// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
|
||||
// return arg.Pass();
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
|
||||
// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
|
||||
// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
|
||||
// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
|
||||
// PassThru(ptr2.Pass()); // ptr2 is correspondingly NULL.
|
||||
// }
|
||||
//
|
||||
// Notice that if you do not call Pass() when returning from PassThru(), or
|
||||
// when invoking TakesOwnership(), the code will not compile because scopers
|
||||
// are not copyable; they only implement move semantics which require calling
|
||||
// the Pass() function to signify a destructive transfer of state. CreateFoo()
|
||||
// is different though because we are constructing a temporary on the return
|
||||
// line and thus can avoid needing to call Pass().
|
||||
//
|
||||
// Pass() properly handles upcast in assignment, i.e. you can assign
|
||||
// scoped_ptr<Child> to scoped_ptr<Parent>:
|
||||
//
|
||||
// scoped_ptr<Foo> foo(new Foo());
|
||||
// scoped_ptr<FooParent> parent = foo.Pass();
|
||||
//
|
||||
// PassAs<>() should be used to upcast return value in return statement:
|
||||
//
|
||||
// scoped_ptr<Foo> CreateFoo() {
|
||||
// scoped_ptr<FooChild> result(new FooChild());
|
||||
// return result.PassAs<Foo>();
|
||||
// }
|
||||
//
|
||||
// Note that PassAs<>() is implemented only for scoped_ptr<T>, but not for
|
||||
// scoped_ptr<T[]>. This is because casting array pointers may not be safe.
|
||||
|
||||
#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 and scoped_ptr_malloc (deprecated).
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm> // For std::swap().
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/move.h"
|
||||
#include "base/template_util.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace subtle {
|
||||
class RefCountedBase;
|
||||
class RefCountedThreadSafeBase;
|
||||
} // namespace subtle
|
||||
|
||||
// Function object which deletes its parameter, which must be a pointer.
|
||||
// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
|
||||
// invokes 'delete'. The default deleter for scoped_ptr<T>.
|
||||
template <class T>
|
||||
struct DefaultDeleter {
|
||||
DefaultDeleter() {}
|
||||
template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
|
||||
// IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
|
||||
// if U* is implicitly convertible to T* and U is not an array type.
|
||||
//
|
||||
// Correct implementation should use SFINAE to disable this
|
||||
// constructor. However, since there are no other 1-argument constructors,
|
||||
// using a COMPILE_ASSERT() based on is_convertible<> and requiring
|
||||
// complete types is simpler and will cause compile failures for equivalent
|
||||
// misuses.
|
||||
//
|
||||
// Note, the is_convertible<U*, T*> check also ensures that U is not an
|
||||
// array. T is guaranteed to be a non-array, so any U* where U is an array
|
||||
// cannot convert to T*.
|
||||
enum { T_must_be_complete = sizeof(T) };
|
||||
enum { U_must_be_complete = sizeof(U) };
|
||||
COMPILE_ASSERT((base::is_convertible<U*, T*>::value),
|
||||
U_ptr_must_implicitly_convert_to_T_ptr);
|
||||
}
|
||||
inline void operator()(T* ptr) const {
|
||||
enum { type_must_be_complete = sizeof(T) };
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of DefaultDeleter for array types.
|
||||
template <class T>
|
||||
struct DefaultDeleter<T[]> {
|
||||
inline void operator()(T* ptr) const {
|
||||
enum { type_must_be_complete = sizeof(T) };
|
||||
delete[] ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// Disable this operator for any U != T because it is undefined to execute
|
||||
// an array delete when the static type of the array mismatches the dynamic
|
||||
// type.
|
||||
//
|
||||
// References:
|
||||
// C++98 [expr.delete]p3
|
||||
// http://cplusplus.github.com/LWG/lwg-defects.html#938
|
||||
template <typename U> void operator()(U* array) const;
|
||||
};
|
||||
|
||||
template <class T, int n>
|
||||
struct DefaultDeleter<T[n]> {
|
||||
// Never allow someone to declare something like scoped_ptr<int[10]>.
|
||||
COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type);
|
||||
};
|
||||
|
||||
// Function object which invokes 'free' on its parameter, which must be
|
||||
// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
|
||||
//
|
||||
// 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() {
|
||||
if (data_.ptr != NULL) {
|
||||
// Not using get_deleter() saves one function call in non-optimized
|
||||
// builds.
|
||||
static_cast<D&>(data_)(data_.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void reset(T* p) {
|
||||
// This is a self-reset, which is no longer allowed: http://crbug.com/162971
|
||||
if (p != NULL && p == data_.ptr)
|
||||
abort();
|
||||
|
||||
// Note that running data_.ptr = p can lead to undefined behavior if
|
||||
// get_deleter()(get()) deletes this. In order to pevent this, reset()
|
||||
// should update the stored pointer before deleting its old value.
|
||||
//
|
||||
// However, changing reset() to use that behavior may cause current code to
|
||||
// break in unexpected ways. If the destruction of the owned object
|
||||
// dereferences the scoped_ptr when it is destroyed by a call to reset(),
|
||||
// then it will incorrectly dispatch calls to |p| rather than the original
|
||||
// value of |data_.ptr|.
|
||||
//
|
||||
// During the transition period, set the stored pointer to NULL while
|
||||
// deleting the object. Eventually, this safety check will be removed to
|
||||
// prevent the scenario initially described from occuring and
|
||||
// http://crbug.com/176091 can be closed.
|
||||
T* old = data_.ptr;
|
||||
data_.ptr = NULL;
|
||||
if (old != NULL)
|
||||
static_cast<D&>(data_)(old);
|
||||
data_.ptr = p;
|
||||
}
|
||||
|
||||
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 = NULL;
|
||||
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 NULL 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
|
||||
// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
|
||||
// increase the size proportional to whatever state they need to have. See
|
||||
// comments inside scoped_ptr_impl<> for details.
|
||||
//
|
||||
// Current implementation targets having a strict subset of C++11's
|
||||
// unique_ptr<> features. Known deficiencies include not supporting move-only
|
||||
// deleteres, function pointers as deleters, and deleters with reference
|
||||
// types.
|
||||
template <class T, class D = base::DefaultDeleter<T> >
|
||||
class scoped_ptr {
|
||||
MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
|
||||
|
||||
COMPILE_ASSERT(base::internal::IsNotRefCounted<T>::value,
|
||||
T_is_refcounted_type_and_needs_scoped_refptr);
|
||||
|
||||
public:
|
||||
// The element and deleter types.
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
|
||||
// Constructor. Defaults to initializing with NULL.
|
||||
scoped_ptr() : impl_(NULL) { }
|
||||
|
||||
// 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 scoped_ptr rvalue for a
|
||||
// convertible type and deleter.
|
||||
//
|
||||
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
|
||||
// from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
|
||||
// has different post-conditions if D is a reference type. Since this
|
||||
// implementation does not support deleters with reference type,
|
||||
// we do not need a separate move constructor allowing us to avoid one
|
||||
// use of SFINAE. You only need to care about this if you modify the
|
||||
// implementation of scoped_ptr.
|
||||
template <typename U, typename V>
|
||||
scoped_ptr(scoped_ptr<U, V> other) : impl_(&other.impl_) {
|
||||
COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
|
||||
}
|
||||
|
||||
// Constructor. Move constructor for C++03 move emulation of this type.
|
||||
scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
|
||||
|
||||
// operator=. Allows assignment from a scoped_ptr rvalue for a convertible
|
||||
// type and deleter.
|
||||
//
|
||||
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
|
||||
// the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
|
||||
// form has different requirements on for move-only Deleters. Since this
|
||||
// implementation does not support move-only Deleters, we do not need a
|
||||
// separate move assignment operator allowing us to avoid one use of SFINAE.
|
||||
// You only need to care about this if you modify the implementation of
|
||||
// scoped_ptr.
|
||||
template <typename U, typename V>
|
||||
scoped_ptr& operator=(scoped_ptr<U, V> rhs) {
|
||||
COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
|
||||
impl_.TakeState(&rhs.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Reset. Deletes the currently owned object, if any.
|
||||
// Then takes ownership of a new object, if given.
|
||||
void reset(element_type* p = NULL) { 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() != NULL);
|
||||
return *impl_.get();
|
||||
}
|
||||
element_type* operator->() const {
|
||||
assert(impl_.get() != NULL);
|
||||
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_ : NULL; }
|
||||
|
||||
// Comparison operators.
|
||||
// These return whether two scoped_ptr refer to the same object, not just to
|
||||
// two different but equal objects.
|
||||
bool operator==(const element_type* p) const { return impl_.get() == p; }
|
||||
bool operator!=(const element_type* p) const { return impl_.get() != p; }
|
||||
|
||||
// Swap two scoped pointers.
|
||||
void swap(scoped_ptr& p2) {
|
||||
impl_.swap(p2.impl_);
|
||||
}
|
||||
|
||||
// Release a pointer.
|
||||
// The return value is the current pointer held by this object.
|
||||
// If this object holds a NULL pointer, the return value is NULL.
|
||||
// After this operation, this object will hold a NULL pointer,
|
||||
// and will not own the object any more.
|
||||
element_type* release() WARN_UNUSED_RESULT {
|
||||
return impl_.release();
|
||||
}
|
||||
|
||||
// C++98 doesn't support functions templates with default parameters which
|
||||
// makes it hard to write a PassAs() that understands converting the deleter
|
||||
// while preserving simple calling semantics.
|
||||
//
|
||||
// Until there is a use case for PassAs() with custom deleters, just ignore
|
||||
// the custom deleter.
|
||||
template <typename PassAsType>
|
||||
scoped_ptr<PassAsType> PassAs() {
|
||||
return scoped_ptr<PassAsType>(Pass());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Forbid comparison of scoped_ptr types. If U != T, it totally
|
||||
// doesn't make sense, and if U == T, it still doesn't make sense
|
||||
// because you should never have the same object owned by two different
|
||||
// scoped_ptrs.
|
||||
template <class U> bool operator==(scoped_ptr<U> const& p2) const;
|
||||
template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
|
||||
};
|
||||
|
||||
template <class T, class D>
|
||||
class scoped_ptr<T[], D> {
|
||||
MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
|
||||
|
||||
public:
|
||||
// The element and deleter types.
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
|
||||
// Constructor. Defaults to initializing with NULL.
|
||||
scoped_ptr() : impl_(NULL) { }
|
||||
|
||||
// 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 NULL, because NULL is an integral expression, not a
|
||||
// pointer to T. Use the no-argument version instead of explicitly
|
||||
// passing NULL.
|
||||
// - it cannot be const-qualified differently from T per unique_ptr spec
|
||||
// (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
|
||||
// to work around this may use implicit_cast<const T*>().
|
||||
// However, because of the first bullet in this comment, users MUST
|
||||
// NOT use implicit_cast<Base*>() to upcast the static type of the array.
|
||||
explicit scoped_ptr(element_type* array) : impl_(array) { }
|
||||
|
||||
// Constructor. Move constructor for C++03 move emulation of this type.
|
||||
scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
|
||||
|
||||
// operator=. Move operator= for C++03 move emulation of this type.
|
||||
scoped_ptr& operator=(RValue rhs) {
|
||||
impl_.TakeState(&rhs.object->impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Reset. Deletes the currently owned array, if any.
|
||||
// Then takes ownership of a new object, if given.
|
||||
void reset(element_type* array = NULL) { impl_.reset(array); }
|
||||
|
||||
// Accessors to get the owned array.
|
||||
element_type& operator[](size_t i) const {
|
||||
assert(impl_.get() != NULL);
|
||||
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_ : NULL; }
|
||||
|
||||
// Comparison operators.
|
||||
// These return whether two scoped_ptr refer to the same object, not just to
|
||||
// two different but equal objects.
|
||||
bool operator==(element_type* array) const { return impl_.get() == array; }
|
||||
bool operator!=(element_type* array) const { return impl_.get() != array; }
|
||||
|
||||
// Swap two scoped pointers.
|
||||
void swap(scoped_ptr& p2) {
|
||||
impl_.swap(p2.impl_);
|
||||
}
|
||||
|
||||
// Release a pointer.
|
||||
// The return value is the current pointer held by this object.
|
||||
// If this object holds a NULL pointer, the return value is NULL.
|
||||
// After this operation, this object will hold a NULL pointer,
|
||||
// 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);
|
||||
|
||||
// Forbid comparison of scoped_ptr types. If U != T, it totally
|
||||
// doesn't make sense, and if U == T, it still doesn't make sense
|
||||
// because you should never have the same object owned by two different
|
||||
// scoped_ptrs.
|
||||
template <class U> bool operator==(scoped_ptr<U> const& p2) const;
|
||||
template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
|
||||
};
|
||||
|
||||
// Free functions
|
||||
template <class T, class D>
|
||||
void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) {
|
||||
p1.swap(p2);
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator==(T* p1, const scoped_ptr<T, D>& p2) {
|
||||
return p1 == p2.get();
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator!=(T* p1, const scoped_ptr<T, D>& p2) {
|
||||
return p1 != p2.get();
|
||||
}
|
||||
|
||||
// DEPRECATED: Use scoped_ptr<C, base::FreeDeleter> instead.
|
||||
//
|
||||
// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
|
||||
// second template argument, the functor used to free the object.
|
||||
|
||||
template<class C, class FreeProc = base::FreeDeleter>
|
||||
class scoped_ptr_malloc {
|
||||
MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr_malloc, RValue)
|
||||
|
||||
public:
|
||||
|
||||
// The element type
|
||||
typedef C element_type;
|
||||
|
||||
// Constructor. Defaults to initializing with NULL.
|
||||
// There is no way to create an uninitialized scoped_ptr.
|
||||
// The input parameter must be allocated with an allocator that matches the
|
||||
// Free functor. For the default Free functor, this is malloc, calloc, or
|
||||
// realloc.
|
||||
explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {}
|
||||
|
||||
// Constructor. Move constructor for C++03 move emulation of this type.
|
||||
scoped_ptr_malloc(RValue rvalue)
|
||||
: ptr_(rvalue.object->release()) {
|
||||
}
|
||||
|
||||
// Destructor. If there is a C object, call the Free functor.
|
||||
~scoped_ptr_malloc() {
|
||||
reset();
|
||||
}
|
||||
|
||||
// operator=. Move operator= for C++03 move emulation of this type.
|
||||
scoped_ptr_malloc& operator=(RValue rhs) {
|
||||
reset(rhs.object->release());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Reset. Calls the Free functor on the current owned object, if any.
|
||||
// Then takes ownership of a new object, if given.
|
||||
// this->reset(this->get()) works.
|
||||
void reset(C* p = NULL) {
|
||||
if (ptr_ != p) {
|
||||
if (ptr_ != NULL) {
|
||||
FreeProc free_proc;
|
||||
free_proc(ptr_);
|
||||
}
|
||||
ptr_ = p;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the current object.
|
||||
// operator* and operator-> will cause an assert() failure if there is
|
||||
// no current object.
|
||||
C& operator*() const {
|
||||
assert(ptr_ != NULL);
|
||||
return *ptr_;
|
||||
}
|
||||
|
||||
C* operator->() const {
|
||||
assert(ptr_ != NULL);
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
C* get() const {
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
// Allow scoped_ptr_malloc<C> to be used in boolean expressions, but not
|
||||
// implicitly convertible to a real bool (which is dangerous).
|
||||
typedef C* scoped_ptr_malloc::*Testable;
|
||||
operator Testable() const { return ptr_ ? &scoped_ptr_malloc::ptr_ : NULL; }
|
||||
|
||||
// Comparison operators.
|
||||
// These return whether a scoped_ptr_malloc and a plain pointer refer
|
||||
// to the same object, not just to two different but equal objects.
|
||||
// For compatibility with the boost-derived implementation, these
|
||||
// take non-const arguments.
|
||||
bool operator==(C* p) const {
|
||||
return ptr_ == p;
|
||||
}
|
||||
|
||||
bool operator!=(C* p) const {
|
||||
return ptr_ != p;
|
||||
}
|
||||
|
||||
// Swap two scoped pointers.
|
||||
void swap(scoped_ptr_malloc & b) {
|
||||
C* tmp = b.ptr_;
|
||||
b.ptr_ = ptr_;
|
||||
ptr_ = tmp;
|
||||
}
|
||||
|
||||
// Release a pointer.
|
||||
// The return value is the current pointer held by this object.
|
||||
// If this object holds a NULL pointer, the return value is NULL.
|
||||
// After this operation, this object will hold a NULL pointer,
|
||||
// and will not own the object any more.
|
||||
C* release() WARN_UNUSED_RESULT {
|
||||
C* tmp = ptr_;
|
||||
ptr_ = NULL;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
C* ptr_;
|
||||
|
||||
// no reason to use these: each scoped_ptr_malloc should have its own object
|
||||
template <class C2, class GP>
|
||||
bool operator==(scoped_ptr_malloc<C2, GP> const& p) const;
|
||||
template <class C2, class GP>
|
||||
bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const;
|
||||
};
|
||||
|
||||
template<class C, class FP> inline
|
||||
void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) {
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template<class C, class FP> inline
|
||||
bool operator==(C* p, const scoped_ptr_malloc<C, FP>& b) {
|
||||
return p == b.get();
|
||||
}
|
||||
|
||||
template<class C, class FP> inline
|
||||
bool operator!=(C* p, const scoped_ptr_malloc<C, FP>& b) {
|
||||
return p != b.get();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
#endif // BASE_MEMORY_SCOPED_PTR_H_
|
|
@ -0,0 +1,31 @@
|
|||
// 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) {
|
||||
value = subtle::NoBarrier_Load(instance);
|
||||
if (value != kBeingCreatedMarker)
|
||||
break;
|
||||
PlatformThread::YieldCurrentThread();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
// 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/memory/aligned_memory.h"
|
||||
#include "base/third_party/dynamic_annotations/dynamic_annotations.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);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
||||
|
||||
// TODO(joth): Move more of this file into namespace base
|
||||
|
||||
// Default traits for Singleton<Type>. Calls operator new and operator delete on
|
||||
// the object. Registers automatic deletion at process exit.
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
// 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;
|
||||
static const bool kAllowedToAccessOnNonjoinableThread = true;
|
||||
};
|
||||
|
||||
|
||||
// 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 (base::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() {
|
||||
base::subtle::NoBarrier_Store(&dead_, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
static base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
|
||||
// Signal the object was already deleted, so it is not revived.
|
||||
static base::subtle::Atomic32 dead_;
|
||||
};
|
||||
|
||||
template <typename Type> base::AlignedMemory<sizeof(Type), ALIGNOF(Type)>
|
||||
StaticMemorySingletonTraits<Type>::buffer_;
|
||||
template <typename Type> base::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 base::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 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)
|
||||
base::ThreadRestrictions::AssertSingletonAllowed();
|
||||
#endif
|
||||
|
||||
base::subtle::AtomicWord value = base::subtle::NoBarrier_Load(&instance_);
|
||||
if (value != 0 && value != base::internal::kBeingCreatedMarker) {
|
||||
// See the corresponding HAPPENS_BEFORE below.
|
||||
ANNOTATE_HAPPENS_AFTER(&instance_);
|
||||
return reinterpret_cast<Type*>(value);
|
||||
}
|
||||
|
||||
// Object isn't created yet, maybe we will get to create it, let's try...
|
||||
if (base::subtle::Acquire_CompareAndSwap(
|
||||
&instance_, 0, base::internal::kBeingCreatedMarker) == 0) {
|
||||
// instance_ was NULL and is now kBeingCreatedMarker. Only one thread
|
||||
// will ever get here. Threads might be spinning on us, and they will
|
||||
// stop right after we do this store.
|
||||
Type* newval = Traits::New();
|
||||
|
||||
// This annotation helps race detectors recognize correct lock-less
|
||||
// synchronization between different threads calling get().
|
||||
// See the corresponding HAPPENS_AFTER below and above.
|
||||
ANNOTATE_HAPPENS_BEFORE(&instance_);
|
||||
base::subtle::Release_Store(
|
||||
&instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
|
||||
|
||||
if (newval != NULL && Traits::kRegisterAtExit)
|
||||
base::AtExitManager::RegisterCallback(OnExit, NULL);
|
||||
|
||||
return newval;
|
||||
}
|
||||
|
||||
// We hit a race. Wait for the other thread to complete it.
|
||||
value = base::internal::WaitForInstance(&instance_);
|
||||
|
||||
// See the corresponding HAPPENS_BEFORE above.
|
||||
ANNOTATE_HAPPENS_AFTER(&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*>(base::subtle::NoBarrier_Load(&instance_)));
|
||||
instance_ = 0;
|
||||
}
|
||||
static base::subtle::AtomicWord instance_;
|
||||
};
|
||||
|
||||
template <typename Type, typename Traits, typename DifferentiatingType>
|
||||
base::subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::
|
||||
instance_ = 0;
|
||||
|
||||
#endif // BASE_MEMORY_SINGLETON_H_
|
|
@ -0,0 +1,338 @@
|
|||
// 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:
|
||||
// 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 thread 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, and cannot be dereferenced or invalidated on any other thread. Bound
|
||||
// WeakPtrs can still be handed off to other threads, e.g. to use to post tasks
|
||||
// back to object on the bound thread.
|
||||
//
|
||||
// Invalidating the factory's WeakPtrs un-binds it from the thread, allowing it
|
||||
// to be passed for a different thread to use or delete it.
|
||||
|
||||
#ifndef BASE_MEMORY_WEAK_PTR_H_
|
||||
#define BASE_MEMORY_WEAK_PTR_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/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 thread, it may be deleted from another
|
||||
// via base::WeakPtr::~WeakPtr().
|
||||
class 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;
|
||||
COMPILE_ASSERT(convertible::value,
|
||||
AsWeakPtr_argument_inherits_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_
|
|
@ -0,0 +1,207 @@
|
|||
// 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_
|
||||
|
||||
// Macro with the boilerplate that makes a type move-only in C++03.
|
||||
//
|
||||
// USAGE
|
||||
//
|
||||
// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create
|
||||
// a "move-only" type. Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be
|
||||
// the first line in a class declaration.
|
||||
//
|
||||
// A class using this macro must call .Pass() (or somehow be an r-value already)
|
||||
// before it can be:
|
||||
//
|
||||
// * Passed as a function argument
|
||||
// * Used as the right-hand side of an assignment
|
||||
// * Returned from a function
|
||||
//
|
||||
// Each class will still need to define their own "move constructor" and "move
|
||||
// operator=" to make this useful. Here's an example of the macro, the move
|
||||
// constructor, and the move operator= from the scoped_ptr class:
|
||||
//
|
||||
// template <typename T>
|
||||
// class scoped_ptr {
|
||||
// MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
|
||||
// public:
|
||||
// scoped_ptr(RValue& other) : ptr_(other.release()) { }
|
||||
// scoped_ptr& operator=(RValue& other) {
|
||||
// swap(other);
|
||||
// return *this;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// Note that the constructor must NOT be marked explicit.
|
||||
//
|
||||
// For consistency, the second parameter to the macro should always be RValue
|
||||
// unless you have a strong reason to do otherwise. It is only exposed as a
|
||||
// macro parameter so that the move constructor and move operator= don't look
|
||||
// like they're using a phantom type.
|
||||
//
|
||||
//
|
||||
// HOW THIS WORKS
|
||||
//
|
||||
// For a thorough explanation of this technique, see:
|
||||
//
|
||||
// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
|
||||
//
|
||||
// The summary is that we take advantage of 2 properties:
|
||||
//
|
||||
// 1) non-const references will not bind to r-values.
|
||||
// 2) C++ can apply one user-defined conversion when initializing a
|
||||
// variable.
|
||||
//
|
||||
// The first lets us disable the copy constructor and assignment operator
|
||||
// by declaring private version of them with a non-const reference parameter.
|
||||
//
|
||||
// For l-values, direct initialization still fails like in
|
||||
// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment
|
||||
// operators are private.
|
||||
//
|
||||
// For r-values, the situation is different. The copy constructor and
|
||||
// assignment operator are not viable due to (1), so we are trying to call
|
||||
// a non-existent constructor and non-existing operator= rather than a private
|
||||
// one. Since we have not committed an error quite yet, we can provide an
|
||||
// alternate conversion sequence and a constructor. We add
|
||||
//
|
||||
// * a private struct named "RValue"
|
||||
// * a user-defined conversion "operator RValue()"
|
||||
// * a "move constructor" and "move operator=" that take the RValue& as
|
||||
// their sole parameter.
|
||||
//
|
||||
// Only r-values will trigger this sequence and execute our "move constructor"
|
||||
// or "move operator=." L-values will match the private copy constructor and
|
||||
// operator= first giving a "private in this context" error. This combination
|
||||
// gives us a move-only type.
|
||||
//
|
||||
// For signaling a destructive transfer of data from an l-value, we provide a
|
||||
// method named Pass() which creates an r-value for the current instance
|
||||
// triggering the move constructor or move operator=.
|
||||
//
|
||||
// Other ways to get r-values is to use the result of an expression like a
|
||||
// function call.
|
||||
//
|
||||
// Here's an example with comments explaining what gets triggered where:
|
||||
//
|
||||
// class Foo {
|
||||
// MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue);
|
||||
//
|
||||
// public:
|
||||
// ... API ...
|
||||
// Foo(RValue other); // Move constructor.
|
||||
// Foo& operator=(RValue rhs); // Move operator=
|
||||
// };
|
||||
//
|
||||
// Foo MakeFoo(); // Function that returns a Foo.
|
||||
//
|
||||
// Foo f;
|
||||
// Foo f_copy(f); // ERROR: Foo(Foo&) is private in this context.
|
||||
// Foo f_assign;
|
||||
// f_assign = f; // ERROR: operator=(Foo&) is private in this context.
|
||||
//
|
||||
//
|
||||
// Foo f(MakeFoo()); // R-value so alternate conversion executed.
|
||||
// Foo f_copy(f.Pass()); // R-value so alternate conversion executed.
|
||||
// f = f_copy.Pass(); // R-value so alternate conversion executed.
|
||||
//
|
||||
//
|
||||
// IMPLEMENTATION SUBTLETIES WITH RValue
|
||||
//
|
||||
// The RValue struct is just a container for a pointer back to the original
|
||||
// object. It should only ever be created as a temporary, and no external
|
||||
// class should ever declare it or use it in a parameter.
|
||||
//
|
||||
// It is tempting to want to use the RValue type in function parameters, but
|
||||
// excluding the limited usage here for the move constructor and move
|
||||
// operator=, doing so would mean that the function could take both r-values
|
||||
// and l-values equially which is unexpected. See COMPARED To Boost.Move for
|
||||
// more details.
|
||||
//
|
||||
// An alternate, and incorrect, implementation of the RValue class used by
|
||||
// Boost.Move makes RValue a fieldless child of the move-only type. RValue&
|
||||
// is then used in place of RValue in the various operators. The RValue& is
|
||||
// "created" by doing *reinterpret_cast<RValue*>(this). This has the appeal
|
||||
// of never creating a temporary RValue struct even with optimizations
|
||||
// disabled. Also, by virtue of inheritance you can treat the RValue
|
||||
// reference as if it were the move-only type itself. Unfortunately,
|
||||
// using the result of this reinterpret_cast<> is actually undefined behavior
|
||||
// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer
|
||||
// will generate non-working code.
|
||||
//
|
||||
// In optimized builds, both implementations generate the same assembly so we
|
||||
// choose the one that adheres to the standard.
|
||||
//
|
||||
//
|
||||
// COMPARED TO C++11
|
||||
//
|
||||
// In C++11, you would implement this functionality using an r-value reference
|
||||
// and our .Pass() method would be replaced with a call to std::move().
|
||||
//
|
||||
// This emulation also has a deficiency where it uses up the single
|
||||
// user-defined conversion allowed by C++ during initialization. This can
|
||||
// cause problems in some API edge cases. For instance, in scoped_ptr, it is
|
||||
// impossible to make a function "void Foo(scoped_ptr<Parent> p)" accept a
|
||||
// value of type scoped_ptr<Child> even if you add a constructor to
|
||||
// scoped_ptr<> that would make it look like it should work. C++11 does not
|
||||
// have this deficiency.
|
||||
//
|
||||
//
|
||||
// COMPARED TO Boost.Move
|
||||
//
|
||||
// Our implementation similar to Boost.Move, but we keep the RValue struct
|
||||
// private to the move-only type, and we don't use the reinterpret_cast<> hack.
|
||||
//
|
||||
// In Boost.Move, RValue is the boost::rv<> template. This type can be used
|
||||
// when writing APIs like:
|
||||
//
|
||||
// void MyFunc(boost::rv<Foo>& f)
|
||||
//
|
||||
// that can take advantage of rv<> to avoid extra copies of a type. However you
|
||||
// would still be able to call this version of MyFunc with an l-value:
|
||||
//
|
||||
// Foo f;
|
||||
// MyFunc(f); // Uh oh, we probably just destroyed |f| w/o calling Pass().
|
||||
//
|
||||
// unless someone is very careful to also declare a parallel override like:
|
||||
//
|
||||
// void MyFunc(const Foo& f)
|
||||
//
|
||||
// that would catch the l-values first. This was declared unsafe in C++11 and
|
||||
// a C++11 compiler will explicitly fail MyFunc(f). Unfortunately, we cannot
|
||||
// ensure this in C++03.
|
||||
//
|
||||
// Since we have no need for writing such APIs yet, our implementation keeps
|
||||
// RValue private and uses a .Pass() method to do the conversion instead of
|
||||
// trying to write a version of "std::move()." Writing an API like std::move()
|
||||
// would require the RValue struct to be public.
|
||||
//
|
||||
//
|
||||
// CAVEATS
|
||||
//
|
||||
// If you include a move-only type as a field inside a class that does not
|
||||
// explicitly declare a copy constructor, the containing class's implicit
|
||||
// copy constructor will change from Containing(const Containing&) to
|
||||
// Containing(Containing&). This can cause some unexpected errors.
|
||||
//
|
||||
// http://llvm.org/bugs/show_bug.cgi?id=11528
|
||||
//
|
||||
// The workaround is to explicitly declare your copy constructor.
|
||||
//
|
||||
#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
|
||||
private: \
|
||||
struct rvalue_type { \
|
||||
explicit rvalue_type(type* object) : object(object) {} \
|
||||
type* object; \
|
||||
}; \
|
||||
type(type&); \
|
||||
void operator=(type&); \
|
||||
public: \
|
||||
operator rvalue_type() { return rvalue_type(this); } \
|
||||
type Pass() { return type(rvalue_type(this)); } \
|
||||
private:
|
||||
|
||||
#endif // BASE_MOVE_H_
|
|
@ -0,0 +1,217 @@
|
|||
// 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_OBSERVER_LIST_H__
|
||||
#define BASE_OBSERVER_LIST_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// OVERVIEW:
|
||||
//
|
||||
// A container for a list of observers. Unlike a normal STL vector or list,
|
||||
// this container can be modified during iteration without invalidating the
|
||||
// iterator. So, it safely handles the case of an observer removing itself
|
||||
// or other observers from the list while observers are being notified.
|
||||
//
|
||||
// TYPICAL USAGE:
|
||||
//
|
||||
// class MyWidget {
|
||||
// public:
|
||||
// ...
|
||||
//
|
||||
// class Observer {
|
||||
// public:
|
||||
// virtual void OnFoo(MyWidget* w) = 0;
|
||||
// virtual void OnBar(MyWidget* w, int x, int y) = 0;
|
||||
// };
|
||||
//
|
||||
// void AddObserver(Observer* obs) {
|
||||
// observer_list_.AddObserver(obs);
|
||||
// }
|
||||
//
|
||||
// void RemoveObserver(Observer* obs) {
|
||||
// observer_list_.RemoveObserver(obs);
|
||||
// }
|
||||
//
|
||||
// void NotifyFoo() {
|
||||
// FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
|
||||
// }
|
||||
//
|
||||
// void NotifyBar(int x, int y) {
|
||||
// FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// ObserverList<Observer> observer_list_;
|
||||
// };
|
||||
//
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename ObserverType>
|
||||
class ObserverListThreadSafe;
|
||||
|
||||
template <class ObserverType>
|
||||
class ObserverListBase
|
||||
: public base::SupportsWeakPtr<ObserverListBase<ObserverType> > {
|
||||
public:
|
||||
// Enumeration of which observers are notified.
|
||||
enum NotificationType {
|
||||
// Specifies that any observers added during notification are notified.
|
||||
// This is the default type if non type is provided to the constructor.
|
||||
NOTIFY_ALL,
|
||||
|
||||
// Specifies that observers added while sending out notification are not
|
||||
// notified.
|
||||
NOTIFY_EXISTING_ONLY
|
||||
};
|
||||
|
||||
// An iterator class that can be used to access the list of observers. See
|
||||
// also the FOR_EACH_OBSERVER macro defined below.
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(ObserverListBase<ObserverType>& list)
|
||||
: list_(list.AsWeakPtr()),
|
||||
index_(0),
|
||||
max_index_(list.type_ == NOTIFY_ALL ?
|
||||
std::numeric_limits<size_t>::max() :
|
||||
list.observers_.size()) {
|
||||
++list_->notify_depth_;
|
||||
}
|
||||
|
||||
~Iterator() {
|
||||
if (list_.get() && --list_->notify_depth_ == 0)
|
||||
list_->Compact();
|
||||
}
|
||||
|
||||
ObserverType* GetNext() {
|
||||
if (!list_.get())
|
||||
return NULL;
|
||||
ListType& observers = list_->observers_;
|
||||
// Advance if the current element is null
|
||||
size_t max_index = std::min(max_index_, observers.size());
|
||||
while (index_ < max_index && !observers[index_])
|
||||
++index_;
|
||||
return index_ < max_index ? observers[index_++] : NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
base::WeakPtr<ObserverListBase<ObserverType> > list_;
|
||||
size_t index_;
|
||||
size_t max_index_;
|
||||
};
|
||||
|
||||
ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
|
||||
explicit ObserverListBase(NotificationType type)
|
||||
: notify_depth_(0), type_(type) {}
|
||||
|
||||
// Add an observer to the list. An observer should not be added to
|
||||
// the same list more than once.
|
||||
void AddObserver(ObserverType* obs) {
|
||||
if (std::find(observers_.begin(), observers_.end(), obs)
|
||||
!= observers_.end()) {
|
||||
NOTREACHED() << "Observers can only be added once!";
|
||||
return;
|
||||
}
|
||||
observers_.push_back(obs);
|
||||
}
|
||||
|
||||
// Remove an observer from the list if it is in the list.
|
||||
void RemoveObserver(ObserverType* obs) {
|
||||
typename ListType::iterator it =
|
||||
std::find(observers_.begin(), observers_.end(), obs);
|
||||
if (it != observers_.end()) {
|
||||
if (notify_depth_) {
|
||||
*it = 0;
|
||||
} else {
|
||||
observers_.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HasObserver(ObserverType* observer) const {
|
||||
for (size_t i = 0; i < observers_.size(); ++i) {
|
||||
if (observers_[i] == observer)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
if (notify_depth_) {
|
||||
for (typename ListType::iterator it = observers_.begin();
|
||||
it != observers_.end(); ++it) {
|
||||
*it = 0;
|
||||
}
|
||||
} else {
|
||||
observers_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
size_t size() const { return observers_.size(); }
|
||||
|
||||
void Compact() {
|
||||
observers_.erase(
|
||||
std::remove(observers_.begin(), observers_.end(),
|
||||
static_cast<ObserverType*>(NULL)), observers_.end());
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ObserverListThreadSafe<ObserverType>;
|
||||
|
||||
typedef std::vector<ObserverType*> ListType;
|
||||
|
||||
ListType observers_;
|
||||
int notify_depth_;
|
||||
NotificationType type_;
|
||||
|
||||
friend class ObserverListBase::Iterator;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
|
||||
};
|
||||
|
||||
template <class ObserverType, bool check_empty = false>
|
||||
class ObserverList : public ObserverListBase<ObserverType> {
|
||||
public:
|
||||
typedef typename ObserverListBase<ObserverType>::NotificationType
|
||||
NotificationType;
|
||||
|
||||
ObserverList() {}
|
||||
explicit ObserverList(NotificationType type)
|
||||
: ObserverListBase<ObserverType>(type) {}
|
||||
|
||||
~ObserverList() {
|
||||
// When check_empty is true, assert that the list is empty on destruction.
|
||||
if (check_empty) {
|
||||
ObserverListBase<ObserverType>::Compact();
|
||||
DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
|
||||
}
|
||||
}
|
||||
|
||||
bool might_have_observers() const {
|
||||
return ObserverListBase<ObserverType>::size() != 0;
|
||||
}
|
||||
};
|
||||
|
||||
#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
|
||||
do { \
|
||||
if ((observer_list).might_have_observers()) { \
|
||||
ObserverListBase<ObserverType>::Iterator \
|
||||
it_inside_observer_macro(observer_list); \
|
||||
ObserverType* obs; \
|
||||
while ((obs = it_inside_observer_macro.GetNext()) != NULL) \
|
||||
obs->func; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // BASE_OBSERVER_LIST_H__
|
|
@ -0,0 +1,295 @@
|
|||
// 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_OBSERVER_LIST_THREADSAFE_H_
|
||||
#define BASE_OBSERVER_LIST_THREADSAFE_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/location.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/message_loop/message_loop_proxy.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// OVERVIEW:
|
||||
//
|
||||
// A thread-safe container for a list of observers.
|
||||
// This is similar to the observer_list (see observer_list.h), but it
|
||||
// is more robust for multi-threaded situations.
|
||||
//
|
||||
// The following use cases are supported:
|
||||
// * Observers can register for notifications from any thread.
|
||||
// Callbacks to the observer will occur on the same thread where
|
||||
// the observer initially called AddObserver() from.
|
||||
// * Any thread may trigger a notification via Notify().
|
||||
// * Observers can remove themselves from the observer list inside
|
||||
// of a callback.
|
||||
// * If one thread is notifying observers concurrently with an observer
|
||||
// removing itself from the observer list, the notifications will
|
||||
// be silently dropped.
|
||||
//
|
||||
// The drawback of the threadsafe observer list is that notifications
|
||||
// are not as real-time as the non-threadsafe version of this class.
|
||||
// Notifications will always be done via PostTask() to another thread,
|
||||
// whereas with the non-thread-safe observer_list, notifications happen
|
||||
// synchronously and immediately.
|
||||
//
|
||||
// IMPLEMENTATION NOTES
|
||||
// The ObserverListThreadSafe maintains an ObserverList for each thread
|
||||
// which uses the ThreadSafeObserver. When Notifying the observers,
|
||||
// we simply call PostTask to each registered thread, and then each thread
|
||||
// will notify its regular ObserverList.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Forward declaration for ObserverListThreadSafeTraits.
|
||||
template <class ObserverType>
|
||||
class ObserverListThreadSafe;
|
||||
|
||||
// An UnboundMethod is a wrapper for a method where the actual object is
|
||||
// provided at Run dispatch time.
|
||||
template <class T, class Method, class Params>
|
||||
class UnboundMethod {
|
||||
public:
|
||||
UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
|
||||
COMPILE_ASSERT(
|
||||
(base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
|
||||
badunboundmethodparams);
|
||||
}
|
||||
void Run(T* obj) const {
|
||||
DispatchToMethod(obj, m_, p_);
|
||||
}
|
||||
private:
|
||||
Method m_;
|
||||
Params p_;
|
||||
};
|
||||
|
||||
// This class is used to work around VS2005 not accepting:
|
||||
//
|
||||
// friend class
|
||||
// base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType> >;
|
||||
//
|
||||
// Instead of friending the class, we could friend the actual function
|
||||
// which calls delete. However, this ends up being
|
||||
// RefCountedThreadSafe::DeleteInternal(), which is private. So we
|
||||
// define our own templated traits class so we can friend it.
|
||||
template <class T>
|
||||
struct ObserverListThreadSafeTraits {
|
||||
static void Destruct(const ObserverListThreadSafe<T>* x) {
|
||||
delete x;
|
||||
}
|
||||
};
|
||||
|
||||
template <class ObserverType>
|
||||
class ObserverListThreadSafe
|
||||
: public base::RefCountedThreadSafe<
|
||||
ObserverListThreadSafe<ObserverType>,
|
||||
ObserverListThreadSafeTraits<ObserverType> > {
|
||||
public:
|
||||
typedef typename ObserverList<ObserverType>::NotificationType
|
||||
NotificationType;
|
||||
|
||||
ObserverListThreadSafe()
|
||||
: type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {}
|
||||
explicit ObserverListThreadSafe(NotificationType type) : type_(type) {}
|
||||
|
||||
// Add an observer to the list. An observer should not be added to
|
||||
// the same list more than once.
|
||||
void AddObserver(ObserverType* obs) {
|
||||
// If there is not a current MessageLoop, it is impossible to notify on it,
|
||||
// so do not add the observer.
|
||||
if (!base::MessageLoop::current())
|
||||
return;
|
||||
|
||||
ObserverList<ObserverType>* list = NULL;
|
||||
base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
|
||||
{
|
||||
base::AutoLock lock(list_lock_);
|
||||
if (observer_lists_.find(thread_id) == observer_lists_.end())
|
||||
observer_lists_[thread_id] = new ObserverListContext(type_);
|
||||
list = &(observer_lists_[thread_id]->list);
|
||||
}
|
||||
list->AddObserver(obs);
|
||||
}
|
||||
|
||||
// Remove an observer from the list if it is in the list.
|
||||
// If there are pending notifications in-transit to the observer, they will
|
||||
// be aborted.
|
||||
// If the observer to be removed is in the list, RemoveObserver MUST
|
||||
// be called from the same thread which called AddObserver.
|
||||
void RemoveObserver(ObserverType* obs) {
|
||||
ObserverListContext* context = NULL;
|
||||
ObserverList<ObserverType>* list = NULL;
|
||||
base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
|
||||
{
|
||||
base::AutoLock lock(list_lock_);
|
||||
typename ObserversListMap::iterator it = observer_lists_.find(thread_id);
|
||||
if (it == observer_lists_.end()) {
|
||||
// This will happen if we try to remove an observer on a thread
|
||||
// we never added an observer for.
|
||||
return;
|
||||
}
|
||||
context = it->second;
|
||||
list = &context->list;
|
||||
|
||||
// If we're about to remove the last observer from the list,
|
||||
// then we can remove this observer_list entirely.
|
||||
if (list->HasObserver(obs) && list->size() == 1)
|
||||
observer_lists_.erase(it);
|
||||
}
|
||||
list->RemoveObserver(obs);
|
||||
|
||||
// If RemoveObserver is called from a notification, the size will be
|
||||
// nonzero. Instead of deleting here, the NotifyWrapper will delete
|
||||
// when it finishes iterating.
|
||||
if (list->size() == 0)
|
||||
delete context;
|
||||
}
|
||||
|
||||
// Verifies that the list is currently empty (i.e. there are no observers).
|
||||
void AssertEmpty() const {
|
||||
base::AutoLock lock(list_lock_);
|
||||
DCHECK(observer_lists_.empty());
|
||||
}
|
||||
|
||||
// Notify methods.
|
||||
// Make a thread-safe callback to each Observer in the list.
|
||||
// Note, these calls are effectively asynchronous. You cannot assume
|
||||
// that at the completion of the Notify call that all Observers have
|
||||
// been Notified. The notification may still be pending delivery.
|
||||
template <class Method>
|
||||
void Notify(Method m) {
|
||||
UnboundMethod<ObserverType, Method, Tuple0> method(m, MakeTuple());
|
||||
Notify<Method, Tuple0>(method);
|
||||
}
|
||||
|
||||
template <class Method, class A>
|
||||
void Notify(Method m, const A& a) {
|
||||
UnboundMethod<ObserverType, Method, Tuple1<A> > method(m, MakeTuple(a));
|
||||
Notify<Method, Tuple1<A> >(method);
|
||||
}
|
||||
|
||||
template <class Method, class A, class B>
|
||||
void Notify(Method m, const A& a, const B& b) {
|
||||
UnboundMethod<ObserverType, Method, Tuple2<A, B> > method(
|
||||
m, MakeTuple(a, b));
|
||||
Notify<Method, Tuple2<A, B> >(method);
|
||||
}
|
||||
|
||||
template <class Method, class A, class B, class C>
|
||||
void Notify(Method m, const A& a, const B& b, const C& c) {
|
||||
UnboundMethod<ObserverType, Method, Tuple3<A, B, C> > method(
|
||||
m, MakeTuple(a, b, c));
|
||||
Notify<Method, Tuple3<A, B, C> >(method);
|
||||
}
|
||||
|
||||
template <class Method, class A, class B, class C, class D>
|
||||
void Notify(Method m, const A& a, const B& b, const C& c, const D& d) {
|
||||
UnboundMethod<ObserverType, Method, Tuple4<A, B, C, D> > method(
|
||||
m, MakeTuple(a, b, c, d));
|
||||
Notify<Method, Tuple4<A, B, C, D> >(method);
|
||||
}
|
||||
|
||||
// TODO(mbelshe): Add more wrappers for Notify() with more arguments.
|
||||
|
||||
private:
|
||||
// See comment above ObserverListThreadSafeTraits' definition.
|
||||
friend struct ObserverListThreadSafeTraits<ObserverType>;
|
||||
|
||||
struct ObserverListContext {
|
||||
explicit ObserverListContext(NotificationType type)
|
||||
: loop(base::MessageLoopProxy::current()),
|
||||
list(type) {
|
||||
}
|
||||
|
||||
scoped_refptr<base::MessageLoopProxy> loop;
|
||||
ObserverList<ObserverType> list;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObserverListContext);
|
||||
};
|
||||
|
||||
~ObserverListThreadSafe() {
|
||||
STLDeleteValues(&observer_lists_);
|
||||
}
|
||||
|
||||
template <class Method, class Params>
|
||||
void Notify(const UnboundMethod<ObserverType, Method, Params>& method) {
|
||||
base::AutoLock lock(list_lock_);
|
||||
typename ObserversListMap::iterator it;
|
||||
for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) {
|
||||
ObserverListContext* context = (*it).second;
|
||||
context->loop->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&ObserverListThreadSafe<ObserverType>::
|
||||
template NotifyWrapper<Method, Params>, this, context, method));
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper which is called to fire the notifications for each thread's
|
||||
// ObserverList. This function MUST be called on the thread which owns
|
||||
// the unsafe ObserverList.
|
||||
template <class Method, class Params>
|
||||
void NotifyWrapper(ObserverListContext* context,
|
||||
const UnboundMethod<ObserverType, Method, Params>& method) {
|
||||
|
||||
// Check that this list still needs notifications.
|
||||
{
|
||||
base::AutoLock lock(list_lock_);
|
||||
typename ObserversListMap::iterator it =
|
||||
observer_lists_.find(base::PlatformThread::CurrentId());
|
||||
|
||||
// The ObserverList could have been removed already. In fact, it could
|
||||
// have been removed and then re-added! If the master list's loop
|
||||
// does not match this one, then we do not need to finish this
|
||||
// notification.
|
||||
if (it == observer_lists_.end() || it->second != context)
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
typename ObserverList<ObserverType>::Iterator it(context->list);
|
||||
ObserverType* obs;
|
||||
while ((obs = it.GetNext()) != NULL)
|
||||
method.Run(obs);
|
||||
}
|
||||
|
||||
// If there are no more observers on the list, we can now delete it.
|
||||
if (context->list.size() == 0) {
|
||||
{
|
||||
base::AutoLock lock(list_lock_);
|
||||
// Remove |list| if it's not already removed.
|
||||
// This can happen if multiple observers got removed in a notification.
|
||||
// See http://crbug.com/55725.
|
||||
typename ObserversListMap::iterator it =
|
||||
observer_lists_.find(base::PlatformThread::CurrentId());
|
||||
if (it != observer_lists_.end() && it->second == context)
|
||||
observer_lists_.erase(it);
|
||||
}
|
||||
delete context;
|
||||
}
|
||||
}
|
||||
|
||||
// Key by PlatformThreadId because in tests, clients can attempt to remove
|
||||
// observers without a MessageLoop. If this were keyed by MessageLoop, that
|
||||
// operation would be silently ignored, leaving garbage in the ObserverList.
|
||||
typedef std::map<base::PlatformThreadId, ObserverListContext*>
|
||||
ObserversListMap;
|
||||
|
||||
mutable base::Lock list_lock_; // Protects the observer_lists_.
|
||||
ObserversListMap observer_lists_;
|
||||
const NotificationType type_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
|
||||
};
|
||||
|
||||
#endif // BASE_OBSERVER_LIST_THREADSAFE_H_
|
|
@ -0,0 +1,16 @@
|
|||
// 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_NACL_H_
|
||||
#define BASE_OS_COMPAT_NACL_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if !defined (__GLIBC__)
|
||||
// NaCl has no timegm().
|
||||
extern "C" time_t timegm(struct tm* const t);
|
||||
#endif // !defined (__GLIBC__)
|
||||
|
||||
#endif // BASE_OS_COMPAT_NACL_H_
|
||||
|
|
@ -0,0 +1,336 @@
|
|||
// 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/path_service.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "base/file_util.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/lazy_instance.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
|
||||
using base::FilePath;
|
||||
using base::MakeAbsoluteFilePath;
|
||||
|
||||
namespace base {
|
||||
bool PathProvider(int key, FilePath* result);
|
||||
#if defined(OS_WIN)
|
||||
bool PathProviderWin(int key, FilePath* result);
|
||||
#elif defined(OS_MACOSX)
|
||||
bool PathProviderMac(int key, FilePath* result);
|
||||
#elif defined(OS_ANDROID)
|
||||
bool PathProviderAndroid(int key, FilePath* result);
|
||||
#elif defined(OS_POSIX)
|
||||
// PathProviderPosix is the default path provider on POSIX OSes other than
|
||||
// Mac and Android.
|
||||
bool PathProviderPosix(int key, FilePath* result);
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
typedef base::hash_map<int, FilePath> PathMap;
|
||||
|
||||
// We keep a linked list of providers. In a debug build we ensure that no two
|
||||
// providers claim overlapping keys.
|
||||
struct Provider {
|
||||
PathService::ProviderFunc func;
|
||||
struct Provider* next;
|
||||
#ifndef NDEBUG
|
||||
int key_start;
|
||||
int key_end;
|
||||
#endif
|
||||
bool is_static;
|
||||
};
|
||||
|
||||
Provider base_provider = {
|
||||
base::PathProvider,
|
||||
NULL,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_START,
|
||||
base::PATH_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
|
||||
#if defined(OS_WIN)
|
||||
Provider base_provider_win = {
|
||||
base::PathProviderWin,
|
||||
&base_provider,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_WIN_START,
|
||||
base::PATH_WIN_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
Provider base_provider_mac = {
|
||||
base::PathProviderMac,
|
||||
&base_provider,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_MAC_START,
|
||||
base::PATH_MAC_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
Provider base_provider_android = {
|
||||
base::PathProviderAndroid,
|
||||
&base_provider,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_ANDROID_START,
|
||||
base::PATH_ANDROID_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
|
||||
Provider base_provider_posix = {
|
||||
base::PathProviderPosix,
|
||||
&base_provider,
|
||||
#ifndef NDEBUG
|
||||
base::PATH_POSIX_START,
|
||||
base::PATH_POSIX_END,
|
||||
#endif
|
||||
true
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct PathData {
|
||||
base::Lock lock;
|
||||
PathMap cache; // Cache mappings from path key to path value.
|
||||
PathMap overrides; // Track path overrides.
|
||||
Provider* providers; // Linked list of path service providers.
|
||||
bool cache_disabled; // Don't use cache if true;
|
||||
|
||||
PathData() : cache_disabled(false) {
|
||||
#if defined(OS_WIN)
|
||||
providers = &base_provider_win;
|
||||
#elif defined(OS_MACOSX)
|
||||
providers = &base_provider_mac;
|
||||
#elif defined(OS_ANDROID)
|
||||
providers = &base_provider_android;
|
||||
#elif defined(OS_POSIX)
|
||||
providers = &base_provider_posix;
|
||||
#endif
|
||||
}
|
||||
|
||||
~PathData() {
|
||||
Provider* p = providers;
|
||||
while (p) {
|
||||
Provider* next = p->next;
|
||||
if (!p->is_static)
|
||||
delete p;
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
|
||||
|
||||
static PathData* GetPathData() {
|
||||
return g_path_data.Pointer();
|
||||
}
|
||||
|
||||
// Tries to find |key| in the cache. |path_data| should be locked by the caller!
|
||||
bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) {
|
||||
if (path_data->cache_disabled)
|
||||
return false;
|
||||
// check for a cached version
|
||||
PathMap::const_iterator it = path_data->cache.find(key);
|
||||
if (it != path_data->cache.end()) {
|
||||
*result = it->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tries to find |key| in the overrides map. |path_data| should be locked by the
|
||||
// caller!
|
||||
bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) {
|
||||
// check for an overridden version.
|
||||
PathMap::const_iterator it = path_data->overrides.find(key);
|
||||
if (it != path_data->overrides.end()) {
|
||||
if (!path_data->cache_disabled)
|
||||
path_data->cache[key] = it->second;
|
||||
*result = it->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
|
||||
// characters). This isn't supported very well by Windows right now, so it is
|
||||
// moot, but we should keep this in mind for the future.
|
||||
// static
|
||||
bool PathService::Get(int key, FilePath* result) {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
DCHECK(result);
|
||||
DCHECK_GE(key, base::DIR_CURRENT);
|
||||
|
||||
// special case the current directory because it can never be cached
|
||||
if (key == base::DIR_CURRENT)
|
||||
return file_util::GetCurrentDirectory(result);
|
||||
|
||||
Provider* provider = NULL;
|
||||
{
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
if (LockedGetFromCache(key, path_data, result))
|
||||
return true;
|
||||
|
||||
if (LockedGetFromOverrides(key, path_data, result))
|
||||
return true;
|
||||
|
||||
// Get the beginning of the list while it is still locked.
|
||||
provider = path_data->providers;
|
||||
}
|
||||
|
||||
FilePath path;
|
||||
|
||||
// Iterating does not need the lock because only the list head might be
|
||||
// modified on another thread.
|
||||
while (provider) {
|
||||
if (provider->func(key, &path))
|
||||
break;
|
||||
DCHECK(path.empty()) << "provider should not have modified path";
|
||||
provider = provider->next;
|
||||
}
|
||||
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
if (path.ReferencesParent()) {
|
||||
// Make sure path service never returns a path with ".." in it.
|
||||
path = MakeAbsoluteFilePath(path);
|
||||
if (path.empty())
|
||||
return false;
|
||||
}
|
||||
*result = path;
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
if (!path_data->cache_disabled)
|
||||
path_data->cache[key] = path;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool PathService::Override(int key, const FilePath& path) {
|
||||
// Just call the full function with true for the value of |create|.
|
||||
return OverrideAndCreateIfNeeded(key, path, true);
|
||||
}
|
||||
|
||||
// static
|
||||
bool PathService::OverrideAndCreateIfNeeded(int key,
|
||||
const FilePath& path,
|
||||
bool create) {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key";
|
||||
|
||||
FilePath file_path = path;
|
||||
|
||||
// For some locations this will fail if called from inside the sandbox there-
|
||||
// fore we protect this call with a flag.
|
||||
if (create) {
|
||||
// Make sure the directory exists. We need to do this before we translate
|
||||
// this to the absolute path because on POSIX, MakeAbsoluteFilePath fails
|
||||
// if called on a non-existent path.
|
||||
if (!base::PathExists(file_path) &&
|
||||
!file_util::CreateDirectory(file_path))
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to have an absolute path.
|
||||
file_path = MakeAbsoluteFilePath(file_path);
|
||||
if (file_path.empty())
|
||||
return false;
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
|
||||
// Clear the cache now. Some of its entries could have depended
|
||||
// on the value we are overriding, and are now out of sync with reality.
|
||||
path_data->cache.clear();
|
||||
|
||||
path_data->overrides[key] = file_path;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool PathService::RemoveOverride(int key) {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
|
||||
if (path_data->overrides.find(key) == path_data->overrides.end())
|
||||
return false;
|
||||
|
||||
// Clear the cache now. Some of its entries could have depended on the value
|
||||
// we are going to remove, and are now out of sync.
|
||||
path_data->cache.clear();
|
||||
|
||||
path_data->overrides.erase(key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void PathService::RegisterProvider(ProviderFunc func, int key_start,
|
||||
int key_end) {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
DCHECK_GT(key_end, key_start);
|
||||
|
||||
Provider* p;
|
||||
|
||||
p = new Provider;
|
||||
p->is_static = false;
|
||||
p->func = func;
|
||||
#ifndef NDEBUG
|
||||
p->key_start = key_start;
|
||||
p->key_end = key_end;
|
||||
#endif
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
|
||||
#ifndef NDEBUG
|
||||
Provider *iter = path_data->providers;
|
||||
while (iter) {
|
||||
DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
|
||||
"path provider collision";
|
||||
iter = iter->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
p->next = path_data->providers;
|
||||
path_data->providers = p;
|
||||
}
|
||||
|
||||
// static
|
||||
void PathService::DisableCache() {
|
||||
PathData* path_data = GetPathData();
|
||||
DCHECK(path_data);
|
||||
|
||||
base::AutoLock scoped_lock(path_data->lock);
|
||||
path_data->cache.clear();
|
||||
path_data->cache_disabled = true;
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// 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;
|
||||
} // namespace
|
||||
|
||||
// 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, base::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.
|
||||
static bool Override(int key, const base::FilePath& path);
|
||||
|
||||
// This function does the same as PathService::Override but it takes an extra
|
||||
// parameter |create| which guides whether the directory to be overriden must
|
||||
// be created in case it doesn't exist already.
|
||||
static bool OverrideAndCreateIfNeeded(int key,
|
||||
const base::FilePath& path,
|
||||
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, base::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 base::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);
|
||||
};
|
||||
|
||||
#endif // BASE_PATH_SERVICE_H_
|
|
@ -0,0 +1,60 @@
|
|||
// 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 PENDING_TASK_H_
|
||||
#define PENDING_TASK_H_
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/location.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/tracking_info.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Contains data about a pending task. Stored in TaskQueue and DelayedTaskQueue
|
||||
// for use by classes that queue and execute tasks.
|
||||
struct BASE_EXPORT PendingTask : public TrackingInfo {
|
||||
#if _MSC_VER >= 1700
|
||||
PendingTask();
|
||||
#endif
|
||||
PendingTask(const tracked_objects::Location& posted_from,
|
||||
const Closure& task);
|
||||
PendingTask(const tracked_objects::Location& posted_from,
|
||||
const Closure& task,
|
||||
TimeTicks delayed_run_time,
|
||||
bool nestable);
|
||||
~PendingTask();
|
||||
|
||||
// Used to support sorting.
|
||||
bool operator<(const PendingTask& other) const;
|
||||
|
||||
// The task to run.
|
||||
Closure task;
|
||||
|
||||
// The site this PendingTask was posted from.
|
||||
tracked_objects::Location posted_from;
|
||||
|
||||
// Secondary sort key for run time.
|
||||
int sequence_num;
|
||||
|
||||
// OK to dispatch from a nested loop.
|
||||
bool nestable;
|
||||
};
|
||||
|
||||
// Wrapper around std::queue specialized for PendingTask which adds a Swap
|
||||
// helper method.
|
||||
class BASE_EXPORT TaskQueue : public std::queue<PendingTask> {
|
||||
public:
|
||||
void Swap(TaskQueue* queue);
|
||||
};
|
||||
|
||||
// PendingTasks are sorted by their |delayed_run_time| property.
|
||||
typedef std::priority_queue<base::PendingTask> DelayedTaskQueue;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // PENDING_TASK_H_
|
|
@ -0,0 +1,31 @@
|
|||
// 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/platform_file.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
PlatformFileInfo::PlatformFileInfo()
|
||||
: size(0),
|
||||
is_directory(false),
|
||||
is_symbolic_link(false) {
|
||||
}
|
||||
|
||||
PlatformFileInfo::~PlatformFileInfo() {}
|
||||
|
||||
#if !defined(OS_NACL)
|
||||
PlatformFile CreatePlatformFile(const FilePath& name,
|
||||
int flags,
|
||||
bool* created,
|
||||
PlatformFileError* error) {
|
||||
if (name.ReferencesParent()) {
|
||||
if (error)
|
||||
*error = PLATFORM_FILE_ERROR_ACCESS_DENIED;
|
||||
return kInvalidPlatformFileValue;
|
||||
}
|
||||
return CreatePlatformFileUnsafe(name, flags, created, error);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace base
|
|
@ -0,0 +1,254 @@
|
|||
// 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_PLATFORM_FILE_H_
|
||||
#define BASE_PLATFORM_FILE_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/time/time.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// PLATFORM_FILE_(OPEN|CREATE).* are mutually exclusive. You should specify
|
||||
// exactly one of the five (possibly combining with other flags) when opening
|
||||
// or creating a file.
|
||||
// PLATFORM_FILE_(WRITE|APPEND) are mutually exclusive. This is so that APPEND
|
||||
// behavior will be consistent with O_APPEND on POSIX.
|
||||
enum PlatformFileFlags {
|
||||
PLATFORM_FILE_OPEN = 1 << 0, // Opens a file, only if it exists.
|
||||
PLATFORM_FILE_CREATE = 1 << 1, // Creates a new file, only if it
|
||||
// does not already exist.
|
||||
PLATFORM_FILE_OPEN_ALWAYS = 1 << 2, // May create a new file.
|
||||
PLATFORM_FILE_CREATE_ALWAYS = 1 << 3, // May overwrite an old file.
|
||||
PLATFORM_FILE_OPEN_TRUNCATED = 1 << 4, // Opens a file and truncates it,
|
||||
// only if it exists.
|
||||
PLATFORM_FILE_READ = 1 << 5,
|
||||
PLATFORM_FILE_WRITE = 1 << 6,
|
||||
PLATFORM_FILE_APPEND = 1 << 7,
|
||||
PLATFORM_FILE_EXCLUSIVE_READ = 1 << 8, // EXCLUSIVE is opposite of Windows
|
||||
// SHARE
|
||||
PLATFORM_FILE_EXCLUSIVE_WRITE = 1 << 9,
|
||||
PLATFORM_FILE_ASYNC = 1 << 10,
|
||||
PLATFORM_FILE_TEMPORARY = 1 << 11, // Used on Windows only
|
||||
PLATFORM_FILE_HIDDEN = 1 << 12, // Used on Windows only
|
||||
PLATFORM_FILE_DELETE_ON_CLOSE = 1 << 13,
|
||||
|
||||
PLATFORM_FILE_WRITE_ATTRIBUTES = 1 << 14, // Used on Windows only
|
||||
PLATFORM_FILE_ENUMERATE = 1 << 15, // May enumerate directory
|
||||
|
||||
PLATFORM_FILE_SHARE_DELETE = 1 << 16, // Used on Windows only
|
||||
|
||||
PLATFORM_FILE_TERMINAL_DEVICE = 1 << 17, // Serial port flags
|
||||
PLATFORM_FILE_BACKUP_SEMANTICS = 1 << 18, // Used on Windows only
|
||||
|
||||
PLATFORM_FILE_EXECUTE = 1 << 19, // Used on Windows only
|
||||
};
|
||||
|
||||
// PLATFORM_FILE_ERROR_ACCESS_DENIED is returned when a call fails because of
|
||||
// a filesystem restriction. PLATFORM_FILE_ERROR_SECURITY is returned when a
|
||||
// browser policy doesn't allow the operation to be executed.
|
||||
enum PlatformFileError {
|
||||
PLATFORM_FILE_OK = 0,
|
||||
PLATFORM_FILE_ERROR_FAILED = -1,
|
||||
PLATFORM_FILE_ERROR_IN_USE = -2,
|
||||
PLATFORM_FILE_ERROR_EXISTS = -3,
|
||||
PLATFORM_FILE_ERROR_NOT_FOUND = -4,
|
||||
PLATFORM_FILE_ERROR_ACCESS_DENIED = -5,
|
||||
PLATFORM_FILE_ERROR_TOO_MANY_OPENED = -6,
|
||||
PLATFORM_FILE_ERROR_NO_MEMORY = -7,
|
||||
PLATFORM_FILE_ERROR_NO_SPACE = -8,
|
||||
PLATFORM_FILE_ERROR_NOT_A_DIRECTORY = -9,
|
||||
PLATFORM_FILE_ERROR_INVALID_OPERATION = -10,
|
||||
PLATFORM_FILE_ERROR_SECURITY = -11,
|
||||
PLATFORM_FILE_ERROR_ABORT = -12,
|
||||
PLATFORM_FILE_ERROR_NOT_A_FILE = -13,
|
||||
PLATFORM_FILE_ERROR_NOT_EMPTY = -14,
|
||||
PLATFORM_FILE_ERROR_INVALID_URL = -15,
|
||||
PLATFORM_FILE_ERROR_IO = -16,
|
||||
// Put new entries here and increment PLATFORM_FILE_ERROR_MAX.
|
||||
PLATFORM_FILE_ERROR_MAX = -17
|
||||
};
|
||||
|
||||
// This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux.
|
||||
enum PlatformFileWhence {
|
||||
PLATFORM_FILE_FROM_BEGIN = 0,
|
||||
PLATFORM_FILE_FROM_CURRENT = 1,
|
||||
PLATFORM_FILE_FROM_END = 2
|
||||
};
|
||||
|
||||
// Used to hold information about a given file.
|
||||
// If you add more fields to this structure (platform-specific fields are OK),
|
||||
// make sure to update all functions that use it in file_util_{win|posix}.cc
|
||||
// too, and the ParamTraits<base::PlatformFileInfo> implementation in
|
||||
// chrome/common/common_param_traits.cc.
|
||||
struct BASE_EXPORT PlatformFileInfo {
|
||||
PlatformFileInfo();
|
||||
~PlatformFileInfo();
|
||||
|
||||
// The size of the file in bytes. Undefined when is_directory is true.
|
||||
int64 size;
|
||||
|
||||
// True if the file corresponds to a directory.
|
||||
bool is_directory;
|
||||
|
||||
// True if the file corresponds to a symbolic link.
|
||||
bool is_symbolic_link;
|
||||
|
||||
// The last modified time of a file.
|
||||
base::Time last_modified;
|
||||
|
||||
// The last accessed time of a file.
|
||||
base::Time last_accessed;
|
||||
|
||||
// The creation time of a file.
|
||||
base::Time creation_time;
|
||||
};
|
||||
|
||||
#if defined(OS_WIN)
|
||||
typedef HANDLE PlatformFile;
|
||||
const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
|
||||
PlatformFileError LastErrorToPlatformFileError(DWORD saved_errno);
|
||||
#elif defined(OS_POSIX)
|
||||
typedef int PlatformFile;
|
||||
const PlatformFile kInvalidPlatformFileValue = -1;
|
||||
PlatformFileError ErrnoToPlatformFileError(int saved_errno);
|
||||
#endif
|
||||
|
||||
// Creates or opens the given file. If |created| is provided, it will be set to
|
||||
// true if a new file was created [or an old one truncated to zero length to
|
||||
// simulate a new file, which can happen with PLATFORM_FILE_CREATE_ALWAYS], and
|
||||
// false otherwise. |error| can be NULL.
|
||||
//
|
||||
// This function fails with 'access denied' if the |name| contains path
|
||||
// traversal ('..') components.
|
||||
BASE_EXPORT PlatformFile CreatePlatformFile(const FilePath& name,
|
||||
int flags,
|
||||
bool* created,
|
||||
PlatformFileError* error);
|
||||
|
||||
// Same as CreatePlatformFile but allows paths with traversal (like \..\)
|
||||
// components. Use only with extreme care.
|
||||
BASE_EXPORT PlatformFile CreatePlatformFileUnsafe(const FilePath& name,
|
||||
int flags,
|
||||
bool* created,
|
||||
PlatformFileError* error);
|
||||
|
||||
BASE_EXPORT FILE* FdopenPlatformFile(PlatformFile file, const char* mode);
|
||||
|
||||
// Closes a file handle. Returns |true| on success and |false| otherwise.
|
||||
BASE_EXPORT bool ClosePlatformFile(PlatformFile file);
|
||||
|
||||
// Changes current position in the file to an |offset| relative to an origin
|
||||
// defined by |whence|. Returns the resultant current position in the file
|
||||
// (relative to the start) or -1 in case of error.
|
||||
BASE_EXPORT int64 SeekPlatformFile(PlatformFile file,
|
||||
PlatformFileWhence whence,
|
||||
int64 offset);
|
||||
|
||||
// Reads the given number of bytes (or until EOF is reached) starting with the
|
||||
// given offset. Returns the number of bytes read, or -1 on error. Note that
|
||||
// this function makes a best effort to read all data on all platforms, so it is
|
||||
// not intended for stream oriented files but instead for cases when the normal
|
||||
// expectation is that actually |size| bytes are read unless there is an error.
|
||||
BASE_EXPORT int ReadPlatformFile(PlatformFile file, int64 offset,
|
||||
char* data, int size);
|
||||
|
||||
// Same as above but without seek.
|
||||
BASE_EXPORT int ReadPlatformFileAtCurrentPos(PlatformFile file,
|
||||
char* data, int size);
|
||||
|
||||
// Reads the given number of bytes (or until EOF is reached) starting with the
|
||||
// given offset, but does not make any effort to read all data on all platforms.
|
||||
// Returns the number of bytes read, or -1 on error.
|
||||
BASE_EXPORT int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset,
|
||||
char* data, int size);
|
||||
|
||||
// Same as above but without seek.
|
||||
BASE_EXPORT int ReadPlatformFileCurPosNoBestEffort(PlatformFile file,
|
||||
char* data, int size);
|
||||
|
||||
// Writes the given buffer into the file at the given offset, overwritting any
|
||||
// data that was previously there. Returns the number of bytes written, or -1
|
||||
// on error. Note that this function makes a best effort to write all data on
|
||||
// all platforms.
|
||||
// Ignores the offset and writes to the end of the file if the file was opened
|
||||
// with PLATFORM_FILE_APPEND.
|
||||
BASE_EXPORT int WritePlatformFile(PlatformFile file, int64 offset,
|
||||
const char* data, int size);
|
||||
|
||||
// Save as above but without seek.
|
||||
BASE_EXPORT int WritePlatformFileAtCurrentPos(PlatformFile file,
|
||||
const char* data, int size);
|
||||
|
||||
// Save as above but does not make any effort to write all data on all
|
||||
// platforms. Returns the number of bytes written, or -1 on error.
|
||||
BASE_EXPORT int WritePlatformFileCurPosNoBestEffort(PlatformFile file,
|
||||
const char* data, int size);
|
||||
|
||||
// Truncates the given file to the given length. If |length| is greater than
|
||||
// the current size of the file, the file is extended with zeros. If the file
|
||||
// doesn't exist, |false| is returned.
|
||||
BASE_EXPORT bool TruncatePlatformFile(PlatformFile file, int64 length);
|
||||
|
||||
// Flushes the buffers of the given file.
|
||||
BASE_EXPORT bool FlushPlatformFile(PlatformFile file);
|
||||
|
||||
// Touches the given file.
|
||||
BASE_EXPORT bool TouchPlatformFile(PlatformFile file,
|
||||
const Time& last_access_time,
|
||||
const Time& last_modified_time);
|
||||
|
||||
// Returns some information for the given file.
|
||||
BASE_EXPORT bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info);
|
||||
|
||||
// Use this class to pass ownership of a PlatformFile to a receiver that may or
|
||||
// may not want to accept it. This class does not own the storage for the
|
||||
// PlatformFile.
|
||||
//
|
||||
// EXAMPLE:
|
||||
//
|
||||
// void MaybeProcessFile(PassPlatformFile pass_file) {
|
||||
// if (...) {
|
||||
// PlatformFile file = pass_file.ReleaseValue();
|
||||
// // Now, we are responsible for closing |file|.
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void OpenAndMaybeProcessFile(const FilePath& path) {
|
||||
// PlatformFile file = CreatePlatformFile(path, ...);
|
||||
// MaybeProcessFile(PassPlatformFile(&file));
|
||||
// if (file != kInvalidPlatformFileValue)
|
||||
// ClosePlatformFile(file);
|
||||
// }
|
||||
//
|
||||
class BASE_EXPORT PassPlatformFile {
|
||||
public:
|
||||
explicit PassPlatformFile(PlatformFile* value) : value_(value) {
|
||||
}
|
||||
|
||||
// Called to retrieve the PlatformFile stored in this object. The caller
|
||||
// gains ownership of the PlatformFile and is now responsible for closing it.
|
||||
// Any subsequent calls to this method will return an invalid PlatformFile.
|
||||
PlatformFile ReleaseValue() {
|
||||
PlatformFile temp = *value_;
|
||||
*value_ = kInvalidPlatformFileValue;
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
PlatformFile* value_;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_PLATFORM_FILE_H_
|
|
@ -0,0 +1,301 @@
|
|||
// 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/platform_file.h"
|
||||
|
||||
#include <io.h>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/metrics/sparse_histogram.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
|
||||
namespace base {
|
||||
PlatformFile CreatePlatformFileUnsafe(const FilePath& name,
|
||||
int flags,
|
||||
bool* created,
|
||||
PlatformFileError* error) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
|
||||
DWORD disposition = 0;
|
||||
if (created)
|
||||
*created = false;
|
||||
|
||||
if (flags & PLATFORM_FILE_OPEN)
|
||||
disposition = OPEN_EXISTING;
|
||||
|
||||
if (flags & PLATFORM_FILE_CREATE) {
|
||||
DCHECK(!disposition);
|
||||
disposition = CREATE_NEW;
|
||||
}
|
||||
|
||||
if (flags & PLATFORM_FILE_OPEN_ALWAYS) {
|
||||
DCHECK(!disposition);
|
||||
disposition = OPEN_ALWAYS;
|
||||
}
|
||||
|
||||
if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
|
||||
DCHECK(!disposition);
|
||||
disposition = CREATE_ALWAYS;
|
||||
}
|
||||
|
||||
if (flags & PLATFORM_FILE_OPEN_TRUNCATED) {
|
||||
DCHECK(!disposition);
|
||||
DCHECK(flags & PLATFORM_FILE_WRITE);
|
||||
disposition = TRUNCATE_EXISTING;
|
||||
}
|
||||
|
||||
if (!disposition) {
|
||||
NOTREACHED();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWORD access = 0;
|
||||
if (flags & PLATFORM_FILE_WRITE)
|
||||
access = GENERIC_WRITE;
|
||||
if (flags & PLATFORM_FILE_APPEND) {
|
||||
DCHECK(!access);
|
||||
access = FILE_APPEND_DATA;
|
||||
}
|
||||
if (flags & PLATFORM_FILE_READ)
|
||||
access |= GENERIC_READ;
|
||||
if (flags & PLATFORM_FILE_WRITE_ATTRIBUTES)
|
||||
access |= FILE_WRITE_ATTRIBUTES;
|
||||
if (flags & PLATFORM_FILE_EXECUTE)
|
||||
access |= GENERIC_EXECUTE;
|
||||
|
||||
DWORD sharing = (flags & PLATFORM_FILE_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
|
||||
if (!(flags & PLATFORM_FILE_EXCLUSIVE_WRITE))
|
||||
sharing |= FILE_SHARE_WRITE;
|
||||
if (flags & PLATFORM_FILE_SHARE_DELETE)
|
||||
sharing |= FILE_SHARE_DELETE;
|
||||
|
||||
DWORD create_flags = 0;
|
||||
if (flags & PLATFORM_FILE_ASYNC)
|
||||
create_flags |= FILE_FLAG_OVERLAPPED;
|
||||
if (flags & PLATFORM_FILE_TEMPORARY)
|
||||
create_flags |= FILE_ATTRIBUTE_TEMPORARY;
|
||||
if (flags & PLATFORM_FILE_HIDDEN)
|
||||
create_flags |= FILE_ATTRIBUTE_HIDDEN;
|
||||
if (flags & PLATFORM_FILE_DELETE_ON_CLOSE)
|
||||
create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
|
||||
if (flags & PLATFORM_FILE_BACKUP_SEMANTICS)
|
||||
create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
|
||||
|
||||
HANDLE file = CreateFile(name.value().c_str(), access, sharing, NULL,
|
||||
disposition, create_flags, NULL);
|
||||
|
||||
if (created && (INVALID_HANDLE_VALUE != file)) {
|
||||
if (flags & (PLATFORM_FILE_OPEN_ALWAYS))
|
||||
*created = (ERROR_ALREADY_EXISTS != GetLastError());
|
||||
else if (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE))
|
||||
*created = true;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
if (file != kInvalidPlatformFileValue)
|
||||
*error = PLATFORM_FILE_OK;
|
||||
else
|
||||
*error = LastErrorToPlatformFileError(GetLastError());
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
FILE* FdopenPlatformFile(PlatformFile file, const char* mode) {
|
||||
if (file == kInvalidPlatformFileValue)
|
||||
return NULL;
|
||||
int fd = _open_osfhandle(reinterpret_cast<intptr_t>(file), 0);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
return _fdopen(fd, mode);
|
||||
}
|
||||
|
||||
bool ClosePlatformFile(PlatformFile file) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
return (CloseHandle(file) != 0);
|
||||
}
|
||||
|
||||
int64 SeekPlatformFile(PlatformFile file,
|
||||
PlatformFileWhence whence,
|
||||
int64 offset) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
if (file == kInvalidPlatformFileValue || offset < 0)
|
||||
return -1;
|
||||
|
||||
LARGE_INTEGER distance, res;
|
||||
distance.QuadPart = offset;
|
||||
DWORD move_method = static_cast<DWORD>(whence);
|
||||
if (!SetFilePointerEx(file, distance, &res, move_method))
|
||||
return -1;
|
||||
return res.QuadPart;
|
||||
}
|
||||
|
||||
int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
if (file == kInvalidPlatformFileValue)
|
||||
return -1;
|
||||
|
||||
LARGE_INTEGER offset_li;
|
||||
offset_li.QuadPart = offset;
|
||||
|
||||
OVERLAPPED overlapped = {0};
|
||||
overlapped.Offset = offset_li.LowPart;
|
||||
overlapped.OffsetHigh = offset_li.HighPart;
|
||||
|
||||
DWORD bytes_read;
|
||||
if (::ReadFile(file, data, size, &bytes_read, &overlapped) != 0)
|
||||
return bytes_read;
|
||||
else if (ERROR_HANDLE_EOF == GetLastError())
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) {
|
||||
return ReadPlatformFile(file, 0, data, size);
|
||||
}
|
||||
|
||||
int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset, char* data,
|
||||
int size) {
|
||||
return ReadPlatformFile(file, offset, data, size);
|
||||
}
|
||||
|
||||
int ReadPlatformFileCurPosNoBestEffort(PlatformFile file,
|
||||
char* data, int size) {
|
||||
return ReadPlatformFile(file, 0, data, size);
|
||||
}
|
||||
|
||||
int WritePlatformFile(PlatformFile file, int64 offset,
|
||||
const char* data, int size) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
if (file == kInvalidPlatformFileValue)
|
||||
return -1;
|
||||
|
||||
LARGE_INTEGER offset_li;
|
||||
offset_li.QuadPart = offset;
|
||||
|
||||
OVERLAPPED overlapped = {0};
|
||||
overlapped.Offset = offset_li.LowPart;
|
||||
overlapped.OffsetHigh = offset_li.HighPart;
|
||||
|
||||
DWORD bytes_written;
|
||||
if (::WriteFile(file, data, size, &bytes_written, &overlapped) != 0)
|
||||
return bytes_written;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WritePlatformFileAtCurrentPos(PlatformFile file, const char* data,
|
||||
int size) {
|
||||
return WritePlatformFile(file, 0, data, size);
|
||||
}
|
||||
|
||||
int WritePlatformFileCurPosNoBestEffort(PlatformFile file,
|
||||
const char* data, int size) {
|
||||
return WritePlatformFile(file, 0, data, size);
|
||||
}
|
||||
|
||||
bool TruncatePlatformFile(PlatformFile file, int64 length) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
if (file == kInvalidPlatformFileValue)
|
||||
return false;
|
||||
|
||||
// Get the current file pointer.
|
||||
LARGE_INTEGER file_pointer;
|
||||
LARGE_INTEGER zero;
|
||||
zero.QuadPart = 0;
|
||||
if (::SetFilePointerEx(file, zero, &file_pointer, FILE_CURRENT) == 0)
|
||||
return false;
|
||||
|
||||
LARGE_INTEGER length_li;
|
||||
length_li.QuadPart = length;
|
||||
// If length > file size, SetFilePointerEx() should extend the file
|
||||
// with zeroes on all Windows standard file systems (NTFS, FATxx).
|
||||
if (!::SetFilePointerEx(file, length_li, NULL, FILE_BEGIN))
|
||||
return false;
|
||||
|
||||
// Set the new file length and move the file pointer to its old position.
|
||||
// This is consistent with ftruncate()'s behavior, even when the file
|
||||
// pointer points to a location beyond the end of the file.
|
||||
return ((::SetEndOfFile(file) != 0) &&
|
||||
(::SetFilePointerEx(file, file_pointer, NULL, FILE_BEGIN) != 0));
|
||||
}
|
||||
|
||||
bool FlushPlatformFile(PlatformFile file) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
return ((file != kInvalidPlatformFileValue) && ::FlushFileBuffers(file));
|
||||
}
|
||||
|
||||
bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
|
||||
const base::Time& last_modified_time) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
if (file == kInvalidPlatformFileValue)
|
||||
return false;
|
||||
|
||||
FILETIME last_access_filetime = last_access_time.ToFileTime();
|
||||
FILETIME last_modified_filetime = last_modified_time.ToFileTime();
|
||||
return (::SetFileTime(file, NULL, &last_access_filetime,
|
||||
&last_modified_filetime) != 0);
|
||||
}
|
||||
|
||||
bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
|
||||
base::ThreadRestrictions::AssertIOAllowed();
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION file_info;
|
||||
if (GetFileInformationByHandle(file, &file_info) == 0)
|
||||
return false;
|
||||
|
||||
LARGE_INTEGER size;
|
||||
size.HighPart = file_info.nFileSizeHigh;
|
||||
size.LowPart = file_info.nFileSizeLow;
|
||||
info->size = size.QuadPart;
|
||||
info->is_directory =
|
||||
(file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
info->is_symbolic_link = false; // Windows doesn't have symbolic links.
|
||||
info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime);
|
||||
info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime);
|
||||
info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime);
|
||||
return true;
|
||||
}
|
||||
|
||||
PlatformFileError LastErrorToPlatformFileError(DWORD last_error) {
|
||||
switch (last_error) {
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
return PLATFORM_FILE_ERROR_IN_USE;
|
||||
case ERROR_FILE_EXISTS:
|
||||
return PLATFORM_FILE_ERROR_EXISTS;
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return PLATFORM_FILE_ERROR_NOT_FOUND;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return PLATFORM_FILE_ERROR_ACCESS_DENIED;
|
||||
case ERROR_TOO_MANY_OPEN_FILES:
|
||||
return PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
|
||||
case ERROR_OUTOFMEMORY:
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
return PLATFORM_FILE_ERROR_NO_MEMORY;
|
||||
case ERROR_HANDLE_DISK_FULL:
|
||||
case ERROR_DISK_FULL:
|
||||
case ERROR_DISK_RESOURCES_EXHAUSTED:
|
||||
return PLATFORM_FILE_ERROR_NO_SPACE;
|
||||
case ERROR_USER_MAPPED_FILE:
|
||||
return PLATFORM_FILE_ERROR_INVALID_OPERATION;
|
||||
case ERROR_NOT_READY:
|
||||
case ERROR_SECTOR_NOT_FOUND:
|
||||
case ERROR_DEV_NOT_EXIST:
|
||||
case ERROR_IO_DEVICE:
|
||||
case ERROR_FILE_CORRUPT:
|
||||
case ERROR_DISK_CORRUPT:
|
||||
return PLATFORM_FILE_ERROR_IO;
|
||||
default:
|
||||
UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
|
||||
last_error);
|
||||
return PLATFORM_FILE_ERROR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_PORT_H_
|
||||
#define BASE_PORT_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "build/build_config.h"
|
||||
|
||||
#ifdef COMPILER_MSVC
|
||||
#define GG_LONGLONG(x) x##I64
|
||||
#define GG_ULONGLONG(x) x##UI64
|
||||
#else
|
||||
#define GG_LONGLONG(x) x##LL
|
||||
#define GG_ULONGLONG(x) x##ULL
|
||||
#endif
|
||||
|
||||
// Per C99 7.8.14, define __STDC_CONSTANT_MACROS before including <stdint.h>
|
||||
// to get the INTn_C and UINTn_C macros for integer constants. It's difficult
|
||||
// to guarantee any specific ordering of header includes, so it's difficult to
|
||||
// guarantee that the INTn_C macros can be defined by including <stdint.h> at
|
||||
// any specific point. Provide GG_INTn_C macros instead.
|
||||
|
||||
#define GG_INT8_C(x) (x)
|
||||
#define GG_INT16_C(x) (x)
|
||||
#define GG_INT32_C(x) (x)
|
||||
#define GG_INT64_C(x) GG_LONGLONG(x)
|
||||
|
||||
#define GG_UINT8_C(x) (x ## U)
|
||||
#define GG_UINT16_C(x) (x ## U)
|
||||
#define GG_UINT32_C(x) (x ## U)
|
||||
#define GG_UINT64_C(x) GG_ULONGLONG(x)
|
||||
|
||||
// It's possible for functions that use a va_list, such as StringPrintf, to
|
||||
// invalidate the data in it upon use. The fix is to make a copy of the
|
||||
// structure before using it and use that copy instead. va_copy is provided
|
||||
// for this purpose. MSVC does not provide va_copy, so define an
|
||||
// implementation here. It is not guaranteed that assignment is a copy, so the
|
||||
// StringUtil.VariableArgsFunc unit test tests this capability.
|
||||
#if defined(COMPILER_GCC)
|
||||
#define GG_VA_COPY(a, b) (va_copy(a, b))
|
||||
#elif defined(COMPILER_MSVC)
|
||||
#define GG_VA_COPY(a, b) (a = b)
|
||||
#endif
|
||||
|
||||
// Define an OS-neutral wrapper for shared library entry points
|
||||
#if defined(OS_WIN)
|
||||
#define API_CALL __stdcall
|
||||
#else
|
||||
#define API_CALL
|
||||
#endif
|
||||
|
||||
#endif // BASE_PORT_H_
|
|
@ -0,0 +1,96 @@
|
|||
// 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 "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
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.
|
||||
BASE_EXPORT ProcessId GetCurrentProcId();
|
||||
|
||||
// Returns the ProcessHandle of the current process.
|
||||
BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
|
||||
|
||||
// Converts a PID to a process handle. This handle must be closed by
|
||||
// CloseProcessHandle when you are done with it. Returns true on success.
|
||||
BASE_EXPORT bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
|
||||
|
||||
// Converts a PID to a process handle. On Windows the handle is opened
|
||||
// with more access rights and must only be used by trusted code.
|
||||
// You have to close returned handle using CloseProcessHandle. Returns true
|
||||
// on success.
|
||||
// TODO(sanjeevr): Replace all calls to OpenPrivilegedProcessHandle with the
|
||||
// more specific OpenProcessHandleWithAccess method and delete this.
|
||||
BASE_EXPORT bool OpenPrivilegedProcessHandle(ProcessId pid,
|
||||
ProcessHandle* handle);
|
||||
|
||||
// Converts a PID to a process handle using the desired access flags. Use a
|
||||
// combination of the kProcessAccess* flags defined above for |access_flags|.
|
||||
BASE_EXPORT bool OpenProcessHandleWithAccess(ProcessId pid,
|
||||
uint32 access_flags,
|
||||
ProcessHandle* handle);
|
||||
|
||||
// Closes the process handle opened by OpenProcessHandle.
|
||||
BASE_EXPORT void CloseProcessHandle(ProcessHandle process);
|
||||
|
||||
// Returns the unique ID for the specified process. This is functionally the
|
||||
// same as Windows' GetProcessId(), but works on versions of Windows before
|
||||
// Win XP SP1 as well.
|
||||
BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
enum IntegrityLevel {
|
||||
INTEGRITY_UNKNOWN,
|
||||
LOW_INTEGRITY,
|
||||
MEDIUM_INTEGRITY,
|
||||
HIGH_INTEGRITY,
|
||||
};
|
||||
// Determine the integrity level of the specified process. Returns false
|
||||
// if the system does not support integrity levels (pre-Vista) or in the case
|
||||
// of an underlying system failure.
|
||||
BASE_EXPORT bool GetProcessIntegrityLevel(ProcessHandle process,
|
||||
IntegrityLevel* level);
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_BSD)
|
||||
// Returns the path to the executable of the given process.
|
||||
BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// Returns the ID for the parent of the given process.
|
||||
BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_PROCESS_PROCESS_HANDLE_H_
|
|
@ -0,0 +1,44 @@
|
|||
// 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 glue file, which allows third party code to call into our profiler
|
||||
// without having to include most any functions from base.
|
||||
|
||||
#ifndef BASE_PROFILER_ALTERNATE_TIMER_H_
|
||||
#define BASE_PROFILER_ALTERNATE_TIMER_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
namespace tracked_objects {
|
||||
|
||||
enum TimeSourceType {
|
||||
TIME_SOURCE_TYPE_WALL_TIME,
|
||||
TIME_SOURCE_TYPE_TCMALLOC
|
||||
};
|
||||
|
||||
// Provide type for an alternate timer function.
|
||||
typedef unsigned int NowFunction();
|
||||
|
||||
// Environment variable name that is used to activate alternate timer profiling
|
||||
// (such as using TCMalloc allocations to provide a pseudo-timer) for tasks
|
||||
// instead of wall clock profiling.
|
||||
BASE_EXPORT extern const char kAlternateProfilerTime[];
|
||||
|
||||
// Set an alternate timer function to replace the OS time function when
|
||||
// profiling. Typically this is called by an allocator that is providing a
|
||||
// function that indicates how much memory has been allocated on any given
|
||||
// thread.
|
||||
BASE_EXPORT void SetAlternateTimeSource(NowFunction* now_function,
|
||||
TimeSourceType type);
|
||||
|
||||
// Gets the pointer to a function that was set via SetAlternateTimeSource().
|
||||
// Returns NULL if no set was done prior to calling GetAlternateTimeSource.
|
||||
NowFunction* GetAlternateTimeSource();
|
||||
|
||||
// Returns the type of the currently set time source.
|
||||
BASE_EXPORT TimeSourceType GetTimeSourceType();
|
||||
|
||||
} // namespace tracked_objects
|
||||
|
||||
#endif // BASE_PROFILER_ALTERNATE_TIMER_H_
|
|
@ -0,0 +1,71 @@
|
|||
// 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_PROFILER_TRACKED_TIME_H_
|
||||
#define BASE_PROFILER_TRACKED_TIME_H_
|
||||
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/time/time.h"
|
||||
|
||||
namespace tracked_objects {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TimeTicks maintains a wasteful 64 bits of data (we need less than 32), and on
|
||||
// windows, a 64 bit timer is expensive to even obtain. We use a simple
|
||||
// millisecond counter for most of our time values, as well as millisecond units
|
||||
// of duration between those values. This means we can only handle durations
|
||||
// up to 49 days (range), or 24 days (non-negative time durations).
|
||||
// We only define enough methods to service the needs of the tracking classes,
|
||||
// and our interfaces are modeled after what TimeTicks and TimeDelta use (so we
|
||||
// can swap them into place if we want to use the "real" classes).
|
||||
|
||||
class BASE_EXPORT Duration { // Similar to base::TimeDelta.
|
||||
public:
|
||||
Duration();
|
||||
|
||||
Duration& operator+=(const Duration& other);
|
||||
Duration operator+(const Duration& other) const;
|
||||
|
||||
bool operator==(const Duration& other) const;
|
||||
bool operator!=(const Duration& other) const;
|
||||
bool operator>(const Duration& other) const;
|
||||
|
||||
static Duration FromMilliseconds(int ms);
|
||||
|
||||
int32 InMilliseconds() const;
|
||||
|
||||
private:
|
||||
friend class TrackedTime;
|
||||
explicit Duration(int32 duration);
|
||||
|
||||
// Internal time is stored directly in milliseconds.
|
||||
int32 ms_;
|
||||
};
|
||||
|
||||
class BASE_EXPORT TrackedTime { // Similar to base::TimeTicks.
|
||||
public:
|
||||
TrackedTime();
|
||||
explicit TrackedTime(const base::TimeTicks& time);
|
||||
|
||||
static TrackedTime Now();
|
||||
Duration operator-(const TrackedTime& other) const;
|
||||
TrackedTime operator+(const Duration& other) const;
|
||||
bool is_null() const;
|
||||
|
||||
static TrackedTime FromMilliseconds(int32 ms) { return TrackedTime(ms); }
|
||||
|
||||
private:
|
||||
friend class Duration;
|
||||
explicit TrackedTime(int32 ms);
|
||||
|
||||
// Internal duration is stored directly in milliseconds.
|
||||
uint32 ms_;
|
||||
};
|
||||
|
||||
} // namespace tracked_objects
|
||||
|
||||
#endif // BASE_PROFILER_TRACKED_TIME_H_
|
|
@ -0,0 +1,58 @@
|
|||
// 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 <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Returns a random number in range [0, kuint64max]. Thread-safe.
|
||||
BASE_EXPORT uint64 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 RandGenerator(uint64 range);
|
||||
|
||||
// Returns a random double in range [0, 1). Thread-safe.
|
||||
BASE_EXPORT double RandDouble();
|
||||
|
||||
// Given input |bits|, convert with maximum precision to a double in
|
||||
// the range [0, 1). Thread-safe.
|
||||
BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64 bits);
|
||||
|
||||
// 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 with random data and returns it.
|
||||
// |length| should be nonzero.
|
||||
//
|
||||
// Note that this is a variation of |RandBytes| with a different return type.
|
||||
//
|
||||
// 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_
|
|
@ -0,0 +1,124 @@
|
|||
// 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_RUN_LOOP_H_
|
||||
#define BASE_RUN_LOOP_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
|
||||
namespace base {
|
||||
#if defined(OS_ANDROID)
|
||||
class MessagePumpForUI;
|
||||
#endif
|
||||
|
||||
#if defined(OS_IOS)
|
||||
class MessagePumpUIApplication;
|
||||
#endif
|
||||
|
||||
// Helper class to Run a nested MessageLoop. Please do not use nested
|
||||
// MessageLoops in production code! If you must, use this class instead of
|
||||
// calling MessageLoop::Run/Quit directly. RunLoop::Run can only be called once
|
||||
// per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run
|
||||
// a nested MessageLoop.
|
||||
class BASE_EXPORT RunLoop {
|
||||
public:
|
||||
RunLoop();
|
||||
#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
|
||||
!defined(USE_GTK_MESSAGE_PUMP)
|
||||
explicit RunLoop(MessageLoop::Dispatcher* dispatcher);
|
||||
#endif
|
||||
~RunLoop();
|
||||
|
||||
#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
|
||||
!defined(USE_GTK_MESSAGE_PUMP)
|
||||
void set_dispatcher(MessageLoop::Dispatcher* dispatcher) {
|
||||
dispatcher_ = dispatcher;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Run the current MessageLoop. This blocks until Quit is called. Before
|
||||
// calling Run, be sure to grab an AsWeakPtr or the QuitClosure in order to
|
||||
// stop the MessageLoop asynchronously. MessageLoop::Quit and QuitNow will
|
||||
// also trigger a return from Run, but those are deprecated.
|
||||
void Run();
|
||||
|
||||
// Run the current MessageLoop until it doesn't find any tasks or messages in
|
||||
// the queue (it goes idle). WARNING: This may never return! Only use this
|
||||
// when repeating tasks such as animated web pages have been shut down.
|
||||
void RunUntilIdle();
|
||||
|
||||
bool running() const { return running_; }
|
||||
|
||||
// Quit an earlier call to Run(). There can be other nested RunLoops servicing
|
||||
// the same task queue (MessageLoop); Quitting one RunLoop has no bearing on
|
||||
// the others. Quit can be called before, during or after Run. If called
|
||||
// before Run, Run will return immediately when called. Calling Quit after the
|
||||
// RunLoop has already finished running has no effect.
|
||||
//
|
||||
// WARNING: You must NEVER assume that a call to Quit will terminate the
|
||||
// targetted message loop. If a nested message loop continues running, the
|
||||
// target may NEVER terminate. It is very easy to livelock (run forever) in
|
||||
// such a case.
|
||||
void Quit();
|
||||
|
||||
// Convenience method to get a closure that safely calls Quit (has no effect
|
||||
// if the RunLoop instance is gone).
|
||||
//
|
||||
// Example:
|
||||
// RunLoop run_loop;
|
||||
// PostTask(run_loop.QuitClosure());
|
||||
// run_loop.Run();
|
||||
base::Closure QuitClosure();
|
||||
|
||||
private:
|
||||
friend class MessageLoop;
|
||||
#if defined(OS_ANDROID)
|
||||
// Android doesn't support the blocking MessageLoop::Run, so it calls
|
||||
// BeforeRun and AfterRun directly.
|
||||
friend class base::MessagePumpForUI;
|
||||
#endif
|
||||
|
||||
#if defined(OS_IOS)
|
||||
// iOS doesn't support the blocking MessageLoop::Run, so it calls
|
||||
// BeforeRun directly.
|
||||
friend class base::MessagePumpUIApplication;
|
||||
#endif
|
||||
|
||||
// Return false to abort the Run.
|
||||
bool BeforeRun();
|
||||
void AfterRun();
|
||||
|
||||
MessageLoop* loop_;
|
||||
|
||||
// WeakPtrFactory for QuitClosure safety.
|
||||
base::WeakPtrFactory<RunLoop> weak_factory_;
|
||||
|
||||
// Parent RunLoop or NULL if this is the top-most RunLoop.
|
||||
RunLoop* previous_run_loop_;
|
||||
|
||||
#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
|
||||
!defined(USE_GTK_MESSAGE_PUMP)
|
||||
MessageLoop::Dispatcher* dispatcher_;
|
||||
#endif
|
||||
|
||||
// Used to count how many nested Run() invocations are on the stack.
|
||||
int run_depth_;
|
||||
|
||||
bool run_called_;
|
||||
bool quit_called_;
|
||||
bool running_;
|
||||
|
||||
// Used to record that QuitWhenIdle() was called on the MessageLoop, meaning
|
||||
// that we should quit Run once it becomes idle.
|
||||
bool quit_when_idle_received_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RunLoop);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_RUN_LOOP_H_
|
|
@ -0,0 +1,34 @@
|
|||
// 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/basictypes.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_
|
|
@ -0,0 +1,68 @@
|
|||
// 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_
|
||||
|
||||
#include "base/memory/ref_counted.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
|
||||
|
||||
#if ENABLE_SEQUENCE_CHECKER
|
||||
#include "base/sequence_checker_impl.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
class SequencedTaskRunner;
|
||||
|
||||
// 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_.CalledOnValidSequence());
|
||||
// ... (do stuff) ...
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// SequenceChecker sequence_checker_;
|
||||
// }
|
||||
//
|
||||
// In Release mode, CalledOnValidSequence 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_
|
|
@ -0,0 +1,52 @@
|
|||
// 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/basictypes.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_
|
|
@ -0,0 +1,159 @@
|
|||
// 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_TASKRUNNER_H_
|
||||
#define BASE_SEQUENCED_TASKRUNNER_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:
|
||||
virtual ~SequencedTaskRunner() {}
|
||||
|
||||
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_TASKRUNNER_H_
|
|
@ -0,0 +1,112 @@
|
|||
// 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/basictypes.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_
|
|
@ -0,0 +1,37 @@
|
|||
// 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 MessageLoopProxy).
|
||||
// - 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:
|
||||
virtual ~SingleThreadTaskRunner() {}
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_SINGLE_THREAD_TASK_RUNNER_H_
|
|
@ -0,0 +1,223 @@
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// To treat a possibly-empty vector as an array, use these functions.
|
||||
// If you know the array will never be empty, you can use &*v.begin()
|
||||
// directly, but that is undefined behaviour if |v| is empty.
|
||||
template<typename T>
|
||||
inline T* vector_as_array(std::vector<T>* v) {
|
||||
return v->empty() ? NULL : &*v->begin();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T* vector_as_array(const std::vector<T>* v) {
|
||||
return v->empty() ? NULL : &*v->begin();
|
||||
}
|
||||
|
||||
// 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;
|
||||
for (typename T::iterator i(container->begin()); i != container->end(); ++i)
|
||||
delete i->second;
|
||||
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();
|
||||
}
|
||||
|
||||
namespace base {
|
||||
|
||||
// Returns true if the container is sorted.
|
||||
template <typename Container>
|
||||
bool STLIsSorted(const Container& cont) {
|
||||
return std::adjacent_find(cont.begin(), cont.end(),
|
||||
std::greater<typename Container::value_type>())
|
||||
== cont.end();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STL_UTIL_H_
|
|
@ -0,0 +1,17 @@
|
|||
// 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
|
|
@ -0,0 +1,46 @@
|
|||
// 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
|
||||
|
||||
#endif // BASE_STRINGS_NULLABLE_STRING16_H_
|
|
@ -0,0 +1,189 @@
|
|||
// 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 <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.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 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().
|
||||
COMPILE_ASSERT(sizeof(int_type) > sizeof(char_type), unexpected_type_width);
|
||||
|
||||
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, int_type 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
|
||||
|
||||
// TODO(brettw) update users of string16 to use the namespace and remove
|
||||
// this "using".
|
||||
using base::char16;
|
||||
using base::string16;
|
||||
|
||||
#endif // BASE_STRINGS_STRING16_H_
|
|
@ -0,0 +1,516 @@
|
|||
// 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/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, typename UINT, bool NEG>
|
||||
struct IntToStringT {
|
||||
// This is to avoid a compiler warning about unary minus on unsigned type.
|
||||
// For example, say you had the following code:
|
||||
// template <typename INT>
|
||||
// INT abs(INT value) { return value < 0 ? -value : value; }
|
||||
// Even though if INT is unsigned, it's impossible for value < 0, so the
|
||||
// unary minus will never be taken, the compiler will still generate a
|
||||
// warning. We do a little specialization dance...
|
||||
template <typename INT2, typename UINT2, bool NEG2>
|
||||
struct ToUnsignedT {};
|
||||
|
||||
template <typename INT2, typename UINT2>
|
||||
struct ToUnsignedT<INT2, UINT2, false> {
|
||||
static UINT2 ToUnsigned(INT2 value) {
|
||||
return static_cast<UINT2>(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename INT2, typename UINT2>
|
||||
struct ToUnsignedT<INT2, UINT2, true> {
|
||||
static UINT2 ToUnsigned(INT2 value) {
|
||||
return static_cast<UINT2>(value < 0 ? -value : value);
|
||||
}
|
||||
};
|
||||
|
||||
// This set of templates is very similar to the above templates, but
|
||||
// for testing whether an integer is negative.
|
||||
template <typename INT2, bool NEG2>
|
||||
struct TestNegT {};
|
||||
template <typename INT2>
|
||||
struct TestNegT<INT2, false> {
|
||||
static bool TestNeg(INT2 value) {
|
||||
// value is unsigned, and can never be negative.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
template <typename INT2>
|
||||
struct TestNegT<INT2, true> {
|
||||
static bool TestNeg(INT2 value) {
|
||||
return value < 0;
|
||||
}
|
||||
};
|
||||
|
||||
static STR IntToString(INT value) {
|
||||
// log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
|
||||
// So round up to allocate 3 output characters per byte, plus 1 for '-'.
|
||||
const int kOutputBufSize = 3 * sizeof(INT) + 1;
|
||||
|
||||
// Allocate the whole string right away, we will right back to front, and
|
||||
// then return the substr of what we ended up using.
|
||||
STR outbuf(kOutputBufSize, 0);
|
||||
|
||||
bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
|
||||
// Even though is_neg will never be true when INT is parameterized as
|
||||
// unsigned, even the presence of the unary operation causes a warning.
|
||||
UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
|
||||
|
||||
for (typename STR::iterator it = outbuf.end();;) {
|
||||
--it;
|
||||
DCHECK(it != outbuf.begin());
|
||||
*it = static_cast<typename STR::value_type>((res % 10) + '0');
|
||||
res /= 10;
|
||||
|
||||
// We're done..
|
||||
if (res == 0) {
|
||||
if (is_neg) {
|
||||
--it;
|
||||
DCHECK(it != outbuf.begin());
|
||||
*it = static_cast<typename STR::value_type>('-');
|
||||
}
|
||||
return STR(it, outbuf.end());
|
||||
}
|
||||
}
|
||||
NOTREACHED();
|
||||
return STR();
|
||||
}
|
||||
};
|
||||
|
||||
// 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* digit) {
|
||||
if (c >= '0' && c < '0' + BASE) {
|
||||
*digit = 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* 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* digit) {
|
||||
return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
|
||||
}
|
||||
|
||||
// There is an IsWhitespace for wchars defined in string_util.h, but it is
|
||||
// locale independent, whereas the functions we are replacing were
|
||||
// locale-dependent. TBD what is desired, but for the moment let's not introduce
|
||||
// a change in behaviour.
|
||||
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 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 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 increment, value_type* output) {
|
||||
*output += increment;
|
||||
}
|
||||
};
|
||||
|
||||
class Negative : public Base<Negative> {
|
||||
public:
|
||||
static bool CheckBounds(value_type* output, uint8 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 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 BaseHexIteratorRangeToInt64Traits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> {
|
||||
};
|
||||
|
||||
template<typename ITERATOR>
|
||||
class BaseHexIteratorRangeToUInt64Traits
|
||||
: public BaseIteratorRangeToNumberTraits<ITERATOR, uint64, 16> {
|
||||
};
|
||||
|
||||
typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
|
||||
HexIteratorRangeToIntTraits;
|
||||
|
||||
typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
|
||||
HexIteratorRangeToInt64Traits;
|
||||
|
||||
typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator>
|
||||
HexIteratorRangeToUInt64Traits;
|
||||
|
||||
template<typename STR>
|
||||
bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
|
||||
DCHECK_EQ(output->size(), 0u);
|
||||
size_t count = input.size();
|
||||
if (count == 0 || (count % 2) != 0)
|
||||
return false;
|
||||
for (uintptr_t i = 0; i < count / 2; ++i) {
|
||||
uint8 msb = 0; // most significant 4 bits
|
||||
uint8 lsb = 0; // least significant 4 bits
|
||||
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, unsigned int, true>::
|
||||
IntToString(value);
|
||||
}
|
||||
|
||||
string16 IntToString16(int value) {
|
||||
return IntToStringT<string16, int, unsigned int, true>::
|
||||
IntToString(value);
|
||||
}
|
||||
|
||||
std::string UintToString(unsigned int value) {
|
||||
return IntToStringT<std::string, unsigned int, unsigned int, false>::
|
||||
IntToString(value);
|
||||
}
|
||||
|
||||
string16 UintToString16(unsigned int value) {
|
||||
return IntToStringT<string16, unsigned int, unsigned int, false>::
|
||||
IntToString(value);
|
||||
}
|
||||
|
||||
std::string Int64ToString(int64 value) {
|
||||
return IntToStringT<std::string, int64, uint64, true>::
|
||||
IntToString(value);
|
||||
}
|
||||
|
||||
string16 Int64ToString16(int64 value) {
|
||||
return IntToStringT<string16, int64, uint64, true>::IntToString(value);
|
||||
}
|
||||
|
||||
std::string Uint64ToString(uint64 value) {
|
||||
return IntToStringT<std::string, uint64, uint64, false>::
|
||||
IntToString(value);
|
||||
}
|
||||
|
||||
string16 Uint64ToString16(uint64 value) {
|
||||
return IntToStringT<string16, uint64, uint64, false>::
|
||||
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* output) {
|
||||
return StringToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToInt64(const StringPiece16& input, int64* output) {
|
||||
return String16ToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToUint64(const StringPiece& input, uint64* output) {
|
||||
return StringToIntImpl(input, output);
|
||||
}
|
||||
|
||||
bool StringToUint64(const StringPiece16& input, uint64* 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 HexStringToInt64(const StringPiece& input, int64* output) {
|
||||
return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
bool HexStringToUInt64(const StringPiece& input, uint64* output) {
|
||||
return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke(
|
||||
input.begin(), input.end(), output);
|
||||
}
|
||||
|
||||
bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
|
||||
return HexStringToBytesT(input, output);
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -0,0 +1,122 @@
|
|||
// 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.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 value);
|
||||
BASE_EXPORT string16 Int64ToString16(int64 value);
|
||||
|
||||
BASE_EXPORT std::string Uint64ToString(uint64 value);
|
||||
BASE_EXPORT string16 Uint64ToString16(uint64 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.
|
||||
BASE_EXPORT bool StringToInt(const StringPiece& input, int* output);
|
||||
BASE_EXPORT bool StringToInt(const StringPiece16& input, int* output);
|
||||
|
||||
BASE_EXPORT bool StringToUint(const StringPiece& input, unsigned* output);
|
||||
BASE_EXPORT bool StringToUint(const StringPiece16& input, unsigned* output);
|
||||
|
||||
BASE_EXPORT bool StringToInt64(const StringPiece& input, int64* output);
|
||||
BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64* output);
|
||||
|
||||
BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64* output);
|
||||
BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64* output);
|
||||
|
||||
BASE_EXPORT bool StringToSizeT(const StringPiece& input, size_t* output);
|
||||
BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output);
|
||||
|
||||
// For floating-point conversions, only conversions of input strings in decimal
|
||||
// form are defined to work. Behavior with strings representing floating-point
|
||||
// numbers in hexadecimal, and strings representing non-fininte values (such as
|
||||
// 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.
|
||||
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.
|
||||
// -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF.
|
||||
BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64* output);
|
||||
|
||||
// Best effort conversion, see StringToInt above for restrictions.
|
||||
// Will only successful parse hex values that will fit into |output|, i.e.
|
||||
// 0x0000000000000000 < |input| < 0xFFFFFFFFFFFFFFFF.
|
||||
// The string is not required to start with 0x.
|
||||
BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64* output);
|
||||
|
||||
// Similar to the previous functions, except that output is a vector of bytes.
|
||||
// |*output| will contain as many bytes as were successfully parsed prior to the
|
||||
// error. There is no overflow, but input.size() must be evenly divisible by 2.
|
||||
// Leading 0x or +/- are not allowed.
|
||||
BASE_EXPORT bool HexStringToBytes(const std::string& input,
|
||||
std::vector<uint8>* output);
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
|
|
@ -0,0 +1,255 @@
|
|||
// 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 <algorithm>
|
||||
#include <ostream>
|
||||
|
||||
namespace base {
|
||||
|
||||
// MSVC doesn't like complex extern templates and DLLs.
|
||||
#if !defined(COMPILER_MSVC)
|
||||
namespace internal {
|
||||
template class StringPieceDetail<std::string>;
|
||||
template class StringPieceDetail<string16>;
|
||||
} // namespace internal
|
||||
|
||||
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 {
|
||||
void CopyToString(const StringPiece& self, std::string* target) {
|
||||
target->assign(!self.empty() ? self.data() : "", self.size());
|
||||
}
|
||||
|
||||
void AppendToString(const StringPiece& self, std::string* target) {
|
||||
if (!self.empty())
|
||||
target->append(self.data(), self.size());
|
||||
}
|
||||
|
||||
StringPiece::size_type copy(const StringPiece& self,
|
||||
char* buf,
|
||||
StringPiece::size_type n,
|
||||
StringPiece::size_type pos) {
|
||||
StringPiece::size_type ret = std::min(self.size() - pos, n);
|
||||
memcpy(buf, self.data() + pos, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
StringPiece::size_type find(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPiece::size_type pos) {
|
||||
if (pos > self.size())
|
||||
return StringPiece::npos;
|
||||
|
||||
StringPiece::const_iterator result =
|
||||
std::search(self.begin() + pos, self.end(), s.begin(), s.end());
|
||||
const StringPiece::size_type xpos =
|
||||
static_cast<size_t>(result - self.begin());
|
||||
return xpos + s.size() <= self.size() ? xpos : StringPiece::npos;
|
||||
}
|
||||
|
||||
StringPiece::size_type find(const StringPiece& self,
|
||||
char c,
|
||||
StringPiece::size_type pos) {
|
||||
if (pos >= self.size())
|
||||
return StringPiece::npos;
|
||||
|
||||
StringPiece::const_iterator result =
|
||||
std::find(self.begin() + pos, self.end(), c);
|
||||
return result != self.end() ?
|
||||
static_cast<size_t>(result - self.begin()) : StringPiece::npos;
|
||||
}
|
||||
|
||||
StringPiece::size_type rfind(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPiece::size_type pos) {
|
||||
if (self.size() < s.size())
|
||||
return StringPiece::npos;
|
||||
|
||||
if (s.empty())
|
||||
return std::min(self.size(), pos);
|
||||
|
||||
StringPiece::const_iterator last =
|
||||
self.begin() + std::min(self.size() - s.size(), pos) + s.size();
|
||||
StringPiece::const_iterator result =
|
||||
std::find_end(self.begin(), last, s.begin(), s.end());
|
||||
return result != last ?
|
||||
static_cast<size_t>(result - self.begin()) : StringPiece::npos;
|
||||
}
|
||||
|
||||
StringPiece::size_type rfind(const StringPiece& self,
|
||||
char c,
|
||||
StringPiece::size_type pos) {
|
||||
if (self.size() == 0)
|
||||
return StringPiece::npos;
|
||||
|
||||
for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
|
||||
if (self.data()[i] == c)
|
||||
return i;
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
return StringPiece::npos;
|
||||
}
|
||||
|
||||
// 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]
|
||||
static inline void BuildLookupTable(const StringPiece& characters_wanted,
|
||||
bool* table) {
|
||||
const StringPiece::size_type length = characters_wanted.length();
|
||||
const char* const data = characters_wanted.data();
|
||||
for (StringPiece::size_type i = 0; i < length; ++i) {
|
||||
table[static_cast<unsigned char>(data[i])] = true;
|
||||
}
|
||||
}
|
||||
|
||||
StringPiece::size_type find_first_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPiece::size_type 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 (StringPiece::size_type i = pos; i < self.size(); ++i) {
|
||||
if (lookup[static_cast<unsigned char>(self.data()[i])]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return StringPiece::npos;
|
||||
}
|
||||
|
||||
StringPiece::size_type find_first_not_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPiece::size_type 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 (StringPiece::size_type i = pos; i < self.size(); ++i) {
|
||||
if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return StringPiece::npos;
|
||||
}
|
||||
|
||||
StringPiece::size_type find_first_not_of(const StringPiece& self,
|
||||
char c,
|
||||
StringPiece::size_type pos) {
|
||||
if (self.size() == 0)
|
||||
return StringPiece::npos;
|
||||
|
||||
for (; pos < self.size(); ++pos) {
|
||||
if (self.data()[pos] != c) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
return StringPiece::npos;
|
||||
}
|
||||
|
||||
StringPiece::size_type find_last_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPiece::size_type 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 (StringPiece::size_type 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;
|
||||
}
|
||||
|
||||
StringPiece::size_type find_last_not_of(const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPiece::size_type pos) {
|
||||
if (self.size() == 0)
|
||||
return StringPiece::npos;
|
||||
|
||||
StringPiece::size_type 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;
|
||||
}
|
||||
|
||||
StringPiece::size_type find_last_not_of(const StringPiece& self,
|
||||
char c,
|
||||
StringPiece::size_type pos) {
|
||||
if (self.size() == 0)
|
||||
return StringPiece::npos;
|
||||
|
||||
for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
|
||||
if (self.data()[i] != c)
|
||||
return i;
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
return StringPiece::npos;
|
||||
}
|
||||
|
||||
StringPiece substr(const StringPiece& self,
|
||||
StringPiece::size_type pos,
|
||||
StringPiece::size_type n) {
|
||||
if (pos > self.size()) pos = self.size();
|
||||
if (n > self.size() - pos) n = self.size() - pos;
|
||||
return StringPiece(self.data() + pos, n);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace base
|
|
@ -0,0 +1,451 @@
|
|||
// 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.
|
||||
//
|
||||
// Functions or methods may use const StringPiece& parameters to accept either
|
||||
// a "const char*" or a "string" value that will be implicitly converted to
|
||||
// a StringPiece. The implicit conversion means that it is often appropriate
|
||||
// to include this .h file in other files rather than forward-declaring
|
||||
// StringPiece as would be appropriate for most other Google classes.
|
||||
//
|
||||
// Systematic usage of StringPiece is encouraged as it will reduce unnecessary
|
||||
// conversions from "const char*" to "string" and back again.
|
||||
//
|
||||
// StringPiece16 is similar to StringPiece but for base::string16 instead of
|
||||
// std::string. We do not define as large of a subset of the STL functions
|
||||
// from basic_string as in StringPiece, but this can be changed if these
|
||||
// functions (find, find_first_of, etc.) are found to be useful in this context.
|
||||
//
|
||||
|
||||
#ifndef BASE_STRINGS_STRING_PIECE_H_
|
||||
#define BASE_STRINGS_STRING_PIECE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "base/strings/string16.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename STRING_TYPE> class BasicStringPiece;
|
||||
typedef BasicStringPiece<std::string> StringPiece;
|
||||
typedef BasicStringPiece<string16> StringPiece16;
|
||||
|
||||
namespace internal {
|
||||
|
||||
// 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.
|
||||
template <typename STRING_TYPE> class StringPieceDetail {
|
||||
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).
|
||||
StringPieceDetail() : ptr_(NULL), length_(0) {}
|
||||
StringPieceDetail(const value_type* str)
|
||||
: ptr_(str),
|
||||
length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {}
|
||||
StringPieceDetail(const STRING_TYPE& str)
|
||||
: ptr_(str.data()), length_(str.size()) {}
|
||||
StringPieceDetail(const value_type* offset, size_type len)
|
||||
: ptr_(offset), length_(len) {}
|
||||
StringPieceDetail(const typename STRING_TYPE::const_iterator& begin,
|
||||
const typename STRING_TYPE::const_iterator& end)
|
||||
: ptr_((end > begin) ? &(*begin) : NULL),
|
||||
length_((end > begin) ? (size_type)(end - begin) : 0) {}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
protected:
|
||||
const value_type* ptr_;
|
||||
size_type length_;
|
||||
};
|
||||
|
||||
template <typename STRING_TYPE>
|
||||
const typename StringPieceDetail<STRING_TYPE>::size_type
|
||||
StringPieceDetail<STRING_TYPE>::npos =
|
||||
typename StringPieceDetail<STRING_TYPE>::size_type(-1);
|
||||
|
||||
// MSVC doesn't like complex extern templates and DLLs.
|
||||
#if !defined(COMPILER_MSVC)
|
||||
extern template class BASE_EXPORT StringPieceDetail<std::string>;
|
||||
extern template class BASE_EXPORT StringPieceDetail<string16>;
|
||||
#endif
|
||||
|
||||
BASE_EXPORT void CopyToString(const StringPiece& self, std::string* target);
|
||||
BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type copy(
|
||||
const StringPiece& self,
|
||||
char* buf,
|
||||
StringPieceDetail<std::string>::size_type n,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type find(
|
||||
const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type find(
|
||||
const StringPiece& self,
|
||||
char c,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type rfind(
|
||||
const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type rfind(
|
||||
const StringPiece& self,
|
||||
char c,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_of(
|
||||
const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_not_of(
|
||||
const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type find_first_not_of(
|
||||
const StringPiece& self,
|
||||
char c,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_of(
|
||||
const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_of(
|
||||
const StringPiece& self,
|
||||
char c,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_not_of(
|
||||
const StringPiece& self,
|
||||
const StringPiece& s,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPieceDetail<std::string>::size_type find_last_not_of(
|
||||
const StringPiece& self,
|
||||
char c,
|
||||
StringPieceDetail<std::string>::size_type pos);
|
||||
BASE_EXPORT StringPiece substr(const StringPiece& self,
|
||||
StringPieceDetail<std::string>::size_type pos,
|
||||
StringPieceDetail<std::string>::size_type n);
|
||||
} // namespace internal
|
||||
|
||||
// Defines the template type that is instantiated as either StringPiece or
|
||||
// StringPiece16.
|
||||
template <typename STRING_TYPE> class BasicStringPiece :
|
||||
public internal::StringPieceDetail<STRING_TYPE> {
|
||||
public:
|
||||
typedef typename internal::StringPieceDetail<STRING_TYPE>::value_type
|
||||
value_type;
|
||||
typedef typename internal::StringPieceDetail<STRING_TYPE>::size_type
|
||||
size_type;
|
||||
|
||||
BasicStringPiece() {}
|
||||
BasicStringPiece(const value_type*str)
|
||||
: internal::StringPieceDetail<STRING_TYPE>(str) {}
|
||||
BasicStringPiece(const STRING_TYPE& str)
|
||||
: internal::StringPieceDetail<STRING_TYPE>(str) {}
|
||||
BasicStringPiece(const value_type* offset, size_type len)
|
||||
: internal::StringPieceDetail<STRING_TYPE>(offset, len) {}
|
||||
BasicStringPiece(const typename STRING_TYPE::const_iterator& begin,
|
||||
const typename STRING_TYPE::const_iterator& end)
|
||||
: internal::StringPieceDetail<STRING_TYPE>(begin, end) {}
|
||||
};
|
||||
|
||||
// Specializes BasicStringPiece for std::string to add a few operations that
|
||||
// are not needed for string16.
|
||||
template <> class BasicStringPiece<std::string> :
|
||||
public internal::StringPieceDetail<std::string> {
|
||||
public:
|
||||
BasicStringPiece() {}
|
||||
BasicStringPiece(const char* str)
|
||||
: internal::StringPieceDetail<std::string>(str) {}
|
||||
BasicStringPiece(const std::string& str)
|
||||
: internal::StringPieceDetail<std::string>(str) {}
|
||||
BasicStringPiece(const char* offset, size_type len)
|
||||
: internal::StringPieceDetail<std::string>(offset, len) {}
|
||||
BasicStringPiece(const std::string::const_iterator& begin,
|
||||
const std::string::const_iterator& end)
|
||||
: internal::StringPieceDetail<std::string>(begin, end) {}
|
||||
|
||||
// Prevent the following overload of set() from hiding the definitions in the
|
||||
// base class.
|
||||
using internal::StringPieceDetail<std::string>::set;
|
||||
|
||||
void set(const void* data, size_type len) {
|
||||
ptr_ = reinterpret_cast<const value_type*>(data);
|
||||
length_ = len;
|
||||
}
|
||||
|
||||
void CopyToString(std::string* target) const {
|
||||
internal::CopyToString(*this, target);
|
||||
}
|
||||
|
||||
void AppendToString(std::string* target) const {
|
||||
internal::AppendToString(*this, target);
|
||||
}
|
||||
|
||||
// Does "this" start with "x"
|
||||
bool starts_with(const BasicStringPiece& x) const {
|
||||
return ((length_ >= x.length_) &&
|
||||
(wordmemcmp(ptr_, x.ptr_, x.length_) == 0));
|
||||
}
|
||||
|
||||
// Does "this" end with "x"
|
||||
bool ends_with(const BasicStringPiece& x) const {
|
||||
return ((length_ >= x.length_) &&
|
||||
(wordmemcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0));
|
||||
}
|
||||
|
||||
size_type copy(char* buf, size_type n, size_type pos = 0) const {
|
||||
return internal::copy(*this, buf, n, pos);
|
||||
}
|
||||
|
||||
size_type find(const BasicStringPiece& s, size_type pos = 0) const {
|
||||
return internal::find(*this, s, pos);
|
||||
}
|
||||
|
||||
size_type find(char c, size_type pos = 0) const {
|
||||
return internal::find(*this, c, pos);
|
||||
}
|
||||
|
||||
size_type rfind(const BasicStringPiece& s, size_type pos = npos) const {
|
||||
return internal::rfind(*this, s, pos);
|
||||
}
|
||||
|
||||
size_type rfind(char c, size_type pos = npos) const {
|
||||
return internal::rfind(*this, c, pos);
|
||||
}
|
||||
|
||||
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(char c, size_type pos = 0) const {
|
||||
return find(c, pos);
|
||||
}
|
||||
|
||||
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(char c, size_type pos = 0) const {
|
||||
return internal::find_first_not_of(*this, c, pos);
|
||||
}
|
||||
|
||||
size_type find_last_of(const BasicStringPiece& s,
|
||||
size_type pos = npos) const {
|
||||
return internal::find_last_of(*this, s, pos);
|
||||
}
|
||||
|
||||
size_type find_last_of(char c, size_type pos = npos) const {
|
||||
return rfind(c, pos);
|
||||
}
|
||||
|
||||
size_type find_last_not_of(const BasicStringPiece& s,
|
||||
size_type pos = npos) const {
|
||||
return internal::find_last_not_of(*this, s, pos);
|
||||
}
|
||||
|
||||
size_type find_last_not_of(char c, size_type pos = npos) const {
|
||||
return internal::find_last_not_of(*this, c, pos);
|
||||
}
|
||||
|
||||
BasicStringPiece substr(size_type pos, size_type n = npos) const {
|
||||
return internal::substr(*this, pos, n);
|
||||
}
|
||||
};
|
||||
|
||||
// MSVC doesn't like complex extern templates and DLLs.
|
||||
#if !defined(COMPILER_MSVC)
|
||||
// We can't explicitly declare the std::string instantiation here because it was
|
||||
// already instantiated when specialized, above. Not only is it a no-op, but
|
||||
// currently it also crashes Clang (see http://crbug.com/107412).
|
||||
extern template class BASE_EXPORT BasicStringPiece<string16>;
|
||||
#endif
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// 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 {
|
||||
#if defined(COMPILER_GCC)
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
#elif defined(COMPILER_MSVC)
|
||||
|
||||
inline size_t hash_value(const base::StringPiece& sp) {
|
||||
HASH_STRING_PIECE(base::StringPiece, sp);
|
||||
}
|
||||
inline size_t hash_value(const base::StringPiece16& sp16) {
|
||||
HASH_STRING_PIECE(base::StringPiece16, sp16);
|
||||
}
|
||||
|
||||
#endif // COMPILER
|
||||
|
||||
} // namespace BASE_HASH_NAMESPACE
|
||||
|
||||
#endif // BASE_STRINGS_STRING_PIECE_H_
|
|
@ -0,0 +1,575 @@
|
|||
// 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/string_piece.h" // For implicit conversions.
|
||||
|
||||
// Safe standard library wrappers for all platforms.
|
||||
|
||||
namespace base {
|
||||
|
||||
// C standard-library functions like "strncasecmp" and "snprintf" that aren't
|
||||
// cross-platform are provided as "base::strncasecmp", and their prototypes
|
||||
// are listed below. These functions are then implemented as inline calls
|
||||
// to the platform-specific equivalents in the platform-specific headers.
|
||||
|
||||
// Compares the two strings s1 and s2 without regard to case using
|
||||
// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
|
||||
// s2 > s1 according to a lexicographic comparison.
|
||||
int strcasecmp(const char* s1, const char* s2);
|
||||
|
||||
// Compares up to count characters of s1 and s2 without regard to case using
|
||||
// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
|
||||
// s2 > s1 according to a lexicographic comparison.
|
||||
int strncasecmp(const char* s1, const char* s2, size_t count);
|
||||
|
||||
// Same as strncmp but for char16 strings.
|
||||
int strncmp16(const char16* s1, const char16* s2, size_t count);
|
||||
|
||||
// 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);
|
||||
|
||||
// vswprintf always null-terminates, but when truncation occurs, it will either
|
||||
// return -1 or the number of characters that would be in an untruncated
|
||||
// formatted string. The actual return value depends on the underlying
|
||||
// C library's vswprintf implementation.
|
||||
int vswprintf(wchar_t* buffer, size_t size,
|
||||
const wchar_t* format, va_list arguments)
|
||||
WPRINTF_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, const char* format, ...)
|
||||
PRINTF_FORMAT(3, 4);
|
||||
inline int snprintf(char* buffer, size_t size, const char* format, ...) {
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = vsnprintf(buffer, size, format, arguments);
|
||||
va_end(arguments);
|
||||
return result;
|
||||
}
|
||||
|
||||
// We separate the declaration from the implementation of this inline
|
||||
// function just so the WPRINTF_FORMAT works.
|
||||
inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...)
|
||||
WPRINTF_FORMAT(3, 4);
|
||||
inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...) {
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int result = vswprintf(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.
|
||||
template <class Char> inline Char ToLowerASCII(Char c) {
|
||||
return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
|
||||
}
|
||||
|
||||
// ASCII-specific toupper. The standard library's toupper is locale sensitive,
|
||||
// so we don't want to use it here.
|
||||
template <class Char> inline Char ToUpperASCII(Char c) {
|
||||
return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
|
||||
}
|
||||
|
||||
// Function objects to aid in comparing/searching strings.
|
||||
|
||||
template<typename Char> struct CaseInsensitiveCompare {
|
||||
public:
|
||||
bool operator()(Char x, Char y) const {
|
||||
// TODO(darin): Do we really want to do locale sensitive comparisons here?
|
||||
// See http://crbug.com/24917
|
||||
return tolower(x) == tolower(y);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Char> struct CaseInsensitiveCompareASCII {
|
||||
public:
|
||||
bool operator()(Char x, Char y) const {
|
||||
return ToLowerASCII(x) == ToLowerASCII(y);
|
||||
}
|
||||
};
|
||||
|
||||
} // 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
|
||||
|
||||
// These threadsafe functions return references to globally unique empty
|
||||
// strings.
|
||||
//
|
||||
// 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 std::wstring& EmptyWString();
|
||||
BASE_EXPORT const string16& EmptyString16();
|
||||
|
||||
BASE_EXPORT extern const wchar_t kWhitespaceWide[];
|
||||
BASE_EXPORT extern const char16 kWhitespaceUTF16[];
|
||||
BASE_EXPORT extern const char kWhitespaceASCII[];
|
||||
|
||||
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 char16 remove_chars[],
|
||||
string16* output);
|
||||
BASE_EXPORT bool RemoveChars(const std::string& input,
|
||||
const char 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 char16 replace_chars[],
|
||||
const string16& replace_with,
|
||||
string16* output);
|
||||
BASE_EXPORT bool ReplaceChars(const std::string& input,
|
||||
const char replace_chars[],
|
||||
const std::string& replace_with,
|
||||
std::string* output);
|
||||
|
||||
// Removes characters in |trim_chars| from the beginning and end of |input|.
|
||||
// |trim_chars| must be null-terminated.
|
||||
// NOTE: Safe to use the same variable for both |input| and |output|.
|
||||
BASE_EXPORT bool TrimString(const std::wstring& input,
|
||||
const wchar_t trim_chars[],
|
||||
std::wstring* output);
|
||||
BASE_EXPORT bool TrimString(const string16& input,
|
||||
const char16 trim_chars[],
|
||||
string16* output);
|
||||
BASE_EXPORT bool TrimString(const std::string& input,
|
||||
const char trim_chars[],
|
||||
std::string* output);
|
||||
|
||||
// Truncates a string to the nearest UTF-8 character that will leave
|
||||
// the string less than or equal to the specified byte size.
|
||||
BASE_EXPORT void TruncateUTF8ToByteSize(const std::string& input,
|
||||
const size_t byte_size,
|
||||
std::string* output);
|
||||
|
||||
// Trims any whitespace from either end of the input string. Returns where
|
||||
// whitespace was found.
|
||||
// The non-wide version has two functions:
|
||||
// * TrimWhitespaceASCII()
|
||||
// This function is for ASCII strings and only looks for ASCII whitespace;
|
||||
// Please choose the best one according to your usage.
|
||||
// NOTE: Safe to use the same variable for both input and output.
|
||||
enum TrimPositions {
|
||||
TRIM_NONE = 0,
|
||||
TRIM_LEADING = 1 << 0,
|
||||
TRIM_TRAILING = 1 << 1,
|
||||
TRIM_ALL = TRIM_LEADING | TRIM_TRAILING,
|
||||
};
|
||||
BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
|
||||
TrimPositions positions,
|
||||
string16* output);
|
||||
BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
|
||||
TrimPositions positions,
|
||||
std::string* output);
|
||||
|
||||
// Deprecated. This function is only for backward compatibility and calls
|
||||
// TrimWhitespaceASCII().
|
||||
BASE_EXPORT TrimPositions TrimWhitespace(const std::string& input,
|
||||
TrimPositions positions,
|
||||
std::string* output);
|
||||
|
||||
// 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 std::wstring CollapseWhitespace(
|
||||
const std::wstring& text,
|
||||
bool trim_sequences_with_line_breaks);
|
||||
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 the passed string is empty or contains only white-space
|
||||
// characters.
|
||||
BASE_EXPORT bool ContainsOnlyWhitespaceASCII(const std::string& str);
|
||||
BASE_EXPORT bool ContainsOnlyWhitespace(const string16& str);
|
||||
|
||||
// Returns true if |input| is empty or contains only characters found in
|
||||
// |characters|.
|
||||
BASE_EXPORT bool ContainsOnlyChars(const std::wstring& input,
|
||||
const std::wstring& characters);
|
||||
BASE_EXPORT bool ContainsOnlyChars(const string16& input,
|
||||
const string16& characters);
|
||||
BASE_EXPORT bool ContainsOnlyChars(const std::string& input,
|
||||
const std::string& characters);
|
||||
|
||||
// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
|
||||
// beforehand.
|
||||
BASE_EXPORT std::string WideToASCII(const std::wstring& wide);
|
||||
BASE_EXPORT std::string UTF16ToASCII(const string16& utf16);
|
||||
|
||||
// Converts the given wide string to the corresponding Latin1. This will fail
|
||||
// (return false) if any characters are more than 255.
|
||||
BASE_EXPORT bool WideToLatin1(const std::wstring& wide, std::string* latin1);
|
||||
|
||||
// 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.
|
||||
BASE_EXPORT bool IsStringUTF8(const std::string& str);
|
||||
BASE_EXPORT bool IsStringASCII(const std::wstring& str);
|
||||
BASE_EXPORT bool IsStringASCII(const string16& str);
|
||||
|
||||
// Converts the elements of the given string. This version uses a pointer to
|
||||
// clearly differentiate it from the non-pointer variant.
|
||||
template <class str> inline void StringToLowerASCII(str* s) {
|
||||
for (typename str::iterator i = s->begin(); i != s->end(); ++i)
|
||||
*i = base::ToLowerASCII(*i);
|
||||
}
|
||||
|
||||
template <class str> inline str StringToLowerASCII(const str& s) {
|
||||
// for std::string and std::wstring
|
||||
str output(s);
|
||||
StringToLowerASCII(&output);
|
||||
return output;
|
||||
}
|
||||
|
||||
// Converts the elements of the given string. This version uses a pointer to
|
||||
// clearly differentiate it from the non-pointer variant.
|
||||
template <class str> inline void StringToUpperASCII(str* s) {
|
||||
for (typename str::iterator i = s->begin(); i != s->end(); ++i)
|
||||
*i = base::ToUpperASCII(*i);
|
||||
}
|
||||
|
||||
template <class str> inline str StringToUpperASCII(const str& s) {
|
||||
// for std::string and std::wstring
|
||||
str output(s);
|
||||
StringToUpperASCII(&output);
|
||||
return output;
|
||||
}
|
||||
|
||||
// Compare the lower-case form of the given string against the given ASCII
|
||||
// string. This is useful for doing checking if an input string matches some
|
||||
// token, and it is optimized to avoid intermediate string copies. This API is
|
||||
// borrowed from the equivalent APIs in Mozilla.
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const std::string& a, const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const std::wstring& a, const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const string16& a, const char* b);
|
||||
|
||||
// Same thing, but with string iterators instead.
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
|
||||
std::string::const_iterator a_end,
|
||||
const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(std::wstring::const_iterator a_begin,
|
||||
std::wstring::const_iterator a_end,
|
||||
const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
|
||||
string16::const_iterator a_end,
|
||||
const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
|
||||
const char* a_end,
|
||||
const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const wchar_t* a_begin,
|
||||
const wchar_t* a_end,
|
||||
const char* b);
|
||||
BASE_EXPORT bool LowerCaseEqualsASCII(const char16* a_begin,
|
||||
const char16* a_end,
|
||||
const char* b);
|
||||
|
||||
// Performs a case-sensitive string compare. The behavior is undefined if both
|
||||
// strings are not ASCII.
|
||||
BASE_EXPORT bool EqualsASCII(const string16& a, const base::StringPiece& b);
|
||||
|
||||
// Returns true if str starts with search, or false otherwise.
|
||||
BASE_EXPORT bool StartsWithASCII(const std::string& str,
|
||||
const std::string& search,
|
||||
bool case_sensitive);
|
||||
BASE_EXPORT bool StartsWith(const std::wstring& str,
|
||||
const std::wstring& search,
|
||||
bool case_sensitive);
|
||||
BASE_EXPORT bool StartsWith(const string16& str,
|
||||
const string16& search,
|
||||
bool case_sensitive);
|
||||
|
||||
// Returns true if str ends with search, or false otherwise.
|
||||
BASE_EXPORT bool EndsWith(const std::string& str,
|
||||
const std::string& search,
|
||||
bool case_sensitive);
|
||||
BASE_EXPORT bool EndsWith(const std::wstring& str,
|
||||
const std::wstring& search,
|
||||
bool case_sensitive);
|
||||
BASE_EXPORT bool EndsWith(const string16& str,
|
||||
const string16& search,
|
||||
bool case_sensitive);
|
||||
|
||||
|
||||
// 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');
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline Char HexDigitToInt(Char c) {
|
||||
DCHECK(IsHexDigit(c));
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns true if it's a whitespace character.
|
||||
inline bool IsWhitespace(wchar_t c) {
|
||||
return wcschr(kWhitespaceWide, c) != NULL;
|
||||
}
|
||||
|
||||
// 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 bytes);
|
||||
|
||||
// Starting at |start_offset| (usually 0), replace the first instance of
|
||||
// |find_this| with |replace_with|.
|
||||
BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
|
||||
string16* str,
|
||||
string16::size_type start_offset,
|
||||
const string16& find_this,
|
||||
const string16& replace_with);
|
||||
BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
|
||||
std::string* str,
|
||||
std::string::size_type start_offset,
|
||||
const std::string& find_this,
|
||||
const std::string& 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,
|
||||
string16::size_type start_offset,
|
||||
const string16& find_this,
|
||||
const string16& replace_with);
|
||||
BASE_EXPORT void ReplaceSubstringsAfterOffset(
|
||||
std::string* str,
|
||||
std::string::size_type start_offset,
|
||||
const std::string& find_this,
|
||||
const std::string& 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).
|
||||
template <class string_type>
|
||||
inline typename string_type::value_type* WriteInto(string_type* str,
|
||||
size_t length_with_null) {
|
||||
DCHECK_GT(length_with_null, 1u);
|
||||
str->reserve(length_with_null);
|
||||
str->resize(length_with_null - 1);
|
||||
return &((*str)[0]);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Splits a string into its fields delimited by any of the characters in
|
||||
// |delimiters|. Each field is added to the |tokens| vector. Returns the
|
||||
// number of tokens found.
|
||||
BASE_EXPORT size_t Tokenize(const std::wstring& str,
|
||||
const std::wstring& delimiters,
|
||||
std::vector<std::wstring>* tokens);
|
||||
BASE_EXPORT size_t Tokenize(const string16& str,
|
||||
const string16& delimiters,
|
||||
std::vector<string16>* tokens);
|
||||
BASE_EXPORT size_t Tokenize(const std::string& str,
|
||||
const std::string& delimiters,
|
||||
std::vector<std::string>* tokens);
|
||||
BASE_EXPORT size_t Tokenize(const base::StringPiece& str,
|
||||
const base::StringPiece& delimiters,
|
||||
std::vector<base::StringPiece>* tokens);
|
||||
|
||||
// Does the opposite of SplitString().
|
||||
BASE_EXPORT string16 JoinString(const std::vector<string16>& parts, char16 s);
|
||||
BASE_EXPORT std::string JoinString(
|
||||
const std::vector<std::string>& parts, char s);
|
||||
|
||||
// Join |parts| using |separator|.
|
||||
BASE_EXPORT std::string JoinString(
|
||||
const std::vector<std::string>& parts,
|
||||
const std::string& separator);
|
||||
BASE_EXPORT string16 JoinString(
|
||||
const std::vector<string16>& parts,
|
||||
const string16& 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 base::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);
|
||||
|
||||
// Returns true if the string passed in matches the pattern. The pattern
|
||||
// string can contain wildcards like * and ?
|
||||
// The backslash character (\) is an escape character for * and ?
|
||||
// We limit the patterns to having a max of 16 * or ? characters.
|
||||
// ? matches 0 or 1 character, while * matches 0 or more characters.
|
||||
BASE_EXPORT bool MatchPattern(const base::StringPiece& string,
|
||||
const base::StringPiece& pattern);
|
||||
BASE_EXPORT bool MatchPattern(const string16& string, const string16& pattern);
|
||||
|
||||
// Hack to convert any char-like type to its unsigned counterpart.
|
||||
// For example, it will convert char, signed char and unsigned char to unsigned
|
||||
// char.
|
||||
template<typename T>
|
||||
struct ToUnsigned {
|
||||
typedef T Unsigned;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ToUnsigned<char> {
|
||||
typedef unsigned char Unsigned;
|
||||
};
|
||||
template<>
|
||||
struct ToUnsigned<signed char> {
|
||||
typedef unsigned char Unsigned;
|
||||
};
|
||||
template<>
|
||||
struct ToUnsigned<wchar_t> {
|
||||
#if defined(WCHAR_T_IS_UTF16)
|
||||
typedef unsigned short Unsigned;
|
||||
#elif defined(WCHAR_T_IS_UTF32)
|
||||
typedef uint32 Unsigned;
|
||||
#endif
|
||||
};
|
||||
template<>
|
||||
struct ToUnsigned<short> {
|
||||
typedef unsigned short Unsigned;
|
||||
};
|
||||
|
||||
#endif // BASE_STRINGS_STRING_UTIL_H_
|
|
@ -0,0 +1,55 @@
|
|||
// 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"
|
||||
|
||||
#define WHITESPACE_UNICODE \
|
||||
0x0009, /* <control-0009> to <control-000D> */ \
|
||||
0x000A, \
|
||||
0x000B, \
|
||||
0x000C, \
|
||||
0x000D, \
|
||||
0x0020, /* Space */ \
|
||||
0x0085, /* <control-0085> */ \
|
||||
0x00A0, /* No-Break Space */ \
|
||||
0x1680, /* Ogham Space Mark */ \
|
||||
0x180E, /* Mongolian Vowel Separator */ \
|
||||
0x2000, /* En Quad to Hair Space */ \
|
||||
0x2001, \
|
||||
0x2002, \
|
||||
0x2003, \
|
||||
0x2004, \
|
||||
0x2005, \
|
||||
0x2006, \
|
||||
0x2007, \
|
||||
0x2008, \
|
||||
0x2009, \
|
||||
0x200A, \
|
||||
0x200C, /* Zero Width Non-Joiner */ \
|
||||
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, // <control-0009> to <control-000D>
|
||||
0x0A,
|
||||
0x0B,
|
||||
0x0C,
|
||||
0x0D,
|
||||
0x20, // Space
|
||||
0
|
||||
};
|
||||
|
||||
const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
|
|
@ -0,0 +1,41 @@
|
|||
#include <wchar.h>
|
||||
|
||||
namespace base {
|
||||
|
||||
bool IsWprintfFormatPortable(const wchar_t* format) {
|
||||
for (const wchar_t* position = format; *position != '\0'; ++position) {
|
||||
if (*position == '%') {
|
||||
bool in_specification = true;
|
||||
bool modifier_l = false;
|
||||
while (in_specification) {
|
||||
// Eat up characters until reaching a known specifier.
|
||||
if (*++position == '\0') {
|
||||
// The format string ended in the middle of a specification. Call
|
||||
// it portable because no unportable specifications were found. The
|
||||
// string is equally broken on all platforms.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*position == 'l') {
|
||||
// 'l' is the only thing that can save the 's' and 'c' specifiers.
|
||||
modifier_l = true;
|
||||
} else if (((*position == 's' || *position == 'c') && !modifier_l) ||
|
||||
*position == 'S' || *position == 'C' || *position == 'F' ||
|
||||
*position == 'D' || *position == 'O' || *position == 'U') {
|
||||
// Not portable.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
|
||||
// Portable, keep scanning the rest of the format string.
|
||||
in_specification = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// 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_WIN_H_
|
||||
#define BASE_STRINGS_STRING_UTIL_WIN_H_
|
||||
|
||||
#include <stdarg.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 strcasecmp(const char* s1, const char* s2) {
|
||||
return _stricmp(s1, s2);
|
||||
}
|
||||
|
||||
inline int strncasecmp(const char* s1, const char* s2, size_t count) {
|
||||
return _strnicmp(s1, s2, count);
|
||||
}
|
||||
|
||||
inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
|
||||
return ::wcsncmp(s1, s2, count);
|
||||
}
|
||||
|
||||
inline int vsnprintf(char* buffer, size_t size,
|
||||
const char* format, va_list arguments) {
|
||||
int length = _vsprintf_p(buffer, size, format, arguments);
|
||||
if (length < 0) {
|
||||
if (size > 0)
|
||||
buffer[0] = 0;
|
||||
return _vscprintf_p(format, arguments);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
inline int vswprintf(wchar_t* buffer, size_t size,
|
||||
const wchar_t* format, va_list arguments) {
|
||||
DCHECK(IsWprintfFormatPortable(format));
|
||||
|
||||
int length = _vswprintf_p(buffer, size, format, arguments);
|
||||
if (length < 0) {
|
||||
if (size > 0)
|
||||
buffer[0] = 0;
|
||||
return _vscwprintf_p(format, arguments);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STRINGS_STRING_UTIL_WIN_H_
|
|
@ -0,0 +1,186 @@
|
|||
// 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/stringprintf.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "base/scoped_clear_errno.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
|
||||
// is the size of the buffer. These return the number of characters in the
|
||||
// formatted string excluding the NUL terminator. If the buffer is not
|
||||
// large enough to accommodate the formatted string without truncation, they
|
||||
// return the number of characters that would be in the fully-formatted string
|
||||
// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
|
||||
inline int vsnprintfT(char* buffer,
|
||||
size_t buf_size,
|
||||
const char* format,
|
||||
va_list argptr) {
|
||||
return base::vsnprintf(buffer, buf_size, format, argptr);
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
inline int vsnprintfT(wchar_t* buffer,
|
||||
size_t buf_size,
|
||||
const wchar_t* format,
|
||||
va_list argptr) {
|
||||
return base::vswprintf(buffer, buf_size, format, argptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Templatized backend for StringPrintF/StringAppendF. This does not finalize
|
||||
// the va_list, the caller is expected to do that.
|
||||
template <class StringType>
|
||||
static void StringAppendVT(StringType* dst,
|
||||
const typename StringType::value_type* format,
|
||||
va_list ap) {
|
||||
// First try with a small fixed size buffer.
|
||||
// This buffer size should be kept in sync with StringUtilTest.GrowBoundary
|
||||
// and StringUtilTest.StringPrintfBounds.
|
||||
typename StringType::value_type stack_buf[1024];
|
||||
|
||||
va_list ap_copy;
|
||||
GG_VA_COPY(ap_copy, ap);
|
||||
|
||||
#if !defined(OS_WIN)
|
||||
ScopedClearErrno clear_errno;
|
||||
#endif
|
||||
int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
|
||||
// It fit.
|
||||
dst->append(stack_buf, result);
|
||||
return;
|
||||
}
|
||||
|
||||
// Repeatedly increase buffer size until it fits.
|
||||
int mem_length = arraysize(stack_buf);
|
||||
while (true) {
|
||||
if (result < 0) {
|
||||
#if !defined(OS_WIN)
|
||||
// On Windows, vsnprintfT always returns the number of characters in a
|
||||
// fully-formatted string, so if we reach this point, something else is
|
||||
// wrong and no amount of buffer-doubling is going to fix it.
|
||||
if (errno != 0 && errno != EOVERFLOW)
|
||||
#endif
|
||||
{
|
||||
// If an error other than overflow occurred, it's never going to work.
|
||||
DLOG(WARNING) << "Unable to printf the requested string due to error.";
|
||||
return;
|
||||
}
|
||||
// Try doubling the buffer size.
|
||||
mem_length *= 2;
|
||||
} else {
|
||||
// We need exactly "result + 1" characters.
|
||||
mem_length = result + 1;
|
||||
}
|
||||
|
||||
if (mem_length > 32 * 1024 * 1024) {
|
||||
// That should be plenty, don't try anything larger. This protects
|
||||
// against huge allocations when using vsnprintfT implementations that
|
||||
// return -1 for reasons other than overflow without setting errno.
|
||||
DLOG(WARNING) << "Unable to printf the requested string due to size.";
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<typename StringType::value_type> mem_buf(mem_length);
|
||||
|
||||
// NOTE: You can only use a va_list once. Since we're in a while loop, we
|
||||
// need to make a new copy each time so we don't use up the original.
|
||||
GG_VA_COPY(ap_copy, ap);
|
||||
result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
if ((result >= 0) && (result < mem_length)) {
|
||||
// It fit.
|
||||
dst->append(&mem_buf[0], result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string StringPrintf(const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string result;
|
||||
StringAppendV(&result, format, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
std::wstring StringPrintf(const wchar_t* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::wstring result;
|
||||
StringAppendV(&result, format, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string StringPrintV(const char* format, va_list ap) {
|
||||
std::string result;
|
||||
StringAppendV(&result, format, ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
dst->clear();
|
||||
StringAppendV(dst, format, ap);
|
||||
va_end(ap);
|
||||
return *dst;
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
const std::wstring& SStringPrintf(std::wstring* dst,
|
||||
const wchar_t* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
dst->clear();
|
||||
StringAppendV(dst, format, ap);
|
||||
va_end(ap);
|
||||
return *dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
void StringAppendF(std::string* dst, const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
StringAppendV(dst, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
StringAppendV(dst, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
|
||||
void StringAppendV(std::string* dst, const char* format, va_list ap) {
|
||||
StringAppendVT(dst, format, ap);
|
||||
}
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
|
||||
StringAppendVT(dst, format, ap);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace base
|
|
@ -0,0 +1,62 @@
|
|||
// 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_STRINGPRINTF_H_
|
||||
#define BASE_STRINGS_STRINGPRINTF_H_
|
||||
|
||||
#include <stdarg.h> // va_list
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/compiler_specific.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Return a C++ string given printf-like input.
|
||||
BASE_EXPORT std::string StringPrintf(const char* format, ...)
|
||||
PRINTF_FORMAT(1, 2);
|
||||
// OS_ANDROID's libc does not support wchar_t, so several overloads are omitted.
|
||||
#if !defined(OS_ANDROID)
|
||||
BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
|
||||
WPRINTF_FORMAT(1, 2);
|
||||
#endif
|
||||
|
||||
// Return a C++ string given vprintf-like input.
|
||||
BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
|
||||
PRINTF_FORMAT(1, 0);
|
||||
|
||||
// Store result into a supplied string and return it.
|
||||
BASE_EXPORT const std::string& SStringPrintf(std::string* dst,
|
||||
const char* format, ...)
|
||||
PRINTF_FORMAT(2, 3);
|
||||
#if !defined(OS_ANDROID)
|
||||
BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
|
||||
const wchar_t* format, ...)
|
||||
WPRINTF_FORMAT(2, 3);
|
||||
#endif
|
||||
|
||||
// Append result to a supplied string.
|
||||
BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
|
||||
PRINTF_FORMAT(2, 3);
|
||||
#if !defined(OS_ANDROID)
|
||||
// TODO(evanm): this is only used in a few places in the code;
|
||||
// replace with string16 version.
|
||||
BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
|
||||
WPRINTF_FORMAT(2, 3);
|
||||
#endif
|
||||
|
||||
// Lower-level routine that takes a va_list and appends to a specified
|
||||
// string. All other routines are just convenience wrappers around it.
|
||||
BASE_EXPORT void StringAppendV(std::string* dst, const char* format, va_list ap)
|
||||
PRINTF_FORMAT(2, 0);
|
||||
#if !defined(OS_ANDROID)
|
||||
BASE_EXPORT void StringAppendV(std::wstring* dst,
|
||||
const wchar_t* format, va_list ap)
|
||||
WPRINTF_FORMAT(2, 0);
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_STRINGS_STRINGPRINTF_H_
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче