diff options
Diffstat (limited to 'base')
51 files changed, 11479 insertions, 0 deletions
diff --git a/base/OWNERS b/base/OWNERS new file mode 100644 index 000000000000..41dd3c96c64f --- /dev/null +++ b/base/OWNERS @@ -0,0 +1,6 @@ +set noparent +mark@chromium.org +darin@chromium.org +brettw@chromium.org +evan@chromium.org +willchan@chromium.org diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h new file mode 100644 index 000000000000..985c42c32381 --- /dev/null +++ b/base/atomic_ref_count.h @@ -0,0 +1,81 @@ +// 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_ +#pragma once + +#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_ diff --git a/base/atomic_sequence_num.h b/base/atomic_sequence_num.h new file mode 100644 index 000000000000..11805a0ae501 --- /dev/null +++ b/base/atomic_sequence_num.h @@ -0,0 +1,31 @@ +// 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_ATOMIC_SEQUENCE_NUM_H_ +#define BASE_ATOMIC_SEQUENCE_NUM_H_ +#pragma once + +#include "base/atomicops.h" +#include "base/basictypes.h" + +namespace base { + +class AtomicSequenceNumber { + public: + AtomicSequenceNumber() : seq_(0) { } + explicit AtomicSequenceNumber(base::LinkerInitialized x) { /* seq_ is 0 */ } + + int GetNext() { + return static_cast<int>( + base::subtle::NoBarrier_AtomicIncrement(&seq_, 1) - 1); + } + + private: + base::subtle::Atomic32 seq_; + DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber); +}; + +} // namespace base + +#endif // BASE_ATOMIC_SEQUENCE_NUM_H_ diff --git a/base/atomicops.h b/base/atomicops.h new file mode 100644 index 000000000000..a087e3d09c9a --- /dev/null +++ b/base/atomicops.h @@ -0,0 +1,150 @@ +// 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. + +// 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_ +#pragma once + +#include "base/basictypes.h" +#include "build/build_config.h" + +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(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(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) +#include "base/atomicops_internals_x86_msvc.h" +#elif defined(OS_MACOSX) && defined(ARCH_CPU_X86_FAMILY) +#include "base/atomicops_internals_x86_macosx.h" +#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY) +#include "base/atomicops_internals_x86_gcc.h" +#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY) +#include "base/atomicops_internals_arm_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_ diff --git a/base/atomicops_internals_arm_gcc.h b/base/atomicops_internals_arm_gcc.h new file mode 100644 index 000000000000..091b34d55ceb --- /dev/null +++ b/base/atomicops_internals_arm_gcc.h @@ -0,0 +1,125 @@ +// 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. + +// This file is an internal atomic implementation, use base/atomicops.h instead. +// +// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears. + +#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_ +#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_ +#pragma once + +namespace base { +namespace subtle { + +// 0xffff0fc0 is the hard coded address of a function provided by +// the kernel which implements an atomic compare-exchange. On older +// ARM architecture revisions (pre-v6) this may be implemented using +// a syscall. This address is stable, and in active use (hard coded) +// by at least glibc-2.7 and the Android C library. +typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value, + Atomic32 new_value, + volatile Atomic32* ptr); +LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) = + (LinuxKernelCmpxchgFunc) 0xffff0fc0; + +typedef void (*LinuxKernelMemoryBarrierFunc)(void); +LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) = + (LinuxKernelMemoryBarrierFunc) 0xffff0fa0; + + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev_value = *ptr; + do { + if (!pLinuxKernelCmpxchg(old_value, new_value, + const_cast<Atomic32*>(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + Atomic32 old_value; + do { + old_value = *ptr; + } while (pLinuxKernelCmpxchg(old_value, new_value, + const_cast<Atomic32*>(ptr))); + return old_value; +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return Barrier_AtomicIncrement(ptr, increment); +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + for (;;) { + // Atomic exchange the old value with an incremented one. + Atomic32 old_value = *ptr; + Atomic32 new_value = old_value + increment; + if (pLinuxKernelCmpxchg(old_value, new_value, + const_cast<Atomic32*>(ptr)) == 0) { + // The exchange took place as expected. + return new_value; + } + // Otherwise, *ptr changed mid-loop and we need to retry. + } + +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + 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 MemoryBarrier() { + pLinuxKernelMemoryBarrier(); +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return *ptr; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + MemoryBarrier(); + return *ptr; +} + +} // namespace base::subtle +} // namespace base + +#endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_ diff --git a/base/atomicops_internals_atomicword_compat.h b/base/atomicops_internals_atomicword_compat.h new file mode 100644 index 000000000000..8382fe1bc970 --- /dev/null +++ b/base/atomicops_internals_atomicword_compat.h @@ -0,0 +1,101 @@ +// 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_ATOMICWORD_COMPAT_H_ +#define BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_ +#pragma once + +// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32, +// which in turn means int. On some LP32 platforms, intptr_t is an int, but +// on others, it's a long. When AtomicWord and Atomic32 are based on different +// fundamental types, their pointers are incompatible. +// +// This file defines function overloads to allow both AtomicWord and Atomic32 +// data to be used with this interface. +// +// On LP64 platforms, AtomicWord and Atomic64 are both always long, +// so this problem doesn't occur. + +#if !defined(ARCH_CPU_64_BITS) + +namespace base { +namespace subtle { + +inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr, + AtomicWord old_value, + AtomicWord new_value) { + return NoBarrier_CompareAndSwap( + reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value); +} + +inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr, + AtomicWord new_value) { + return NoBarrier_AtomicExchange( + reinterpret_cast<volatile Atomic32*>(ptr), new_value); +} + +inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr, + AtomicWord increment) { + return NoBarrier_AtomicIncrement( + reinterpret_cast<volatile Atomic32*>(ptr), increment); +} + +inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr, + AtomicWord increment) { + return Barrier_AtomicIncrement( + reinterpret_cast<volatile Atomic32*>(ptr), increment); +} + +inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr, + AtomicWord old_value, + AtomicWord new_value) { + return base::subtle::Acquire_CompareAndSwap( + reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value); +} + +inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr, + AtomicWord old_value, + AtomicWord new_value) { + return base::subtle::Release_CompareAndSwap( + reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value); +} + +inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) { + NoBarrier_Store( + reinterpret_cast<volatile Atomic32*>(ptr), value); +} + +inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) { + return base::subtle::Acquire_Store( + reinterpret_cast<volatile Atomic32*>(ptr), value); +} + +inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) { + return base::subtle::Release_Store( + reinterpret_cast<volatile Atomic32*>(ptr), value); +} + +inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) { + return NoBarrier_Load( + reinterpret_cast<volatile const Atomic32*>(ptr)); +} + +inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) { + return base::subtle::Acquire_Load( + reinterpret_cast<volatile const Atomic32*>(ptr)); +} + +inline AtomicWord Release_Load(volatile const AtomicWord* ptr) { + return base::subtle::Release_Load( + reinterpret_cast<volatile const Atomic32*>(ptr)); +} + +} // namespace base::subtle +} // namespace base + +#endif // !defined(ARCH_CPU_64_BITS) + +#endif // BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_ diff --git a/base/atomicops_internals_x86_gcc.cc b/base/atomicops_internals_x86_gcc.cc new file mode 100644 index 000000000000..933ca51896df --- /dev/null +++ b/base/atomicops_internals_x86_gcc.cc @@ -0,0 +1,104 @@ +// 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 module gets enough CPU information to optimize the +// atomicops module on x86. + +#include <string.h> + +#include "base/atomicops.h" +#include "base/basictypes.h" + +// This file only makes sense with atomicops_internals_x86_gcc.h -- it +// depends on structs that are defined in that file. If atomicops.h +// doesn't sub-include that file, then we aren't needed, and shouldn't +// try to do anything. +#ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_ + +// Inline cpuid instruction. In PIC compilations, %ebx contains the address +// of the global offset table. To avoid breaking such executables, this code +// must preserve that register's value across cpuid instructions. +#if defined(__i386__) +#define cpuid(a, b, c, d, inp) \ + asm ("mov %%ebx, %%edi\n" \ + "cpuid\n" \ + "xchg %%edi, %%ebx\n" \ + : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) +#elif defined (__x86_64__) +#define cpuid(a, b, c, d, inp) \ + asm ("mov %%rbx, %%rdi\n" \ + "cpuid\n" \ + "xchg %%rdi, %%rbx\n" \ + : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) +#endif + +#if defined(cpuid) // initialize the struct only on x86 + +// Set the flags so that code will run correctly and conservatively, so even +// if we haven't been initialized yet, we're probably single threaded, and our +// default values should hopefully be pretty safe. +struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = { + false, // bug can't exist before process spawns multiple threads + false, // no SSE2 +}; + +// Initialize the AtomicOps_Internalx86CPUFeatures struct. +static void AtomicOps_Internalx86CPUFeaturesInit() { + uint32 eax; + uint32 ebx; + uint32 ecx; + uint32 edx; + + // Get vendor string (issue CPUID with eax = 0) + cpuid(eax, ebx, ecx, edx, 0); + char vendor[13]; + memcpy(vendor, &ebx, 4); + memcpy(vendor + 4, &edx, 4); + memcpy(vendor + 8, &ecx, 4); + vendor[12] = 0; + + // get feature flags in ecx/edx, and family/model in eax + cpuid(eax, ebx, ecx, edx, 1); + + int family = (eax >> 8) & 0xf; // family and model fields + int model = (eax >> 4) & 0xf; + if (family == 0xf) { // use extended family and model fields + family += (eax >> 20) & 0xff; + model += ((eax >> 16) & 0xf) << 4; + } + + // Opteron Rev E has a bug in which on very rare occasions a locked + // instruction doesn't act as a read-acquire barrier if followed by a + // non-locked read-modify-write instruction. Rev F has this bug in + // pre-release versions, but not in versions released to customers, + // so we test only for Rev E, which is family 15, model 32..63 inclusive. + if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD + family == 15 && + 32 <= model && model <= 63) { + AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true; + } else { + AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false; + } + + // edx bit 26 is SSE2 which we use to tell use whether we can use mfence + AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1); +} + +namespace { + +class AtomicOpsx86Initializer { + public: + AtomicOpsx86Initializer() { + AtomicOps_Internalx86CPUFeaturesInit(); + } +}; + +// A global to get use initialized on startup via static initialization :/ +AtomicOpsx86Initializer g_initer; + +} // namespace + +#endif // if x86 + +#endif // ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_ diff --git a/base/atomicops_internals_x86_gcc.h b/base/atomicops_internals_x86_gcc.h new file mode 100644 index 000000000000..72fd35000e7a --- /dev/null +++ b/base/atomicops_internals_x86_gcc.h @@ -0,0 +1,270 @@ +// 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_ +#pragma once + +#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_ diff --git a/base/atomicops_internals_x86_macosx.h b/base/atomicops_internals_x86_macosx.h new file mode 100644 index 000000000000..4b7cec81d045 --- /dev/null +++ b/base/atomicops_internals_x86_macosx.h @@ -0,0 +1,198 @@ +// 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_MACOSX_H_ +#define BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_ +#pragma once + +#include <libkern/OSAtomic.h> + +namespace base { +namespace subtle { + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev_value; + do { + if (OSAtomicCompareAndSwap32(old_value, new_value, + const_cast<Atomic32*>(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr, + Atomic32 new_value) { + Atomic32 old_value; + do { + old_value = *ptr; + } while (!OSAtomicCompareAndSwap32(old_value, new_value, + const_cast<Atomic32*>(ptr))); + return old_value; +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr, + Atomic32 increment) { + return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr)); +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr, + Atomic32 increment) { + return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr)); +} + +inline void MemoryBarrier() { + OSMemoryBarrier(); +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev_value; + do { + if (OSAtomicCompareAndSwap32Barrier(old_value, new_value, + const_cast<Atomic32*>(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr, + Atomic32 old_value, + Atomic32 new_value) { + return Acquire_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) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return *ptr; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32 *ptr) { + MemoryBarrier(); + return *ptr; +} + +#ifdef __LP64__ + +// 64-bit implementation on 64-bit platform + +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 prev_value; + do { + if (OSAtomicCompareAndSwap64(old_value, new_value, + reinterpret_cast<volatile int64_t*>(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr, + Atomic64 new_value) { + Atomic64 old_value; + do { + old_value = *ptr; + } while (!OSAtomicCompareAndSwap64(old_value, new_value, + reinterpret_cast<volatile int64_t*>(ptr))); + return old_value; +} + +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr, + Atomic64 increment) { + return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr)); +} + +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr, + Atomic64 increment) { + return OSAtomicAdd64Barrier(increment, + reinterpret_cast<volatile int64_t*>(ptr)); +} + +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 prev_value; + do { + if (OSAtomicCompareAndSwap64Barrier( + old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr, + Atomic64 old_value, + Atomic64 new_value) { + // The lib kern interface does not distinguish between + // Acquire and Release memory barriers; they are equivalent. + return Acquire_CompareAndSwap(ptr, old_value, new_value); +} + +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) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { + return *ptr; +} + +inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) { + Atomic64 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic64 Release_Load(volatile const Atomic64 *ptr) { + MemoryBarrier(); + return *ptr; +} + +#endif // defined(__LP64__) + +} // namespace base::subtle +} // namespace base + +#endif // BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_ diff --git a/base/atomicops_internals_x86_msvc.h b/base/atomicops_internals_x86_msvc.h new file mode 100644 index 000000000000..15745288c3d4 --- /dev/null +++ b/base/atomicops_internals_x86_msvc.h @@ -0,0 +1,181 @@ +// 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_ +#pragma once + +#include <windows.h> + +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() { + // We use MemoryBarrier from WinNT.h + ::MemoryBarrier(); +} + +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_ diff --git a/base/base_export.h b/base/base_export.h new file mode 100644 index 000000000000..c3bff9fae031 --- /dev/null +++ b/base/base_export.h @@ -0,0 +1,26 @@ +// 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_BASE_OSP_EXPORT_ +#define BASE_BASE_OSP_EXPORT_ +#pragma once + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(BASE_IMPLEMENTATION) +#define BASE_EXPORT __declspec(dllexport) +#else +#define BASE_EXPORT __declspec(dllimport) +#endif // defined(BASE_IMPLEMENTATION) + +#else // defined(WIN32) +#define BASE_EXPORT __attribute__((visibility("default"))) +#endif + +#else // defined(COMPONENT_BUILD) +#define BASE_EXPORT +#endif + +#endif // BASE_BASE_OSP_EXPORT_ diff --git a/base/basictypes.h b/base/basictypes.h new file mode 100644 index 000000000000..c6f509785660 --- /dev/null +++ b/base/basictypes.h @@ -0,0 +1,367 @@ +// 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_ +#pragma once + +#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; +// TODO: Remove these type guards. These are to avoid conflicts with +// obsolete/protypes.h in the Gecko SDK. +#ifndef _INT32 +#define _INT32 +typedef int int32; +#endif + +// 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) +typedef long int64; +#else +typedef long long int64; +#endif + +// NOTE: unsigned types are DANGEROUS in loops and other arithmetical +// places. Use the signed types unless your variable represents a bit +// pattern (eg a hash value) or you really need the extra bit. Do NOT +// use 'unsigned' to express "this value should always be positive"; +// use assertions for this. + +typedef unsigned char uint8; +typedef unsigned short uint16; +// TODO: Remove these type guards. These are to avoid conflicts with +// obsolete/protypes.h in the Gecko SDK. +#ifndef _UINT32 +#define _UINT32 +typedef unsigned int uint32; +#endif + +// See the comment above about NSPR and 64-bit. +#if defined(__LP64__) && !defined(OS_MACOSX) +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)); + +// 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 baned 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 convertable 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. + + +// MetatagId refers to metatag-id that we assign to +// each metatag <name, value> pair.. +typedef uint32 MetatagId; + +// Argument type used in interfaces that can optionally take ownership +// of a passed in argument. If TAKE_OWNERSHIP is passed, the called +// object takes ownership of the argument. Otherwise it does not. +enum Ownership { + DO_NOT_TAKE_OWNERSHIP, + TAKE_OWNERSHIP +}; + +// 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 betweeen 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& ignored) { +} + +// 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 }; +} // base + +#endif // BASE_BASICTYPES_H_ diff --git a/base/compiler_specific.h b/base/compiler_specific.h new file mode 100644 index 000000000000..0a6e05a6c679 --- /dev/null +++ b/base/compiler_specific.h @@ -0,0 +1,140 @@ +// 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_COMPILER_SPECIFIC_H_ +#define BASE_COMPILER_SPECIFIC_H_ +#pragma once + +#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 |this| to be passed as an argument in constructor initializer lists. +// This uses push/pop instead of the seemingly simpler suppress feature to avoid +// having the warning be disabled for more than just |code|. +// +// Example usage: +// Foo::Foo() : x(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(y(this)), z(3) {} +// +// Compiler warning C4355: 'this': used in base member initializer list: +// http://msdn.microsoft.com/en-us/library/3c594ae3(VS.80).aspx +#define ALLOW_THIS_IN_INITIALIZER_LIST(code) MSVC_PUSH_DISABLE_WARNING(4355) \ + code \ + MSVC_POP_WARNING() + +// 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 +// can be gained through the derived class. 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 ALLOW_THIS_IN_INITIALIZER_LIST(code) code +#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)) +#define NOINLINE __attribute__((noinline)) +#else +#define ALLOW_UNUSED +#define NOINLINE +#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 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))) + +#endif // BASE_COMPILER_SPECIFIC_H_ diff --git a/base/file_descriptor_posix.h b/base/file_descriptor_posix.h new file mode 100644 index 000000000000..6f46ab4986cc --- /dev/null +++ b/base/file_descriptor_posix.h @@ -0,0 +1,46 @@ +// 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_ +#pragma once + +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_ diff --git a/base/hash_tables.h b/base/hash_tables.h new file mode 100644 index 000000000000..b91d5d48bb6f --- /dev/null +++ b/base/hash_tables.h @@ -0,0 +1,120 @@ +// 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_HASH_TABLES_H_ +#define BASE_HASH_TABLES_H_ +#pragma once + +#include "build/build_config.h" + +#include "base/string16.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_set; +} + +#endif // BASE_HASH_TABLES_H_ diff --git a/base/logging.h b/base/logging.h new file mode 100644 index 000000000000..c18fadadb6c4 --- /dev/null +++ b/base/logging.h @@ -0,0 +1,952 @@ +// 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_LOGGING_H_ +#define BASE_LOGGING_H_ +#pragma once + +#include <cassert> +#include <string> +#include <cstring> +#include <sstream> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "build/build_config.h" + +// +// Optional message capabilities +// ----------------------------- +// Assertion failed messages and fatal errors are displayed in a dialog box +// before the application exits. However, running this UI creates a message +// loop, which causes application messages to be processed and potentially +// dispatched to existing application windows. Since the application is in a +// bad state when this assertion dialog is displayed, these messages may not +// get processed and hang the dialog, or the application might go crazy. +// +// Therefore, it can be beneficial to display the error dialog in a separate +// process from the main application. When the logging system needs to display +// a fatal error dialog box, it will look for a program called +// "DebugMessage.exe" in the same directory as the application executable. It +// will run this application with the message as the command line, and will +// not include the name of the application as is traditional for easier +// parsing. +// +// The code for DebugMessage.exe is only one line. In WinMain, do: +// MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0); +// +// If DebugMessage.exe is not found, the logging code will use a normal +// MessageBox, potentially causing the problems discussed above. + + +// Instructions +// ------------ +// +// Make a bunch of macros for logging. The way to log things is to stream +// things to LOG(<a particular severity level>). E.g., +// +// LOG(INFO) << "Found " << num_cookies << " cookies"; +// +// You can also do conditional logging: +// +// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// The above will cause log messages to be output on the 1st, 11th, 21st, ... +// times it is executed. Note that the special COUNTER value is used to +// identify which repetition is happening. +// +// The CHECK(condition) macro is active in both debug and release builds and +// effectively performs a LOG(FATAL) which terminates the process and +// generates a crashdump unless a debugger is attached. +// +// There are also "debug mode" logging macros like the ones above: +// +// DLOG(INFO) << "Found cookies"; +// +// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// All "debug mode" logging is compiled away to nothing for non-debug mode +// compiles. LOG_IF and development flags also work well together +// because the code can be compiled away sometimes. +// +// We also have +// +// LOG_ASSERT(assertion); +// DLOG_ASSERT(assertion); +// +// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; +// +// There are "verbose level" logging macros. They look like +// +// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; +// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; +// +// These always log at the INFO log level (when they log at all). +// The verbose logging can also be turned on module-by-module. For instance, +// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0 +// will cause: +// a. VLOG(2) and lower messages to be printed from profile.{h,cc} +// b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc} +// c. VLOG(3) and lower messages to be printed from files prefixed with +// "browser" +// d. VLOG(4) and lower messages to be printed from files under a +// "chromeos" directory. +// e. VLOG(0) and lower messages to be printed from elsewhere +// +// The wildcarding functionality shown by (c) supports both '*' (match +// 0 or more characters) and '?' (match any single character) +// wildcards. Any pattern containing a forward or backward slash will +// be tested against the whole pathname and not just the module. +// E.g., "*/foo/bar/*=2" would change the logging level for all code +// in source files under a "foo/bar" directory. +// +// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as +// +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished with just VLOG(2) << ...; +// } +// +// There is also a VLOG_IF "verbose level" condition macro for sample +// cases, when some extra computation and preparation for logs is not +// needed. +// +// VLOG_IF(1, (size > 1024)) +// << "I'm printed when size is more than 1024 and when you run the " +// "program with --v=1 or more"; +// +// We also override the standard 'assert' to use 'DLOG_ASSERT'. +// +// Lastly, there is: +// +// PLOG(ERROR) << "Couldn't do foo"; +// DPLOG(ERROR) << "Couldn't do foo"; +// PLOG_IF(ERROR, cond) << "Couldn't do foo"; +// DPLOG_IF(ERROR, cond) << "Couldn't do foo"; +// PCHECK(condition) << "Couldn't do foo"; +// DPCHECK(condition) << "Couldn't do foo"; +// +// which append the last system error to the message in string form (taken from +// GetLastError() on Windows and errno on POSIX). +// +// The supported severity levels for macros that allow you to specify one +// are (in increasing order of severity) INFO, WARNING, ERROR, ERROR_REPORT, +// and FATAL. +// +// Very important: logging a message at the FATAL severity level causes +// the program to terminate (after the message is logged). +// +// Note the special severity of ERROR_REPORT only available/relevant in normal +// mode, which displays error dialog without terminating the program. There is +// no error dialog for severity ERROR or below in normal mode. +// +// There is also the special severity of DFATAL, which logs FATAL in +// debug mode, ERROR in normal mode. + +namespace logging { + +// Where to record logging output? A flat file and/or system debug log via +// OutputDebugString. Defaults on Windows to LOG_ONLY_TO_FILE, and on +// POSIX to LOG_ONLY_TO_SYSTEM_DEBUG_LOG (aka stderr). +enum LoggingDestination { LOG_NONE, + LOG_ONLY_TO_FILE, + LOG_ONLY_TO_SYSTEM_DEBUG_LOG, + LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG }; + +// Indicates that the log file should be locked when being written to. +// Often, there is no locking, which is fine for a single threaded program. +// If logging is being done from multiple threads or there can be more than +// one process doing the logging, the file should be locked during writes to +// make each log outut atomic. Other writers will block. +// +// All processes writing to the log file must have their locking set for it to +// work properly. Defaults to DONT_LOCK_LOG_FILE. +enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE }; + +// On startup, should we delete or append to an existing log file (if any)? +// Defaults to APPEND_TO_OLD_LOG_FILE. +enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE }; + +enum DcheckState { + DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS, + ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS +}; + +// TODO(avi): do we want to do a unification of character types here? +#if defined(OS_WIN) +typedef wchar_t PathChar; +#else +typedef char PathChar; +#endif + +// Define different names for the BaseInitLoggingImpl() function depending on +// whether NDEBUG is defined or not so that we'll fail to link if someone tries +// to compile logging.cc with NDEBUG but includes logging.h without defining it, +// or vice versa. +#if NDEBUG +#define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG +#else +#define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG +#endif + +// Implementation of the InitLogging() method declared below. We use a +// more-specific name so we can #define it above without affecting other code +// that has named stuff "InitLogging". +BASE_EXPORT bool BaseInitLoggingImpl(const PathChar* log_file, + LoggingDestination logging_dest, + LogLockingState lock_log, + OldFileDeletionState delete_old, + DcheckState dcheck_state); + +// Sets the log file name and other global logging state. Calling this function +// is recommended, and is normally done at the beginning of application init. +// If you don't call it, all the flags will be initialized to their default +// values, and there is a race condition that may leak a critical section +// object if two threads try to do the first log at the same time. +// See the definition of the enums above for descriptions and default values. +// +// The default log file is initialized to "debug.log" in the application +// directory. You probably don't want this, especially since the program +// directory may not be writable on an enduser's system. +inline bool InitLogging(const PathChar* log_file, + LoggingDestination logging_dest, + LogLockingState lock_log, + OldFileDeletionState delete_old, + DcheckState dcheck_state) { + return BaseInitLoggingImpl(log_file, logging_dest, lock_log, + delete_old, dcheck_state); +} + +// Sets the log level. Anything at or above this level will be written to the +// log file/displayed to the user (if applicable). Anything below this level +// will be silently ignored. The log level defaults to 0 (everything is logged +// up to level INFO) if this function is not called. +// Note that log messages for VLOG(x) are logged at level -x, so setting +// the min log level to negative values enables verbose logging. +BASE_EXPORT void SetMinLogLevel(int level); + +// Gets the current log level. +BASE_EXPORT int GetMinLogLevel(); + +// Gets the VLOG default verbosity level. +BASE_EXPORT int GetVlogVerbosity(); + +// Gets the current vlog level for the given file (usually taken from +// __FILE__). + +// Note that |N| is the size *with* the null terminator. +BASE_EXPORT int GetVlogLevelHelper(const char* file_start, size_t N); + +template <size_t N> +int GetVlogLevel(const char (&file)[N]) { + return GetVlogLevelHelper(file, N); +} + +// Sets the common items you want to be prepended to each log message. +// process and thread IDs default to off, the timestamp defaults to on. +// If this function is not called, logging defaults to writing the timestamp +// only. +BASE_EXPORT void SetLogItems(bool enable_process_id, bool enable_thread_id, + bool enable_timestamp, bool enable_tickcount); + +// Sets whether or not you'd like to see fatal debug messages popped up in +// a dialog box or not. +// Dialogs are not shown by default. +BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs); + +// Sets the Log Assert Handler that will be used to notify of check failures. +// The default handler shows a dialog box and then terminate the process, +// however clients can use this function to override with their own handling +// (e.g. a silent one for Unit Tests) +typedef void (*LogAssertHandlerFunction)(const std::string& str); +BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler); + +// Sets the Log Report Handler that will be used to notify of check failures +// in non-debug mode. The default handler shows a dialog box and continues +// the execution, however clients can use this function to override with their +// own handling. +typedef void (*LogReportHandlerFunction)(const std::string& str); +BASE_EXPORT void SetLogReportHandler(LogReportHandlerFunction handler); + +// Sets the Log Message Handler that gets passed every log message before +// it's sent to other log destinations (if any). +// Returns true to signal that it handled the message and the message +// should not be sent to other log destinations. +typedef bool (*LogMessageHandlerFunction)(int severity, + const char* file, int line, size_t message_start, const std::string& str); +BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler); +BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler(); + +typedef int LogSeverity; +const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity +// Note: the log severities are used to index into the array of names, +// see log_severity_names. +const LogSeverity LOG_INFO = 0; +const LogSeverity LOG_WARNING = 1; +const LogSeverity LOG_ERROR = 2; +const LogSeverity LOG_ERROR_REPORT = 3; +const LogSeverity LOG_FATAL = 4; +const LogSeverity LOG_NUM_SEVERITIES = 5; + +// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode +#ifdef NDEBUG +const LogSeverity LOG_DFATAL = LOG_ERROR; +#else +const LogSeverity LOG_DFATAL = LOG_FATAL; +#endif + +// A few definitions of macros that don't generate much code. These are used +// by LOG() and LOG_IF, etc. Since these are used all over our code, it's +// better to have compact code for these operations. +#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, \ + logging::LOG_ERROR_REPORT , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__) + +#define COMPACT_GOOGLE_LOG_INFO \ + COMPACT_GOOGLE_LOG_EX_INFO(LogMessage) +#define COMPACT_GOOGLE_LOG_WARNING \ + COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage) +#define COMPACT_GOOGLE_LOG_ERROR \ + COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage) +#define COMPACT_GOOGLE_LOG_ERROR_REPORT \ + COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(LogMessage) +#define COMPACT_GOOGLE_LOG_FATAL \ + COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage) +#define COMPACT_GOOGLE_LOG_DFATAL \ + COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage) + +// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets +// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us +// to keep using this syntax, we define this macro to do the same thing +// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that +// the Windows SDK does for consistency. +#define ERROR 0 +#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \ + COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR +// Needed for LOG_IS_ON(ERROR). +const LogSeverity LOG_0 = LOG_ERROR; + +// As special cases, we can assume that LOG_IS_ON(ERROR_REPORT) and +// LOG_IS_ON(FATAL) always hold. Also, LOG_IS_ON(DFATAL) always holds +// in debug mode. In particular, CHECK()s will always fire if they +// fail. +#define LOG_IS_ON(severity) \ + ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel()) + +// We can't do any caching tricks with VLOG_IS_ON() like the +// google-glog version since it requires GCC extensions. This means +// that using the v-logging functions in conjunction with --vmodule +// may be slow. +#define VLOG_IS_ON(verboselevel) \ + ((verboselevel) <= ::logging::GetVlogLevel(__FILE__)) + +// Helper macro which avoids evaluating the arguments to a stream if +// the condition doesn't hold. +#define LAZY_STREAM(stream, condition) \ + !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream) + +// We use the preprocessor's merging operator, "##", so that, e.g., +// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny +// subtle difference between ostream member streaming functions (e.g., +// ostream::operator<<(int) and ostream non-member streaming functions +// (e.g., ::operator<<(ostream&, string&): it turns out that it's +// impossible to stream something like a string directly to an unnamed +// ostream. We employ a neat hack by calling the stream() member +// function of LogMessage which seems to avoid the problem. +#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() + +#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity)) +#define LOG_IF(severity, condition) \ + LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition)) + +#define SYSLOG(severity) LOG(severity) +#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition) + +// The VLOG macros log with negative verbosities. +#define VLOG_STREAM(verbose_level) \ + logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream() + +#define VLOG(verbose_level) \ + LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level)) + +#define VLOG_IF(verbose_level, condition) \ + LAZY_STREAM(VLOG_STREAM(verbose_level), \ + VLOG_IS_ON(verbose_level) && (condition)) + +#if defined (OS_WIN) +#define VPLOG_STREAM(verbose_level) \ + logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \ + ::logging::GetLastSystemErrorCode()).stream() +#elif defined(OS_POSIX) +#define VPLOG_STREAM(verbose_level) \ + logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \ + ::logging::GetLastSystemErrorCode()).stream() +#endif + +#define VPLOG(verbose_level) \ + LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level)) + +#define VPLOG_IF(verbose_level, condition) \ + LAZY_STREAM(VPLOG_STREAM(verbose_level), \ + VLOG_IS_ON(verbose_level) && (condition)) + +// TODO(akalin): Add more VLOG variants, e.g. VPLOG. + +#define LOG_ASSERT(condition) \ + LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " +#define SYSLOG_ASSERT(condition) \ + SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " + +#if defined(OS_WIN) +#define LOG_GETLASTERROR_STREAM(severity) \ + COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \ + ::logging::GetLastSystemErrorCode()).stream() +#define LOG_GETLASTERROR(severity) \ + LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), LOG_IS_ON(severity)) +#define LOG_GETLASTERROR_MODULE_STREAM(severity, module) \ + COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \ + ::logging::GetLastSystemErrorCode(), module).stream() +#define LOG_GETLASTERROR_MODULE(severity, module) \ + LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module), \ + LOG_IS_ON(severity)) +// PLOG_STREAM is used by PLOG, which is the usual error logging macro +// for each platform. +#define PLOG_STREAM(severity) LOG_GETLASTERROR_STREAM(severity) +#elif defined(OS_POSIX) +#define LOG_ERRNO_STREAM(severity) \ + COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \ + ::logging::GetLastSystemErrorCode()).stream() +#define LOG_ERRNO(severity) \ + LAZY_STREAM(LOG_ERRNO_STREAM(severity), LOG_IS_ON(severity)) +// PLOG_STREAM is used by PLOG, which is the usual error logging macro +// for each platform. +#define PLOG_STREAM(severity) LOG_ERRNO_STREAM(severity) +// TODO(tschmelcher): Should we add OSStatus logging for Mac? +#endif + +#define PLOG(severity) \ + LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity)) + +#define PLOG_IF(severity, condition) \ + LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition)) + +// CHECK dies with a fatal error if condition is not true. It is *not* +// controlled by NDEBUG, so the check will be executed regardless of +// compilation mode. +// +// We make sure CHECK et al. always evaluates their arguments, as +// doing CHECK(FunctionWithSideEffect()) is a common idiom. +#define CHECK(condition) \ + LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \ + << "Check failed: " #condition ". " + +#define PCHECK(condition) \ + LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \ + << "Check failed: " #condition ". " + +// Build the error message string. This is separate from the "Impl" +// function template because it is not performance critical and so can +// be out of line, while the "Impl" code should be inline. Caller +// takes ownership of the returned string. +template<class t1, class t2> +std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) { + std::ostringstream ss; + ss << names << " (" << v1 << " vs. " << v2 << ")"; + std::string* msg = new std::string(ss.str()); + return msg; +} + +// MSVC doesn't like complex extern templates and DLLs. +#if !defined(COMPILER_MSVC) && !defined(COMPONENT_BUILD) +// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated +// in logging.cc. +extern template std::string* MakeCheckOpString<int, int>( + const int&, const int&, const char* names); +extern template std::string* MakeCheckOpString<unsigned long, unsigned long>( + const unsigned long&, const unsigned long&, const char* names); +extern template std::string* MakeCheckOpString<unsigned long, unsigned int>( + const unsigned long&, const unsigned int&, const char* names); +extern template std::string* MakeCheckOpString<unsigned int, unsigned long>( + const unsigned int&, const unsigned long&, const char* names); +extern template std::string* MakeCheckOpString<std::string, std::string>( + const std::string&, const std::string&, const char* name); +#endif + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use CHECK_EQ et al below. +// +// TODO(akalin): Rewrite this so that constructs like if (...) +// CHECK_EQ(...) else { ... } work properly. +#define CHECK_OP(name, op, val1, val2) \ + if (std::string* _result = \ + logging::Check##name##Impl((val1), (val2), \ + #val1 " " #op " " #val2)) \ + logging::LogMessage(__FILE__, __LINE__, _result).stream() + +// Helper functions for CHECK_OP macro. +// The (int, int) specialization works around the issue that the compiler +// will not instantiate the template version of the function on values of +// unnamed enum type - see comment below. +#define DEFINE_CHECK_OP_IMPL(name, op) \ + template <class t1, class t2> \ + inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ + const char* names) { \ + if (v1 op v2) return NULL; \ + else return MakeCheckOpString(v1, v2, names); \ + } \ + inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ + if (v1 op v2) return NULL; \ + else return MakeCheckOpString(v1, v2, names); \ + } +DEFINE_CHECK_OP_IMPL(EQ, ==) +DEFINE_CHECK_OP_IMPL(NE, !=) +DEFINE_CHECK_OP_IMPL(LE, <=) +DEFINE_CHECK_OP_IMPL(LT, < ) +DEFINE_CHECK_OP_IMPL(GE, >=) +DEFINE_CHECK_OP_IMPL(GT, > ) +#undef DEFINE_CHECK_OP_IMPL + +#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2) +#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2) +#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2) +#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2) +#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2) +#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2) + +// http://crbug.com/16512 is open for a real fix for this. For now, Windows +// uses OFFICIAL_BUILD and other platforms use the branding flag when NDEBUG is +// defined. +#if ( defined(OS_WIN) && defined(OFFICIAL_BUILD)) || \ + (!defined(OS_WIN) && defined(NDEBUG) && defined(GOOGLE_CHROME_BUILD)) +// Used by unit tests. +#define LOGGING_IS_OFFICIAL_BUILD + +// In order to have optimized code for official builds, remove DLOGs and +// DCHECKs. +#define ENABLE_DLOG 0 +#define ENABLE_DCHECK 0 + +#elif defined(NDEBUG) +// Otherwise, if we're a release build, remove DLOGs but not DCHECKs +// (since those can still be turned on via a command-line flag). +#define ENABLE_DLOG 0 +#define ENABLE_DCHECK 1 + +#else +// Otherwise, we're a debug build so enable DLOGs and DCHECKs. +#define ENABLE_DLOG 1 +#define ENABLE_DCHECK 1 +#endif + +// Definitions for DLOG et al. + +#if ENABLE_DLOG + +#define DLOG_IS_ON(severity) LOG_IS_ON(severity) +#define DLOG_IF(severity, condition) LOG_IF(severity, condition) +#define DLOG_ASSERT(condition) LOG_ASSERT(condition) +#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition) +#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition) +#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition) + +#else // ENABLE_DLOG + +// If ENABLE_DLOG is off, we want to avoid emitting any references to +// |condition| (which may reference a variable defined only if NDEBUG +// is not defined). Contrast this with DCHECK et al., which has +// different behavior. + +#define DLOG_EAT_STREAM_PARAMETERS \ + true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL) + +#define DLOG_IS_ON(severity) false +#define DLOG_IF(severity, condition) DLOG_EAT_STREAM_PARAMETERS +#define DLOG_ASSERT(condition) DLOG_EAT_STREAM_PARAMETERS +#define DPLOG_IF(severity, condition) DLOG_EAT_STREAM_PARAMETERS +#define DVLOG_IF(verboselevel, condition) DLOG_EAT_STREAM_PARAMETERS +#define DVPLOG_IF(verboselevel, condition) DLOG_EAT_STREAM_PARAMETERS + +#endif // ENABLE_DLOG + +// DEBUG_MODE is for uses like +// if (DEBUG_MODE) foo.CheckThatFoo(); +// instead of +// #ifndef NDEBUG +// foo.CheckThatFoo(); +// #endif +// +// We tie its state to ENABLE_DLOG. +enum { DEBUG_MODE = ENABLE_DLOG }; + +#undef ENABLE_DLOG + +#define DLOG(severity) \ + LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity)) + +#if defined(OS_WIN) +#define DLOG_GETLASTERROR(severity) \ + LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), DLOG_IS_ON(severity)) +#define DLOG_GETLASTERROR_MODULE(severity, module) \ + LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module), \ + DLOG_IS_ON(severity)) +#elif defined(OS_POSIX) +#define DLOG_ERRNO(severity) \ + LAZY_STREAM(LOG_ERRNO_STREAM(severity), DLOG_IS_ON(severity)) +#endif + +#define DPLOG(severity) \ + LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity)) + +#define DVLOG(verboselevel) DLOG_IF(INFO, VLOG_IS_ON(verboselevel)) + +#define DVPLOG(verboselevel) DVPLOG_IF(verboselevel, VLOG_IS_ON(verboselevel)) + +// Definitions for DCHECK et al. + +#if ENABLE_DCHECK + +#if defined(NDEBUG) + +#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ + COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_ERROR_REPORT +const LogSeverity LOG_DCHECK = LOG_ERROR_REPORT; +BASE_EXPORT extern DcheckState g_dcheck_state; +#define DCHECK_IS_ON() \ + ((::logging::g_dcheck_state == \ + ::logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) && \ + LOG_IS_ON(DCHECK)) + +#else // defined(NDEBUG) + +// On a regular debug build, we want to have DCHECKs enabled. +#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ + COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL +const LogSeverity LOG_DCHECK = LOG_FATAL; +#define DCHECK_IS_ON() true + +#endif // defined(NDEBUG) + +#else // ENABLE_DCHECK + +// These are just dummy values since DCHECK_IS_ON() is always false in +// this case. +#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ + COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO +const LogSeverity LOG_DCHECK = LOG_INFO; +#define DCHECK_IS_ON() false + +#endif // ENABLE_DCHECK +#undef ENABLE_DCHECK + +// DCHECK et al. make sure to reference |condition| regardless of +// whether DCHECKs are enabled; this is so that we don't get unused +// variable warnings if the only use of a variable is in a DCHECK. +// This behavior is different from DLOG_IF et al. + +#define DCHECK(condition) \ + LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \ + << "Check failed: " #condition ". " + +#define DPCHECK(condition) \ + LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \ + << "Check failed: " #condition ". " + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use DCHECK_EQ et al below. +#define DCHECK_OP(name, op, val1, val2) \ + if (DCHECK_IS_ON()) \ + if (std::string* _result = \ + logging::Check##name##Impl((val1), (val2), \ + #val1 " " #op " " #val2)) \ + logging::LogMessage( \ + __FILE__, __LINE__, ::logging::LOG_DCHECK, \ + _result).stream() + +// Equality/Inequality checks - compare two values, and log a +// LOG_DCHECK message including the two values when the result is not +// as expected. The values must have operator<<(ostream, ...) +// defined. +// +// You may append to the error message like so: +// DCHECK_NE(1, 2) << ": The world must be ending!"; +// +// We are very careful to ensure that each argument is evaluated exactly +// once, and that anything which is legal to pass as a function argument is +// legal here. In particular, the arguments may be temporary expressions +// which will end up being destroyed at the end of the apparent statement, +// for example: +// DCHECK_EQ(string("abc")[1], 'b'); +// +// WARNING: These may not compile correctly if one of the arguments is a pointer +// and the other is NULL. To work around this, simply static_cast NULL to the +// type of the desired pointer. + +#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2) +#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2) +#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2) +#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2) +#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2) +#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2) + +#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD) +// TODO(port): fix once "enough" works +#define NOTREACHED() LOG(ERROR) << "NOTREACHED()" +#else +#define NOTREACHED() DCHECK(false) +#endif + +// Redefine the standard assert to use our nice log files +#undef assert +#define assert(x) DLOG_ASSERT(x) + +// This class more or less represents a particular log message. You +// create an instance of LogMessage and then stream stuff to it. +// When you finish streaming to it, ~LogMessage is called and the +// full message gets streamed to the appropriate destination. +// +// You shouldn't actually use LogMessage's constructor to log things, +// though. You should use the LOG() macro (and variants thereof) +// above. +class BASE_EXPORT LogMessage { + public: + LogMessage(const char* file, int line, LogSeverity severity, int ctr); + + // Two special constructors that generate reduced amounts of code at + // LOG call sites for common cases. + // + // Used for LOG(INFO): Implied are: + // severity = LOG_INFO, ctr = 0 + // + // Using this constructor instead of the more complex constructor above + // saves a couple of bytes per call site. + LogMessage(const char* file, int line); + + // Used for LOG(severity) where severity != INFO. Implied + // are: ctr = 0 + // + // Using this constructor instead of the more complex constructor above + // saves a couple of bytes per call site. + LogMessage(const char* file, int line, LogSeverity severity); + + // A special constructor used for check failures. Takes ownership + // of the given string. + // Implied severity = LOG_FATAL + LogMessage(const char* file, int line, std::string* result); + + // A special constructor used for check failures, with the option to + // specify severity. Takes ownership of the given string. + LogMessage(const char* file, int line, LogSeverity severity, + std::string* result); + + ~LogMessage(); + + std::ostream& stream() { return stream_; } + + private: + void Init(const char* file, int line); + + LogSeverity severity_; + std::ostringstream stream_; + size_t message_start_; // Offset of the start of the message (past prefix + // info). + // The file and line information passed in to the constructor. + const char* file_; + const int line_; + +#if defined(OS_WIN) + // Stores the current value of GetLastError in the constructor and restores + // it in the destructor by calling SetLastError. + // This is useful since the LogMessage class uses a lot of Win32 calls + // that will lose the value of GLE and the code that called the log function + // will have lost the thread error value when the log call returns. + class SaveLastError { + public: + SaveLastError(); + ~SaveLastError(); + + unsigned long get_error() const { return last_error_; } + + protected: + unsigned long last_error_; + }; + + SaveLastError last_error_; +#endif + + DISALLOW_COPY_AND_ASSIGN(LogMessage); +}; + +// A non-macro interface to the log facility; (useful +// when the logging level is not a compile-time constant). +inline void LogAtLevel(int const log_level, std::string const &msg) { + LogMessage(__FILE__, __LINE__, log_level).stream() << msg; +} + +// This class is used to explicitly ignore values in the conditional +// logging macros. This avoids compiler warnings like "value computed +// is not used" and "statement has no effect". +class LogMessageVoidify { + public: + LogMessageVoidify() { } + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) { } +}; + +#if defined(OS_WIN) +typedef unsigned long SystemErrorCode; +#elif defined(OS_POSIX) +typedef int SystemErrorCode; +#endif + +// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to +// pull in windows.h just for GetLastError() and DWORD. +BASE_EXPORT SystemErrorCode GetLastSystemErrorCode(); + +#if defined(OS_WIN) +// Appends a formatted system message of the GetLastError() type. +class BASE_EXPORT Win32ErrorLogMessage { + public: + Win32ErrorLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err, + const char* module); + + Win32ErrorLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err); + + // Appends the error message before destructing the encapsulated class. + ~Win32ErrorLogMessage(); + + std::ostream& stream() { return log_message_.stream(); } + + private: + SystemErrorCode err_; + // Optional name of the module defining the error. + const char* module_; + LogMessage log_message_; + + DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage); +}; +#elif defined(OS_POSIX) +// Appends a formatted system message of the errno type +class BASE_EXPORT ErrnoLogMessage { + public: + ErrnoLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err); + + // Appends the error message before destructing the encapsulated class. + ~ErrnoLogMessage(); + + std::ostream& stream() { return log_message_.stream(); } + + private: + SystemErrorCode err_; + LogMessage log_message_; + + DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage); +}; +#endif // OS_WIN + +// Closes the log file explicitly if open. +// NOTE: Since the log file is opened as necessary by the action of logging +// statements, there's no guarantee that it will stay closed +// after this call. +BASE_EXPORT void CloseLogFile(); + +// Async signal safe logging mechanism. +BASE_EXPORT void RawLog(int level, const char* message); + +#define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message) + +#define RAW_CHECK(condition) \ + do { \ + if (!(condition)) \ + logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n"); \ + } while (0) + +} // namespace logging + +// These functions are provided as a convenience for logging, which is where we +// use streams (it is against Google style to use streams in other places). It +// is designed to allow you to emit non-ASCII Unicode strings to the log file, +// which is normally ASCII. It is relatively slow, so try not to use it for +// common cases. Non-ASCII characters will be converted to UTF-8 by these +// operators. +BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr); +inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) { + return out << wstr.c_str(); +} + +// The NOTIMPLEMENTED() macro annotates codepaths which have +// not been implemented yet. +// +// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY: +// 0 -- Do nothing (stripped by compiler) +// 1 -- Warn at compile time +// 2 -- Fail at compile time +// 3 -- Fail at runtime (DCHECK) +// 4 -- [default] LOG(ERROR) at runtime +// 5 -- LOG(ERROR) at runtime, only once per call-site + +#ifndef NOTIMPLEMENTED_POLICY +// Select default policy: LOG(ERROR) +#define NOTIMPLEMENTED_POLICY 4 +#endif + +#if defined(COMPILER_GCC) +// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name +// of the current function in the NOTIMPLEMENTED message. +#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__ +#else +#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED" +#endif + +#if NOTIMPLEMENTED_POLICY == 0 +#define NOTIMPLEMENTED() ; +#elif NOTIMPLEMENTED_POLICY == 1 +// TODO, figure out how to generate a warning +#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED) +#elif NOTIMPLEMENTED_POLICY == 2 +#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED) +#elif NOTIMPLEMENTED_POLICY == 3 +#define NOTIMPLEMENTED() NOTREACHED() +#elif NOTIMPLEMENTED_POLICY == 4 +#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG +#elif NOTIMPLEMENTED_POLICY == 5 +#define NOTIMPLEMENTED() do {\ + static int count = 0;\ + LOG_IF(ERROR, 0 == count++) << NOTIMPLEMENTED_MSG;\ +} while(0) +#endif + +namespace base { + +class StringPiece; + +// Allows StringPiece to be logged. +BASE_EXPORT std::ostream& operator<<(std::ostream& o, const StringPiece& piece); + +} // namespace base + +#endif // BASE_LOGGING_H_ diff --git a/base/memory/ref_counted.cc b/base/memory/ref_counted.cc new file mode 100644 index 000000000000..31ad5098cd0f --- /dev/null +++ b/base/memory/ref_counted.cc @@ -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 diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h new file mode 100644 index 000000000000..439fda44d1ad --- /dev/null +++ b/base/memory/ref_counted.h @@ -0,0 +1,299 @@ +// 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_REF_COUNTED_H_ +#define BASE_MEMORY_REF_COUNTED_H_ +#pragma once + +#include "base/atomic_ref_count.h" +#include "base/base_export.h" +#include "base/threading/thread_collision_warner.h" + +namespace base { + +namespace subtle { + +class BASE_EXPORT RefCountedBase { + public: + static bool ImplementsThreadSafeReferenceCounting() { return false; } + + 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: + static bool ImplementsThreadSafeReferenceCounting() { return true; } + + 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() { } + ~RefCounted() { } + + void AddRef() const { + subtle::RefCountedBase::AddRef(); + } + + void Release() const { + if (subtle::RefCountedBase::Release()) { + delete static_cast<const T*>(this); + } + } + + 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() { } + ~RefCountedThreadSafe() { } + + void AddRef() const { + subtle::RefCountedThreadSafeBase::AddRef(); + } + + void Release() const { + if (subtle::RefCountedThreadSafeBase::Release()) { + Traits::Destruct(static_cast<const T*>(this)); + } + } + + private: + friend struct DefaultRefCountedThreadSafeTraits<T>; + static void DeleteInternal(const T* x) { delete x; } + + DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe); +}; + +// +// A wrapper for some piece of data so we can place other things in +// scoped_refptrs<>. +// +template<typename T> +class RefCountedData : public base::RefCounted< base::RefCountedData<T> > { + public: + RefCountedData() : data() {} + RefCountedData(const T& in_value) : data(in_value) {} + + T data; +}; + +} // 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: + 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 { return ptr_; } + + // 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. + T* release() { + T* retVal = ptr_; + ptr_ = NULL; + return retVal; + } + + scoped_refptr<T>& operator=(T* p) { + // AddRef first so that self assignment should work + if (p) + p->AddRef(); + if (ptr_ ) + ptr_ ->Release(); + ptr_ = p; + 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_ diff --git a/base/memory/ref_counted_memory.cc b/base/memory/ref_counted_memory.cc new file mode 100644 index 000000000000..7e034f91af62 --- /dev/null +++ b/base/memory/ref_counted_memory.cc @@ -0,0 +1,72 @@ +// 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_memory.h" + +#include "base/logging.h" + +RefCountedMemory::RefCountedMemory() { +} + +RefCountedMemory::~RefCountedMemory() { +} + +const unsigned char* RefCountedStaticMemory::front() const { + return data_; +} + +size_t RefCountedStaticMemory::size() const { + return length_; +} + +RefCountedBytes::RefCountedBytes() { +} + +RefCountedBytes::RefCountedBytes(const std::vector<unsigned char>& initializer) + : data_(initializer) { +} + +RefCountedBytes* RefCountedBytes::TakeVector( + std::vector<unsigned char>* to_destroy) { + RefCountedBytes* bytes = new RefCountedBytes; + bytes->data_.swap(*to_destroy); + return bytes; +} + +const unsigned char* RefCountedBytes::front() const { + // STL will assert if we do front() on an empty vector, but calling code + // expects a NULL. + return size() ? &data_.front() : NULL; +} + +size_t RefCountedBytes::size() const { + return data_.size(); +} + +RefCountedBytes::~RefCountedBytes() { +} + +namespace base { + +RefCountedString::RefCountedString() {} + +RefCountedString::~RefCountedString() {} + +// static +RefCountedString* RefCountedString::TakeString(std::string* to_destroy) { + RefCountedString* self = new RefCountedString; + to_destroy->swap(self->data_); + return self; +} + +const unsigned char* RefCountedString::front() const { + return data_.empty() ? NULL : + reinterpret_cast<const unsigned char*>(data_.data()); +} + +size_t RefCountedString::size() const { + return data_.size(); +} + +} // namespace base diff --git a/base/memory/ref_counted_memory.h b/base/memory/ref_counted_memory.h new file mode 100644 index 000000000000..7b55d145ec20 --- /dev/null +++ b/base/memory/ref_counted_memory.h @@ -0,0 +1,119 @@ +// 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_REF_COUNTED_MEMORY_H_ +#define BASE_MEMORY_REF_COUNTED_MEMORY_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/base_export.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" + +// TODO(erg): The contents of this file should be in a namespace. This would +// require touching >100 files in chrome/ though. + +// A generic interface to memory. This object is reference counted because one +// of its two subclasses own the data they carry, and we need to have +// heterogeneous containers of these two types of memory. +class BASE_EXPORT RefCountedMemory + : public base::RefCountedThreadSafe<RefCountedMemory> { + public: + // Retrieves a pointer to the beginning of the data we point to. If the data + // is empty, this will return NULL. + virtual const unsigned char* front() const = 0; + + // Size of the memory pointed to. + virtual size_t size() const = 0; + + protected: + friend class base::RefCountedThreadSafe<RefCountedMemory>; + RefCountedMemory(); + virtual ~RefCountedMemory(); +}; + +// An implementation of RefCountedMemory, where the ref counting does not +// matter. +class BASE_EXPORT RefCountedStaticMemory : public RefCountedMemory { + public: + RefCountedStaticMemory() + : data_(NULL), length_(0) {} + RefCountedStaticMemory(const unsigned char* data, size_t length) + : data_(length ? data : NULL), length_(length) {} + + // Overridden from RefCountedMemory: + virtual const unsigned char* front() const OVERRIDE; + virtual size_t size() const OVERRIDE; + + private: + const unsigned char* data_; + size_t length_; + + DISALLOW_COPY_AND_ASSIGN(RefCountedStaticMemory); +}; + +// An implementation of RefCountedMemory, where we own our the data in a +// vector. +class BASE_EXPORT RefCountedBytes : public RefCountedMemory { + public: + RefCountedBytes(); + + // Constructs a RefCountedBytes object by _copying_ from |initializer|. + RefCountedBytes(const std::vector<unsigned char>& initializer); + + // Constructs a RefCountedBytes object by performing a swap. (To non + // destructively build a RefCountedBytes, use the constructor that takes a + // vector.) + static RefCountedBytes* TakeVector(std::vector<unsigned char>* to_destroy); + + // Overridden from RefCountedMemory: + virtual const unsigned char* front() const OVERRIDE; + virtual size_t size() const OVERRIDE; + + const std::vector<unsigned char>& data() const { return data_; } + std::vector<unsigned char>& data() { return data_; } + + private: + friend class base::RefCountedThreadSafe<RefCountedBytes>; + virtual ~RefCountedBytes(); + + std::vector<unsigned char> data_; + + DISALLOW_COPY_AND_ASSIGN(RefCountedBytes); +}; + +namespace base { + +// An implementation of RefCountedMemory, where the bytes are stored in an STL +// string. Use this if your data naturally arrives in that format. +class BASE_EXPORT RefCountedString : public RefCountedMemory { + public: + RefCountedString(); + + // Constructs a RefCountedString object by performing a swap. (To non + // destructively build a RefCountedString, use the default constructor and + // copy into object->data()). + static RefCountedString* TakeString(std::string* to_destroy); + + // Overridden from RefCountedMemory: + virtual const unsigned char* front() const OVERRIDE; + virtual size_t size() const OVERRIDE; + + const std::string& data() const { return data_; } + std::string& data() { return data_; } + + private: + friend class base::RefCountedThreadSafe<RefCountedString>; + virtual ~RefCountedString(); + + std::string data_; + + DISALLOW_COPY_AND_ASSIGN(RefCountedString); +}; + +} // namespace base + +#endif // BASE_MEMORY_REF_COUNTED_MEMORY_H_ diff --git a/base/memory/ref_counted_memory_unittest.cc b/base/memory/ref_counted_memory_unittest.cc new file mode 100644 index 000000000000..19360400c14a --- /dev/null +++ b/base/memory/ref_counted_memory_unittest.cc @@ -0,0 +1,45 @@ +// 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_memory.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { + +TEST(RefCountedMemoryUnitTest, RefCountedStaticMemory) { + scoped_refptr<RefCountedMemory> mem = new RefCountedStaticMemory( + reinterpret_cast<const uint8*>("static mem00"), 10); + + EXPECT_EQ(10U, mem->size()); + EXPECT_EQ("static mem", + std::string(reinterpret_cast<const char*>(mem->front()), + mem->size())); +} + +TEST(RefCountedMemoryUnitTest, RefCountedBytes) { + std::vector<uint8> data; + data.push_back(45); + data.push_back(99); + scoped_refptr<RefCountedMemory> mem = RefCountedBytes::TakeVector(&data); + + EXPECT_EQ(0U, data.size()); + + EXPECT_EQ(2U, mem->size()); + EXPECT_EQ(45U, mem->front()[0]); + EXPECT_EQ(99U, mem->front()[1]); +} + +TEST(RefCountedMemoryUnitTest, RefCountedString) { + std::string s("destroy me"); + scoped_refptr<RefCountedMemory> mem = RefCountedString::TakeString(&s); + + EXPECT_EQ(0U, s.size()); + + EXPECT_EQ(10U, mem->size()); + EXPECT_EQ('d', mem->front()[0]); + EXPECT_EQ('e', mem->front()[1]); +} + +} // namespace base diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc new file mode 100644 index 000000000000..dcc292f00ddf --- /dev/null +++ b/base/memory/ref_counted_unittest.cc @@ -0,0 +1,36 @@ +// 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 "testing/gtest/include/gtest/gtest.h" + +namespace { + +class SelfAssign : public base::RefCounted<SelfAssign> { + friend class base::RefCounted<SelfAssign>; + + ~SelfAssign() {} +}; + +class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> { + public: + CheckDerivedMemberAccess() { + // This shouldn't compile if we don't have access to the member variable. + SelfAssign** pptr = &ptr_; + EXPECT_EQ(*pptr, ptr_); + } +}; + +} // end namespace + +TEST(RefCountedUnitTest, TestSelfAssignment) { + SelfAssign* p = new SelfAssign; + scoped_refptr<SelfAssign> var(p); + var = var; + EXPECT_EQ(var.get(), p); +} + +TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) { + CheckDerivedMemberAccess check; +} diff --git a/base/pickle.cc b/base/pickle.cc new file mode 100644 index 000000000000..f42f249bb274 --- /dev/null +++ b/base/pickle.cc @@ -0,0 +1,449 @@ +// 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/pickle.h" + +#include <stdlib.h> + +#include <algorithm> // for max() +#include <limits> + +//------------------------------------------------------------------------------ + +// static +const int Pickle::kPayloadUnit = 64; + +// We mark a read only pickle with a special capacity_. +static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max(); + +// Payload is uint32 aligned. + +Pickle::Pickle() + : header_(NULL), + header_size_(sizeof(Header)), + capacity_(0), + variable_buffer_offset_(0) { + Resize(kPayloadUnit); + header_->payload_size = 0; +} + +Pickle::Pickle(int header_size) + : header_(NULL), + header_size_(AlignInt(header_size, sizeof(uint32))), + capacity_(0), + variable_buffer_offset_(0) { + DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header)); + DCHECK_LE(header_size, kPayloadUnit); + Resize(kPayloadUnit); + header_->payload_size = 0; +} + +Pickle::Pickle(const char* data, int data_len) + : header_(reinterpret_cast<Header*>(const_cast<char*>(data))), + header_size_(0), + capacity_(kCapacityReadOnly), + variable_buffer_offset_(0) +{ + + if (data_len >= static_cast<int>(sizeof(Header))) + { + header_size_ = data_len - header_->payload_size; + } + + if (header_size_ > static_cast<unsigned int>(data_len)) + { + header_size_ = 0; + } + + + if (header_size_ != AlignInt(header_size_, sizeof(uint32))) + { + header_size_ = 0; + } + + + // If there is anything wrong with the data, we're not going to use it. + if (!header_size_) + header_ = NULL; +} + +Pickle::Pickle(const Pickle& other) + : header_(NULL), + header_size_(other.header_size_), + capacity_(0), + variable_buffer_offset_(other.variable_buffer_offset_) { + size_t payload_size = header_size_ + other.header_->payload_size; + bool resized = Resize(payload_size); + CHECK(resized); // Realloc failed. + memcpy(header_, other.header_, payload_size); +} + +Pickle::~Pickle() { + if (capacity_ != kCapacityReadOnly) + free(header_); +} + +Pickle& Pickle::operator=(const Pickle& other) { + if (this == &other) { + NOTREACHED(); + return *this; + } + if (capacity_ == kCapacityReadOnly) { + header_ = NULL; + capacity_ = 0; + } + if (header_size_ != other.header_size_) { + free(header_); + header_ = NULL; + header_size_ = other.header_size_; + } + bool resized = Resize(other.header_size_ + other.header_->payload_size); + CHECK(resized); // Realloc failed. + memcpy(header_, other.header_, + other.header_size_ + other.header_->payload_size); + variable_buffer_offset_ = other.variable_buffer_offset_; + return *this; +} + +bool Pickle::ReadBool(void** iter, bool* result) const { + DCHECK(iter); + + int tmp; + if (!ReadInt(iter, &tmp)) + return false; + DCHECK(0 == tmp || 1 == tmp); + *result = tmp ? true : false; + return true; +} + +bool Pickle::ReadInt(void** iter, int* result) const { + DCHECK(iter); + if (!*iter) + *iter = const_cast<char*>(payload()); + + if (!IteratorHasRoomFor(*iter, sizeof(*result))) + return false; + + // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not + // dependent on alignment. + // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result)); + *result = *reinterpret_cast<int*>(*iter); + + UpdateIter(iter, sizeof(*result)); + return true; +} + +bool Pickle::ReadLong(void** iter, long* result) const { + DCHECK(iter); + if (!*iter) + *iter = const_cast<char*>(payload()); + + if (!IteratorHasRoomFor(*iter, sizeof(*result))) + return false; + + // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not + // dependent on alignment. + memcpy(result, *iter, sizeof(*result)); + + UpdateIter(iter, sizeof(*result)); + return true; +} + +bool Pickle::ReadSize(void** iter, size_t* result) const { + DCHECK(iter); + if (!*iter) + *iter = const_cast<char*>(payload()); + + if (!IteratorHasRoomFor(*iter, sizeof(*result))) + return false; + + // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not + // dependent on alignment. + // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result)); + *result = *reinterpret_cast<size_t*>(*iter); + + UpdateIter(iter, sizeof(*result)); + return true; +} + +bool Pickle::ReadUInt16(void** iter, uint16* result) const { + DCHECK(iter); + if (!*iter) + *iter = const_cast<char*>(payload()); + + if (!IteratorHasRoomFor(*iter, sizeof(*result))) + return false; + + memcpy(result, *iter, sizeof(*result)); + + UpdateIter(iter, sizeof(*result)); + return true; +} + +bool Pickle::ReadUInt32(void** iter, uint32* result) const { + DCHECK(iter); + if (!*iter) + *iter = const_cast<char*>(payload()); + + if (!IteratorHasRoomFor(*iter, sizeof(*result))) + return false; + + memcpy(result, *iter, sizeof(*result)); + + UpdateIter(iter, sizeof(*result)); + return true; +} + +bool Pickle::ReadInt64(void** iter, int64* result) const { + DCHECK(iter); + if (!*iter) + *iter = const_cast<char*>(payload()); + + if (!IteratorHasRoomFor(*iter, sizeof(*result))) + return false; + + memcpy(result, *iter, sizeof(*result)); + + UpdateIter(iter, sizeof(*result)); + return true; +} + +bool Pickle::ReadUInt64(void** iter, uint64* result) const { + DCHECK(iter); + if (!*iter) + *iter = const_cast<char*>(payload()); + + if (!IteratorHasRoomFor(*iter, sizeof(*result))) + return false; + + memcpy(result, *iter, sizeof(*result)); + + UpdateIter(iter, sizeof(*result)); + return true; +} + + +bool Pickle::ReadString(void** iter, std::string* result) const { + DCHECK(iter); + + int len; + if (!ReadLength(iter, &len)) + return false; + if (!IteratorHasRoomFor(*iter, len)) + return false; + + char* chars = reinterpret_cast<char*>(*iter); + result->assign(chars, len); + + UpdateIter(iter, len); + return true; +} + +/* +bool Pickle::ReadWString(void** iter, std::wstring* result) const { + DCHECK(iter); + + int len; + if (!ReadLength(iter, &len)) + return false; + // Avoid integer overflow. + if (len > INT_MAX / static_cast<int>(sizeof(wchar_t))) + return false; + if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t))) + return false; + + wchar_t* chars = reinterpret_cast<wchar_t*>(*iter); + result->assign(chars, len); + + UpdateIter(iter, len * sizeof(wchar_t)); + return true; +} + +bool Pickle::ReadString16(void** iter, string16* result) const { + DCHECK(iter); + + int len; + if (!ReadLength(iter, &len)) + return false; + if (!IteratorHasRoomFor(*iter, len * sizeof(char16))) + return false; + + char16* chars = reinterpret_cast<char16*>(*iter); + result->assign(chars, len); + + UpdateIter(iter, len * sizeof(char16)); + return true; +} +*/ + +bool Pickle::ReadData(void** iter, const char** data, int* length) const { + DCHECK(iter); + DCHECK(data); + DCHECK(length); + *length = 0; + *data = 0; + + if (!ReadLength(iter, length)) + return false; + + return ReadBytes(iter, data, *length); +} + +bool Pickle::ReadBytes(void** iter, const char** data, int length) const { + DCHECK(iter); + DCHECK(data); + *data = 0; + if (!*iter) + *iter = const_cast<char*>(payload()); + + if (!IteratorHasRoomFor(*iter, length)) + return false; + + *data = reinterpret_cast<const char*>(*iter); + + UpdateIter(iter, length); + return true; +} + +bool Pickle::ReadLength(void** iter, int* result) const { + if (!ReadInt(iter, result)) + return false; + return ((*result) >= 0); +} + + +bool Pickle::WriteString(const std::string& value) { + if (!WriteInt(static_cast<int>(value.size()))) + return false; + + return WriteBytes(value.data(), static_cast<int>(value.size())); +} + +/* +bool Pickle::WriteWString(const std::wstring& value) { + if (!WriteInt(static_cast<int>(value.size()))) + return false; + + return WriteBytes(value.data(), + static_cast<int>(value.size() * sizeof(wchar_t))); +} + +bool Pickle::WriteString16(const string16& value) { + if (!WriteInt(static_cast<int>(value.size()))) + return false; + + return WriteBytes(value.data(), + static_cast<int>(value.size()) * sizeof(char16)); +} +*/ + +bool Pickle::WriteData(const char* data, int length) { + return length >= 0 && WriteInt(length) && WriteBytes(data, length); +} + +bool Pickle::WriteBytes(const void* data, int data_len) { + DCHECK_NE(kCapacityReadOnly, capacity_) << "oops: pickle is readonly"; + + char* dest = BeginWrite(data_len); + if (!dest) + return false; + + memcpy(dest, data, data_len); + + EndWrite(dest, data_len); + return true; +} + +char* Pickle::BeginWriteData(int length) { + DCHECK_EQ(variable_buffer_offset_, 0U) << + "There can only be one variable buffer in a Pickle"; + + if (length < 0 || !WriteInt(length)) + return NULL; + + char *data_ptr = BeginWrite(length); + if (!data_ptr) + return NULL; + + variable_buffer_offset_ = + data_ptr - reinterpret_cast<char*>(header_) - sizeof(int); + + // EndWrite doesn't necessarily have to be called after the write operation, + // so we call it here to pad out what the caller will eventually write. + EndWrite(data_ptr, length); + return data_ptr; +} + +void Pickle::TrimWriteData(int new_length) { + DCHECK_NE(variable_buffer_offset_, 0U); + + // Fetch the the variable buffer size + int* cur_length = reinterpret_cast<int*>( + reinterpret_cast<char*>(header_) + variable_buffer_offset_); + + if (new_length < 0 || new_length > *cur_length) { + NOTREACHED() << "Invalid length in TrimWriteData."; + return; + } + + // Update the payload size and variable buffer size + header_->payload_size -= (*cur_length - new_length); + *cur_length = new_length; +} + +char* Pickle::BeginWrite(size_t length) { + // write at a uint32-aligned offset from the beginning of the header + size_t offset = AlignInt(header_->payload_size, sizeof(uint32)); + + size_t new_size = offset + length; + size_t needed_size = header_size_ + new_size; + if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) + return NULL; + +#ifdef ARCH_CPU_64_BITS + DCHECK_LE(length, std::numeric_limits<uint32>::max()); +#endif + + header_->payload_size = static_cast<uint32>(new_size); + return payload() + offset; +} + +void Pickle::EndWrite(char* dest, int length) { + // Zero-pad to keep tools like purify from complaining about uninitialized + // memory. + if (length % sizeof(uint32)) + memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32))); +} + +bool Pickle::Resize(size_t new_capacity) { + new_capacity = AlignInt(new_capacity, kPayloadUnit); + + CHECK_NE(capacity_, kCapacityReadOnly); + void* p = realloc(header_, new_capacity); + if (!p) + return false; + + header_ = reinterpret_cast<Header*>(p); + capacity_ = new_capacity; + return true; +} + +// static +const char* Pickle::FindNext(size_t header_size, + const char* start, + const char* end) { + DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32))); + DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit)); + + if (static_cast<size_t>(end - start) < sizeof(Header)) + return NULL; + + const Header* hdr = reinterpret_cast<const Header*>(start); + const char* payload_base = start + header_size; + const char* payload_end = payload_base + hdr->payload_size; + if (payload_end < payload_base) + return NULL; + + return (payload_end > end) ? NULL : payload_end; +} diff --git a/base/pickle.h b/base/pickle.h new file mode 100644 index 000000000000..e7ececff42cd --- /dev/null +++ b/base/pickle.h @@ -0,0 +1,249 @@ +// 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_PICKLE_H__ +#define BASE_PICKLE_H__ +#pragma once + +#include <string> +#include <iostream> + +#include "base/base_export.h" +#include "base/basictypes.h" +//#include "base/gtest_prod_util.h" // jaehwa +//#include "base/logging.h" // jaehwa +#include "log.h" // jaehwa +//#include "base/string16.h" // jaehwa + +// This class provides facilities for basic binary value packing and unpacking. +// +// The Pickle class supports appending primitive values (ints, strings, etc.) +// to a pickle instance. The Pickle instance grows its internal memory buffer +// dynamically to hold the sequence of primitive values. The internal memory +// buffer is exposed as the "data" of the Pickle. This "data" can be passed +// to a Pickle object to initialize it for reading. +// +// When reading from a Pickle object, it is important for the consumer to know +// what value types to read and in what order to read them as the Pickle does +// not keep track of the type of data written to it. +// +// The Pickle's data has a header which contains the size of the Pickle's +// payload. It can optionally support additional space in the header. That +// space is controlled by the header_size parameter passed to the Pickle +// constructor. +// +class BASE_EXPORT Pickle { + public: + // Initialize a Pickle object using the default header size. + Pickle(); + + // Initialize a Pickle object with the specified header size in bytes, which + // must be greater-than-or-equal-to sizeof(Pickle::Header). The header size + // will be rounded up to ensure that the header size is 32bit-aligned. + explicit Pickle(int header_size); + + // Initializes a Pickle from a const block of data. The data is not copied; + // instead the data is merely referenced by this Pickle. Only const methods + // should be used on the Pickle when initialized this way. The header + // padding size is deduced from the data length. + Pickle(const char* data, int data_len); + + // Initializes a Pickle as a deep copy of another Pickle. + Pickle(const Pickle& other); + + virtual ~Pickle(); + + // Performs a deep copy. + Pickle& operator=(const Pickle& other); + + // Returns the size of the Pickle's data. + size_t size() const { return header_size_ + header_->payload_size; } + + // Returns the data for this Pickle. + const void* data() const { return header_; } + + // Methods for reading the payload of the Pickle. To read from the start of + // the Pickle, initialize *iter to NULL. If successful, these methods return + // true. Otherwise, false is returned to indicate that the result could not + // be extracted. + bool ReadBool(void** iter, bool* result) const; + bool ReadInt(void** iter, int* result) const; + bool ReadLong(void** iter, long* result) const; + bool ReadSize(void** iter, size_t* result) const; + bool ReadUInt16(void** iter, uint16* result) const; + bool ReadUInt32(void** iter, uint32* result) const; + bool ReadInt64(void** iter, int64* result) const; + bool ReadUInt64(void** iter, uint64* result) const; + bool ReadString(void** iter, std::string* result) const; +// bool ReadWString(void** iter, std::wstring* result) const; +// bool ReadString16(void** iter, string16* result) const; + bool ReadData(void** iter, const char** data, int* length) const; + bool ReadBytes(void** iter, const char** data, int length) const; + + // Safer version of ReadInt() checks for the result not being negative. + // Use it for reading the object sizes. + bool ReadLength(void** iter, int* result) const; + + // Methods for adding to the payload of the Pickle. These values are + // appended to the end of the Pickle's payload. When reading values from a + // Pickle, it is important to read them in the order in which they were added + // to the Pickle. + bool WriteBool(bool value) { + return WriteInt(value ? 1 : 0); + } + bool WriteInt(int value) { + return WriteBytes(&value, sizeof(value)); + } + bool WriteLong(long value) { + return WriteBytes(&value, sizeof(value)); + } + bool WriteSize(size_t value) { + return WriteBytes(&value, sizeof(value)); + } + bool WriteUInt16(uint16 value) { + return WriteBytes(&value, sizeof(value)); + } + bool WriteUInt32(uint32 value) { + return WriteBytes(&value, sizeof(value)); + } + bool WriteInt64(int64 value) { + return WriteBytes(&value, sizeof(value)); + } + bool WriteUInt64(uint64 value) { + return WriteBytes(&value, sizeof(value)); + } + bool WriteString(const std::string& value); +// bool WriteWString(const std::wstring& value); +// bool WriteString16(const string16& value); + bool WriteData(const char* data, int length); + bool WriteBytes(const void* data, int data_len); + + // Same as WriteData, but allows the caller to write directly into the + // Pickle. This saves a copy in cases where the data is not already + // available in a buffer. The caller should take care to not write more + // than the length it declares it will. Use ReadData to get the data. + // Returns NULL on failure. + // + // The returned pointer will only be valid until the next write operation + // on this Pickle. + char* BeginWriteData(int length); + + // For Pickles which contain variable length buffers (e.g. those created + // with BeginWriteData), the Pickle can + // be 'trimmed' if the amount of data required is less than originally + // requested. For example, you may have created a buffer with 10K of data, + // but decided to only fill 10 bytes of that data. Use this function + // to trim the buffer so that we don't send 9990 bytes of unused data. + // You cannot increase the size of the variable buffer; only shrink it. + // This function assumes that the length of the variable buffer has + // not been changed. + void TrimWriteData(int length); + + // Payload follows after allocation of Header (header size is customizable). + struct Header { + uint32 payload_size; // Specifies the size of the payload. + }; + + // Returns the header, cast to a user-specified type T. The type T must be a + // subclass of Header and its size must correspond to the header_size passed + // to the Pickle constructor. + template <class T> + T* headerT() { + DCHECK_EQ(header_size_, sizeof(T)); + return static_cast<T*>(header_); + } + template <class T> + const T* headerT() const { + DCHECK_EQ(header_size_, sizeof(T)); + return static_cast<const T*>(header_); + } + + // Returns true if the given iterator could point to data with the given + // length. If there is no room for the given data before the end of the + // payload, returns false. + bool IteratorHasRoomFor(const void* iter, int len) const { + if ((len < 0) || (iter < header_) || iter > end_of_payload()) + return false; + const char* end_of_region = reinterpret_cast<const char*>(iter) + len; + // Watch out for overflow in pointer calculation, which wraps. + return (iter <= end_of_region) && (end_of_region <= end_of_payload()); + } + + protected: + size_t payload_size() const { return header_->payload_size; } + + char* payload() { + return reinterpret_cast<char*>(header_) + header_size_; + } + const char* payload() const { + return reinterpret_cast<const char*>(header_) + header_size_; + } + + // Returns the address of the byte immediately following the currently valid + // header + payload. + char* end_of_payload() { + // We must have a valid header_. + return payload() + payload_size(); + } + const char* end_of_payload() const { + // This object may be invalid. + return header_ ? payload() + payload_size() : NULL; + } + + size_t capacity() const { + return capacity_; + } + + // Resizes the buffer for use when writing the specified amount of data. The + // location that the data should be written at is returned, or NULL if there + // was an error. Call EndWrite with the returned offset and the given length + // to pad out for the next write. + char* BeginWrite(size_t length); + + // Completes the write operation by padding the data with NULL bytes until it + // is padded. Should be paired with BeginWrite, but it does not necessarily + // have to be called after the data is written. + void EndWrite(char* dest, int length); + + // Resize the capacity, note that the input value should include the size of + // the header: new_capacity = sizeof(Header) + desired_payload_capacity. + // A realloc() failure will cause a Resize failure... and caller should check + // the return result for true (i.e., successful resizing). + bool Resize(size_t new_capacity); + + // Aligns 'i' by rounding it up to the next multiple of 'alignment' + static size_t AlignInt(size_t i, int alignment) { + return i + (alignment - (i % alignment)) % alignment; + } + + // Moves the iterator by the given number of bytes, making sure it is aligned. + // Pointer (iterator) is NOT aligned, but the change in the pointer + // is guaranteed to be a multiple of sizeof(uint32). + static void UpdateIter(void** iter, int bytes) { + *iter = static_cast<char*>(*iter) + AlignInt(bytes, sizeof(uint32)); + } + + // Find the end of the pickled data that starts at range_start. Returns NULL + // if the entire Pickle is not found in the given data range. + static const char* FindNext(size_t header_size, + const char* range_start, + const char* range_end); + + // The allocation granularity of the payload. + static const int kPayloadUnit; + + private: + Header* header_; + size_t header_size_; // Supports extra data between header and payload. + // Allocation size of payload (or -1 if allocation is const). + size_t capacity_; + size_t variable_buffer_offset_; // IF non-zero, then offset to a buffer. + +// FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize); +// FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext); +// FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader); +// FRIEND_TEST_ALL_PREFIXES(PickleTest, IteratorHasRoom); +}; + +#endif // BASE_PICKLE_H__ diff --git a/base/platform_file_posix.cc b/base/platform_file_posix.cc new file mode 100644 index 000000000000..fed36966a97c --- /dev/null +++ b/base/platform_file_posix.cc @@ -0,0 +1,200 @@ +// 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" + +#include <fcntl.h> +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "base/eintr_wrapper.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "base/utf_string_conversions.h" + +#if defined(OS_ANDROID) +#include "base/os_compat_android.h" +#endif + +namespace base { + +#if defined(OS_OPENBSD) || defined(OS_FREEBSD) || \ + (defined(OS_MACOSX) && \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) +typedef struct stat stat_wrapper_t; +static int CallFstat(int fd, stat_wrapper_t *sb) { + return fstat(fd, sb); +} +#else +typedef struct stat64 stat_wrapper_t; +static int CallFstat(int fd, stat_wrapper_t *sb) { + return fstat64(fd, sb); +} +#endif + +// TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here? +PlatformFile CreatePlatformFile(const FilePath& name, int flags, + bool* created, PlatformFileError* error_code) { + int open_flags = 0; + if (flags & PLATFORM_FILE_CREATE) + open_flags = O_CREAT | O_EXCL; + + if (created) + *created = false; + + if (flags & PLATFORM_FILE_CREATE_ALWAYS) { + DCHECK(!open_flags); + open_flags = O_CREAT | O_TRUNC; + } + + if (flags & PLATFORM_FILE_OPEN_TRUNCATED) { + DCHECK(!open_flags); + DCHECK(flags & PLATFORM_FILE_WRITE); + open_flags = O_TRUNC; + } + + if (!open_flags && !(flags & PLATFORM_FILE_OPEN) && + !(flags & PLATFORM_FILE_OPEN_ALWAYS)) { + NOTREACHED(); + errno = EOPNOTSUPP; + if (error_code) + *error_code = PLATFORM_FILE_ERROR_FAILED; + return kInvalidPlatformFileValue; + } + + if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) { + open_flags |= O_RDWR; + } else if (flags & PLATFORM_FILE_WRITE) { + open_flags |= O_WRONLY; + } else if (!(flags & PLATFORM_FILE_READ) && + !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) && + !(flags & PLATFORM_FILE_OPEN_ALWAYS)) { + NOTREACHED(); + } + + COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero); + + int descriptor = + HANDLE_EINTR(open(name.value().c_str(), open_flags, S_IRUSR | S_IWUSR)); + + if (flags & PLATFORM_FILE_OPEN_ALWAYS) { + if (descriptor <= 0) { + open_flags |= O_CREAT; + if (flags & PLATFORM_FILE_EXCLUSIVE_READ || + flags & PLATFORM_FILE_EXCLUSIVE_WRITE) { + open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW + } + descriptor = HANDLE_EINTR( + open(name.value().c_str(), open_flags, S_IRUSR | S_IWUSR)); + if (created && descriptor > 0) + *created = true; + } + } + + if (created && (descriptor > 0) && + (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE))) + *created = true; + + if ((descriptor > 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) { + unlink(name.value().c_str()); + } + + if (error_code) { + if (descriptor >= 0) + *error_code = PLATFORM_FILE_OK; + else { + switch (errno) { + case EACCES: + case EISDIR: + case EROFS: + case EPERM: + *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED; + break; + case ETXTBSY: + *error_code = PLATFORM_FILE_ERROR_IN_USE; + break; + case EEXIST: + *error_code = PLATFORM_FILE_ERROR_EXISTS; + break; + case ENOENT: + *error_code = PLATFORM_FILE_ERROR_NOT_FOUND; + break; + case EMFILE: + *error_code = PLATFORM_FILE_ERROR_TOO_MANY_OPENED; + break; + case ENOMEM: + *error_code = PLATFORM_FILE_ERROR_NO_MEMORY; + break; + case ENOSPC: + *error_code = PLATFORM_FILE_ERROR_NO_SPACE; + break; + case ENOTDIR: + *error_code = PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; + break; + default: + *error_code = PLATFORM_FILE_ERROR_FAILED; + } + } + } + + return descriptor; +} + +bool ClosePlatformFile(PlatformFile file) { + return !HANDLE_EINTR(close(file)); +} + +int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) { + if (file < 0) + return -1; + + return HANDLE_EINTR(pread(file, data, size, offset)); +} + +int WritePlatformFile(PlatformFile file, int64 offset, + const char* data, int size) { + if (file < 0) + return -1; + + return HANDLE_EINTR(pwrite(file, data, size, offset)); +} + +bool TruncatePlatformFile(PlatformFile file, int64 length) { + return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length))); +} + +bool FlushPlatformFile(PlatformFile file) { + return !HANDLE_EINTR(fsync(file)); +} + +bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time, + const base::Time& last_modified_time) { + if (file < 0) + return false; + + timeval times[2]; + times[0] = last_access_time.ToTimeVal(); + times[1] = last_modified_time.ToTimeVal(); + return !futimes(file, times); +} + +bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { + if (!info) + return false; + + stat_wrapper_t file_info; + if (CallFstat(file, &file_info)) + return false; + + info->is_directory = S_ISDIR(file_info.st_mode); + info->is_symbolic_link = S_ISLNK(file_info.st_mode); + info->size = file_info.st_size; + info->last_modified = base::Time::FromTimeT(file_info.st_mtime); + info->last_accessed = base::Time::FromTimeT(file_info.st_atime); + info->creation_time = base::Time::FromTimeT(file_info.st_ctime); + return true; +} + +} // namespace base diff --git a/base/port.h b/base/port.h new file mode 100644 index 000000000000..2e66057aeeaf --- /dev/null +++ b/base/port.h @@ -0,0 +1,55 @@ +// 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_ +#pragma once + +#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_ diff --git a/base/string16.cc b/base/string16.cc new file mode 100644 index 000000000000..6fc38ce7cb09 --- /dev/null +++ b/base/string16.cc @@ -0,0 +1,80 @@ +// 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. + +#include "base/string16.h" + +#if defined(WCHAR_T_IS_UTF16) + +#error This file should not be used on 2-byte wchar_t systems +// If this winds up being needed on 2-byte wchar_t systems, either the +// definitions below can be used, or the host system's wide character +// functions like wmemcmp can be wrapped. + +#elif defined(WCHAR_T_IS_UTF32) + +#include <ostream> + +#include "base/utf_string_conversions.h" + +namespace base { + +int c16memcmp(const char16* s1, const char16* s2, size_t n) { + // We cannot call memcmp because that changes the semantics. + while (n-- > 0) { + if (*s1 != *s2) { + // We cannot use (*s1 - *s2) because char16 is unsigned. + return ((*s1 < *s2) ? -1 : 1); + } + ++s1; + ++s2; + } + return 0; +} + +size_t c16len(const char16* s) { + const char16 *s_orig = s; + while (*s) { + ++s; + } + return s - s_orig; +} + +const char16* c16memchr(const char16* s, char16 c, size_t n) { + while (n-- > 0) { + if (*s == c) { + return s; + } + ++s; + } + return 0; +} + +char16* c16memmove(char16* s1, const char16* s2, size_t n) { + return reinterpret_cast<char16*>(memmove(s1, s2, n * sizeof(char16))); +} + +char16* c16memcpy(char16* s1, const char16* s2, size_t n) { + return reinterpret_cast<char16*>(memcpy(s1, s2, n * sizeof(char16))); +} + +char16* c16memset(char16* s, char16 c, size_t n) { + char16 *s_orig = s; + while (n-- > 0) { + *s = c; + ++s; + } + return s_orig; +} + +} // namespace base + +template class std::basic_string<char16, base::string16_char_traits>; + +namespace base { +std::ostream& operator<<(std::ostream& out, const string16& str) { + return out << UTF16ToUTF8(str); +} +} + +#endif // WCHAR_T_IS_UTF32 diff --git a/base/string16.h b/base/string16.h new file mode 100644 index 000000000000..4c7b21f8a0eb --- /dev/null +++ b/base/string16.h @@ -0,0 +1,178 @@ +// 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_STRING16_H_ +#define BASE_STRING16_H_ +#pragma once + +// 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) + +typedef wchar_t char16; +typedef std::wstring string16; + +#elif defined(WCHAR_T_IS_UTF32) + +typedef uint16 char16; + +namespace base { + +// 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); + } +}; + +} // 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 std::basic_string<char16, base::string16_char_traits>; + +typedef std::basic_string<char16, base::string16_char_traits> string16; + +namespace base { +BASE_EXPORT extern std::ostream& operator<<(std::ostream& out, + const string16& str); +} + +#endif // WCHAR_T_IS_UTF32 + +#endif // BASE_STRING16_H_ diff --git a/base/string_number_conversions.cc b/base/string_number_conversions.cc new file mode 100644 index 000000000000..54eca17511c1 --- /dev/null +++ b/base/string_number_conversions.cc @@ -0,0 +1,545 @@ +// 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/string_number_conversions.h" + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <wctype.h> + +#include <limits> + +#include "base/logging.h" +#include "base/third_party/dmg_fp/dmg_fp.h" +#include "base/utf_string_conversions.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 (!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; +}; + +typedef BaseIteratorRangeToNumberTraits<std::string::const_iterator, int, 10> + IteratorRangeToIntTraits; +typedef BaseIteratorRangeToNumberTraits<string16::const_iterator, int, 10> + WideIteratorRangeToIntTraits; +typedef BaseIteratorRangeToNumberTraits<std::string::const_iterator, int64, 10> + IteratorRangeToInt64Traits; +typedef BaseIteratorRangeToNumberTraits<string16::const_iterator, int64, 10> + WideIteratorRangeToInt64Traits; + +typedef BaseIteratorRangeToNumberTraits<const char*, int, 10> + CharBufferToIntTraits; +typedef BaseIteratorRangeToNumberTraits<const char16*, int, 10> + WideCharBufferToIntTraits; +typedef BaseIteratorRangeToNumberTraits<const char*, int64, 10> + CharBufferToInt64Traits; +typedef BaseIteratorRangeToNumberTraits<const char16*, int64, 10> + WideCharBufferToInt64Traits; + +template<typename ITERATOR> +class BaseHexIteratorRangeToIntTraits + : public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> { + public: + // Allow parsing of 0xFFFFFFFF, which is technically an overflow + static unsigned int max() { + return std::numeric_limits<unsigned int>::max(); + } +}; + +typedef BaseHexIteratorRangeToIntTraits<std::string::const_iterator> + HexIteratorRangeToIntTraits; +typedef BaseHexIteratorRangeToIntTraits<const char*> + HexCharBufferToIntTraits; + +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; +} + +} // 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 std::string& input, int* output) { + return IteratorRangeToNumber<IteratorRangeToIntTraits>::Invoke(input.begin(), + input.end(), + output); +} + +bool StringToInt(std::string::const_iterator begin, + std::string::const_iterator end, + int* output) { + return IteratorRangeToNumber<IteratorRangeToIntTraits>::Invoke(begin, + end, + output); +} + +#if !defined(STD_STRING_ITERATOR_IS_CHAR_POINTER) +bool StringToInt(const char* begin, const char* end, int* output) { + return IteratorRangeToNumber<CharBufferToIntTraits>::Invoke(begin, + end, + output); +} +#endif + +bool StringToInt(const string16& input, int* output) { + return IteratorRangeToNumber<WideIteratorRangeToIntTraits>::Invoke( + input.begin(), input.end(), output); +} + +bool StringToInt(string16::const_iterator begin, + string16::const_iterator end, + int* output) { + return IteratorRangeToNumber<WideIteratorRangeToIntTraits>::Invoke(begin, + end, + output); +} + +#if !defined(BASE_STRING16_ITERATOR_IS_CHAR16_POINTER) +bool StringToInt(const char16* begin, const char16* end, int* output) { + return IteratorRangeToNumber<WideCharBufferToIntTraits>::Invoke(begin, + end, + output); +} +#endif + +bool StringToInt64(const std::string& input, int64* output) { + return IteratorRangeToNumber<IteratorRangeToInt64Traits>::Invoke( + input.begin(), input.end(), output); +} + +bool StringToInt64(std::string::const_iterator begin, + std::string::const_iterator end, + int64* output) { + return IteratorRangeToNumber<IteratorRangeToInt64Traits>::Invoke(begin, + end, + output); +} + +#if !defined(STD_STRING_ITERATOR_IS_CHAR_POINTER) +bool StringToInt64(const char* begin, const char* end, int64* output) { + return IteratorRangeToNumber<CharBufferToInt64Traits>::Invoke(begin, + end, + output); +} +#endif + +bool StringToInt64(const string16& input, int64* output) { + return IteratorRangeToNumber<WideIteratorRangeToInt64Traits>::Invoke( + input.begin(), input.end(), output); +} + +bool StringToInt64(string16::const_iterator begin, + string16::const_iterator end, + int64* output) { + return IteratorRangeToNumber<WideIteratorRangeToInt64Traits>::Invoke(begin, + end, + output); +} + +#if !defined(BASE_STRING16_ITERATOR_IS_CHAR16_POINTER) +bool StringToInt64(const char16* begin, const char16* end, int64* output) { + return IteratorRangeToNumber<WideCharBufferToInt64Traits>::Invoke(begin, + end, + output); +} +#endif + +bool StringToDouble(const std::string& input, double* output) { + errno = 0; // Thread-safe? It is on at least Mac, Linux, and Windows. + 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 std::string& input, int* output) { + return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke( + input.begin(), input.end(), output); +} + +bool HexStringToInt(std::string::const_iterator begin, + std::string::const_iterator end, + int* output) { + return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke(begin, + end, + output); +} + +#if !defined(STD_STRING_ITERATOR_IS_CHAR_POINTER) +bool HexStringToInt(const char* begin, const char* end, int* output) { + return IteratorRangeToNumber<HexCharBufferToIntTraits>::Invoke(begin, + end, + output); +} +#endif + +bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) { + return HexStringToBytesT(input, output); +} + +} // namespace base diff --git a/base/string_number_conversions.h b/base/string_number_conversions.h new file mode 100644 index 000000000000..6cf6a76b80d2 --- /dev/null +++ b/base/string_number_conversions.h @@ -0,0 +1,124 @@ +// 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_STRING_NUMBER_CONVERSIONS_H_ +#define BASE_STRING_NUMBER_CONVERSIONS_H_ + +#include <string> +#include <vector> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/string16.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/underflow. |*output| will be set to the maximum 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 std::string& input, int* output); +BASE_EXPORT bool StringToInt(std::string::const_iterator begin, + std::string::const_iterator end, + int* output); +BASE_EXPORT bool StringToInt(const char* begin, const char* end, int* output); + +BASE_EXPORT bool StringToInt(const string16& input, int* output); +BASE_EXPORT bool StringToInt(string16::const_iterator begin, + string16::const_iterator end, + int* output); +BASE_EXPORT bool StringToInt(const char16* begin, const char16* end, + int* output); + +BASE_EXPORT bool StringToInt64(const std::string& input, int64* output); +BASE_EXPORT bool StringToInt64(std::string::const_iterator begin, + std::string::const_iterator end, + int64* output); +BASE_EXPORT bool StringToInt64(const char* begin, const char* end, + int64* output); + +BASE_EXPORT bool StringToInt64(const string16& input, int64* output); +BASE_EXPORT bool StringToInt64(string16::const_iterator begin, + string16::const_iterator end, + int64* output); +BASE_EXPORT bool StringToInt64(const char16* begin, const char16* end, + int64* 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. +BASE_EXPORT bool HexStringToInt(const std::string& input, int* output); +BASE_EXPORT bool HexStringToInt(std::string::const_iterator begin, + std::string::const_iterator end, + int* output); +BASE_EXPORT bool HexStringToInt(const char* begin, const char* end, + int* 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_STRING_NUMBER_CONVERSIONS_H_ + diff --git a/base/string_piece.cc b/base/string_piece.cc new file mode 100644 index 000000000000..bf6291c28075 --- /dev/null +++ b/base/string_piece.cc @@ -0,0 +1,214 @@ +// 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. +// Copied from strings/stringpiece.cc with modifications + +#include <algorithm> +#include <ostream> + +#include "base/string_piece.h" + +namespace base { + +typedef StringPiece::size_type size_type; + +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; +} + +void StringPiece::CopyToString(std::string* target) const { + target->assign(!empty() ? data() : "", size()); +} + +void StringPiece::AppendToString(std::string* target) const { + if (!empty()) + target->append(data(), size()); +} + +size_type StringPiece::copy(char* buf, size_type n, size_type pos) const { + size_type ret = std::min(length_ - pos, n); + memcpy(buf, ptr_ + pos, ret); + return ret; +} + +size_type StringPiece::find(const StringPiece& s, size_type pos) const { + if (pos > length_) + return npos; + + const char* result = std::search(ptr_ + pos, ptr_ + length_, + s.ptr_, s.ptr_ + s.length_); + const size_type xpos = result - ptr_; + return xpos + s.length_ <= length_ ? xpos : npos; +} + +size_type StringPiece::find(char c, size_type pos) const { + if (pos >= length_) + return npos; + + const char* result = std::find(ptr_ + pos, ptr_ + length_, c); + return result != ptr_ + length_ ? static_cast<size_t>(result - ptr_) : npos; +} + +size_type StringPiece::rfind(const StringPiece& s, size_type pos) const { + if (length_ < s.length_) + return npos; + + if (s.empty()) + return std::min(length_, pos); + + const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_; + const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_); + return result != last ? static_cast<size_t>(result - ptr_) : npos; +} + +size_type StringPiece::rfind(char c, size_type pos) const { + if (length_ == 0) + return npos; + + for (size_type i = std::min(pos, length_ - 1); ; --i) { + if (ptr_[i] == c) + return i; + if (i == 0) + break; + } + return 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 size_type length = characters_wanted.length(); + const char* const data = characters_wanted.data(); + for (size_type i = 0; i < length; ++i) { + table[static_cast<unsigned char>(data[i])] = true; + } +} + +size_type StringPiece::find_first_of(const StringPiece& s, + size_type pos) const { + if (length_ == 0 || s.length_ == 0) + return npos; + + // Avoid the cost of BuildLookupTable() for a single-character search. + if (s.length_ == 1) + return find_first_of(s.ptr_[0], pos); + + bool lookup[UCHAR_MAX + 1] = { false }; + BuildLookupTable(s, lookup); + for (size_type i = pos; i < length_; ++i) { + if (lookup[static_cast<unsigned char>(ptr_[i])]) { + return i; + } + } + return npos; +} + +size_type StringPiece::find_first_not_of(const StringPiece& s, + size_type pos) const { + if (length_ == 0) + return npos; + + if (s.length_ == 0) + return 0; + + // Avoid the cost of BuildLookupTable() for a single-character search. + if (s.length_ == 1) + return find_first_not_of(s.ptr_[0], pos); + + bool lookup[UCHAR_MAX + 1] = { false }; + BuildLookupTable(s, lookup); + for (size_type i = pos; i < length_; ++i) { + if (!lookup[static_cast<unsigned char>(ptr_[i])]) { + return i; + } + } + return npos; +} + +size_type StringPiece::find_first_not_of(char c, size_type pos) const { + if (length_ == 0) + return npos; + + for (; pos < length_; ++pos) { + if (ptr_[pos] != c) { + return pos; + } + } + return npos; +} + +size_type StringPiece::find_last_of(const StringPiece& s, size_type pos) const { + if (length_ == 0 || s.length_ == 0) + return npos; + + // Avoid the cost of BuildLookupTable() for a single-character search. + if (s.length_ == 1) + return find_last_of(s.ptr_[0], pos); + + bool lookup[UCHAR_MAX + 1] = { false }; + BuildLookupTable(s, lookup); + for (size_type i = std::min(pos, length_ - 1); ; --i) { + if (lookup[static_cast<unsigned char>(ptr_[i])]) + return i; + if (i == 0) + break; + } + return npos; +} + +size_type StringPiece::find_last_not_of(const StringPiece& s, + size_type pos) const { + if (length_ == 0) + return npos; + + size_type i = std::min(pos, length_ - 1); + if (s.length_ == 0) + return i; + + // Avoid the cost of BuildLookupTable() for a single-character search. + if (s.length_ == 1) + return find_last_not_of(s.ptr_[0], pos); + + bool lookup[UCHAR_MAX + 1] = { false }; + BuildLookupTable(s, lookup); + for (; ; --i) { + if (!lookup[static_cast<unsigned char>(ptr_[i])]) + return i; + if (i == 0) + break; + } + return npos; +} + +size_type StringPiece::find_last_not_of(char c, size_type pos) const { + if (length_ == 0) + return npos; + + for (size_type i = std::min(pos, length_ - 1); ; --i) { + if (ptr_[i] != c) + return i; + if (i == 0) + break; + } + return npos; +} + +StringPiece StringPiece::substr(size_type pos, size_type n) const { + if (pos > length_) pos = length_; + if (n > length_ - pos) n = length_ - pos; + return StringPiece(ptr_ + pos, n); +} + +const StringPiece::size_type StringPiece::npos = size_type(-1); + +} // namespace base diff --git a/base/string_piece.h b/base/string_piece.h new file mode 100644 index 000000000000..278c7b692ae4 --- /dev/null +++ b/base/string_piece.h @@ -0,0 +1,349 @@ +// 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. +// 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_STRING_PIECE_H_ +#define BASE_STRING_PIECE_H_ +#pragma once + +#include <string> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/hash_tables.h" +#include "base/string16.h" + +namespace base { + +class BASE_EXPORT StringPiece { + public: + // standard STL container boilerplate + typedef size_t size_type; + typedef char value_type; + typedef const char* pointer; + typedef const char& reference; + typedef const char& const_reference; + typedef ptrdiff_t difference_type; + typedef const char* const_iterator; + typedef const char* iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef std::reverse_iterator<iterator> 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. + StringPiece() : ptr_(NULL), length_(0) { } + StringPiece(const char* str) + : ptr_(str), length_((str == NULL) ? 0 : strlen(str)) { } + StringPiece(const std::string& str) + : ptr_(str.data()), length_(str.size()) { } + StringPiece(const char* offset, size_type len) + : ptr_(offset), length_(len) { } + + // 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 char* 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 char* data, size_type len) { + ptr_ = data; + length_ = len; + } + void set(const char* str) { + ptr_ = str; + length_ = str ? strlen(str) : 0; + } + void set(const void* data, size_type len) { + ptr_ = reinterpret_cast<const char*>(data); + length_ = len; + } + + char 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 StringPiece& 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; + } + + std::string as_string() const { + // std::string doesn't like to take a NULL pointer even with a 0 size. + return std::string(!empty() ? data() : "", size()); + } + + void CopyToString(std::string* target) const; + void AppendToString(std::string* target) const; + + // Does "this" start with "x" + bool starts_with(const StringPiece& x) const { + return ((length_ >= x.length_) && + (wordmemcmp(ptr_, x.ptr_, x.length_) == 0)); + } + + // Does "this" end with "x" + bool ends_with(const StringPiece& x) const { + return ((length_ >= x.length_) && + (wordmemcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0)); + } + + iterator begin() const { return ptr_; } + 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_; } + + size_type copy(char* buf, size_type n, size_type pos = 0) const; + + size_type find(const StringPiece& s, size_type pos = 0) const; + size_type find(char c, size_type pos = 0) const; + size_type rfind(const StringPiece& s, size_type pos = npos) const; + size_type rfind(char c, size_type pos = npos) const; + + size_type find_first_of(const StringPiece& s, size_type pos = 0) const; + size_type find_first_of(char c, size_type pos = 0) const { + return find(c, pos); + } + size_type find_first_not_of(const StringPiece& s, size_type pos = 0) const; + size_type find_first_not_of(char c, size_type pos = 0) const; + size_type find_last_of(const StringPiece& s, size_type pos = npos) const; + size_type find_last_of(char c, size_type pos = npos) const { + return rfind(c, pos); + } + size_type find_last_not_of(const StringPiece& s, size_type pos = npos) const; + size_type find_last_not_of(char c, size_type pos = npos) const; + + StringPiece substr(size_type pos, size_type n = npos) const; + + static int wordmemcmp(const char* p, const char* p2, size_type N) { + return memcmp(p, p2, N); + } + + private: + const char* ptr_; + size_type length_; +}; + +class BASE_EXPORT StringPiece16 { + public: + // standard STL container boilerplate + typedef size_t size_type; + typedef char16 value_type; + typedef const char16* pointer; + typedef const char16& reference; + typedef const char16& const_reference; + typedef ptrdiff_t difference_type; + typedef const char16* const_iterator; + typedef const char16* iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + + public: + // We provide non-explicit singleton constructors so users can pass + // in a "const char16*" or a "string16" wherever a "StringPiece16" is + // expected. + StringPiece16() : ptr_(NULL), length_(0) { } + StringPiece16(const char16* str) + : ptr_(str), + length_((str == NULL) ? 0 : string16::traits_type::length(str)) { } + StringPiece16(const string16& str) + : ptr_(str.data()), length_(str.size()) { } + StringPiece16(const char16* offset, size_type len) + : ptr_(offset), length_(len) { } + + // 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 char16* 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 char16* data, size_type len) { + ptr_ = data; + length_ = len; + } + void set(const char16* str) { + ptr_ = str; + length_ = str ? string16::traits_type::length(str) : 0; + } + + char16 operator[](size_type i) const { return ptr_[i]; } + + string16 as_string16() const { + // StringPiece claims that this is bad when data() is NULL, but unittesting + // seems to say otherwise. + return string16(data(), size()); + } + + iterator begin() const { return ptr_; } + 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 char16* p, const char16* p2, size_type N) { + return string16::traits_type::compare(p, p2, N); + } + + private: + const char16* ptr_; + size_type length_; +}; + +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); +} + +} // 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/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_STRING_PIECE_H_ diff --git a/base/synchronization/lock.h b/base/synchronization/lock.h new file mode 100644 index 000000000000..f3a685e4ed0b --- /dev/null +++ b/base/synchronization/lock.h @@ -0,0 +1,132 @@ +// 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_SYNCHRONIZATION_LOCK_H_ +#define BASE_SYNCHRONIZATION_LOCK_H_ +#pragma once + +#include "base/base_export.h" +#include "base/synchronization/lock_impl.h" +#include "base/threading/platform_thread.h" + +namespace base { + +// A convenient wrapper for an OS specific critical section. The only real +// intelligence in this class is in debug mode for the support for the +// AssertAcquired() method. +class BASE_EXPORT Lock { + public: +#if defined(NDEBUG) // Optimized wrapper implementation + Lock() : lock_() {} + ~Lock() {} + void Acquire() { lock_.Lock(); } + void Release() { lock_.Unlock(); } + + // If the lock is not held, take it and return true. If the lock is already + // held by another thread, immediately return false. This must not be called + // by a thread already holding the lock (what happens is undefined and an + // assertion may fail). + bool Try() { return lock_.Try(); } + + // Null implementation if not debug. + void AssertAcquired() const {} +#else + Lock(); + ~Lock() {} + + // NOTE: Although windows critical sections support recursive locks, we do not + // allow this, and we will commonly fire a DCHECK() if a thread attempts to + // acquire the lock a second time (while already holding it). + void Acquire() { + lock_.Lock(); + CheckUnheldAndMark(); + } + void Release() { + CheckHeldAndUnmark(); + lock_.Unlock(); + } + + bool Try() { + bool rv = lock_.Try(); + if (rv) { + CheckUnheldAndMark(); + } + return rv; + } + + void AssertAcquired() const; +#endif // NDEBUG + +#if defined(OS_POSIX) + // The posix implementation of ConditionVariable needs to be able + // to see our lock and tweak our debugging counters, as it releases + // and acquires locks inside of pthread_cond_{timed,}wait. + // Windows doesn't need to do this as it calls the Lock::* methods. + friend class ConditionVariable; +#endif + + private: +#if !defined(NDEBUG) + // Members and routines taking care of locks assertions. + // Note that this checks for recursive locks and allows them + // if the variable is set. This is allowed by the underlying implementation + // on windows but not on Posix, so we're doing unneeded checks on Posix. + // It's worth it to share the code. + void CheckHeldAndUnmark(); + void CheckUnheldAndMark(); + + // All private data is implicitly protected by lock_. + // Be VERY careful to only access members under that lock. + + // Determines validity of owning_thread_id_. Needed as we don't have + // a null owning_thread_id_ value. + bool owned_by_thread_; + base::PlatformThreadId owning_thread_id_; +#endif // NDEBUG + + // Platform specific underlying lock implementation. + internal::LockImpl lock_; + + DISALLOW_COPY_AND_ASSIGN(Lock); +}; + +// A helper class that acquires the given Lock while the AutoLock is in scope. +class AutoLock { + public: + explicit AutoLock(Lock& lock) : lock_(lock) { + lock_.Acquire(); + } + + ~AutoLock() { + lock_.AssertAcquired(); + lock_.Release(); + } + + private: + Lock& lock_; + DISALLOW_COPY_AND_ASSIGN(AutoLock); +}; + +// AutoUnlock is a helper that will Release() the |lock| argument in the +// constructor, and re-Acquire() it in the destructor. +class AutoUnlock { + public: + explicit AutoUnlock(Lock& lock) : lock_(lock) { + // We require our caller to have the lock. + lock_.AssertAcquired(); + lock_.Release(); + } + + ~AutoUnlock() { + lock_.Acquire(); + } + + private: + Lock& lock_; + DISALLOW_COPY_AND_ASSIGN(AutoUnlock); +}; + +} // namespace base + +#endif // BASE_SYNCHRONIZATION_LOCK_H_ diff --git a/base/synchronization/lock_impl.h b/base/synchronization/lock_impl.h new file mode 100644 index 000000000000..63efc5ff4ed1 --- /dev/null +++ b/base/synchronization/lock_impl.h @@ -0,0 +1,64 @@ +// 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_SYNCHRONIZATION_LOCK_IMPL_H_ +#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_ +#pragma once + +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(OS_POSIX) +#include <pthread.h> +#endif + +#include "base/base_export.h" +#include "base/basictypes.h" + +namespace base { +namespace internal { + +// This class implements the underlying platform-specific spin-lock mechanism +// used for the Lock class. Most users should not use LockImpl directly, but +// should instead use Lock. +class BASE_EXPORT LockImpl { + public: +#if defined(OS_WIN) + typedef CRITICAL_SECTION OSLockType; +#elif defined(OS_POSIX) + typedef pthread_mutex_t OSLockType; +#endif + + LockImpl(); + ~LockImpl(); + + // If the lock is not held, take it and return true. If the lock is already + // held by something else, immediately return false. + bool Try(); + + // Take the lock, blocking until it is available if necessary. + void Lock(); + + // Release the lock. This must only be called by the lock's holder: after + // a successful call to Try, or a call to Lock. + void Unlock(); + + // Return the native underlying lock. Not supported for Windows builds. + // TODO(awalker): refactor lock and condition variables so that this is + // unnecessary. +#if !defined(OS_WIN) + OSLockType* os_lock() { return &os_lock_; } +#endif + + private: + OSLockType os_lock_; + + DISALLOW_COPY_AND_ASSIGN(LockImpl); +}; + +} // namespace internal +} // namespace base + +#endif // BASE_SYNCHRONIZATION_LOCK_IMPL_H_ diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h new file mode 100644 index 000000000000..62712edd9244 --- /dev/null +++ b/base/synchronization/waitable_event.h @@ -0,0 +1,181 @@ +// 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_SYNCHRONIZATION_WAITABLE_EVENT_H_ +#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_ +#pragma once + +#include "base/base_export.h" +#include "base/basictypes.h" + +#if defined(OS_WIN) +#include <windows.h> +#endif + +#if defined(OS_POSIX) +#include <list> +#include <utility> +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#endif + +namespace base { + +// This replaces INFINITE from Win32 +static const int kNoTimeout = -1; + +class TimeDelta; + +// A WaitableEvent can be a useful thread synchronization tool when you want to +// allow one thread to wait for another thread to finish some work. For +// non-Windows systems, this can only be used from within a single address +// space. +// +// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to +// protect a simple boolean value. However, if you find yourself using a +// WaitableEvent in conjunction with a Lock to wait for a more complex state +// change (e.g., for an item to be added to a queue), then you should probably +// be using a ConditionVariable instead of a WaitableEvent. +// +// NOTE: On Windows, this class provides a subset of the functionality afforded +// by a Windows event object. This is intentional. If you are writing Windows +// specific code and you need other features of a Windows event, then you might +// be better off just using an Windows event directly. +class BASE_EXPORT WaitableEvent { + public: + // If manual_reset is true, then to set the event state to non-signaled, a + // consumer must call the Reset method. If this parameter is false, then the + // system automatically resets the event state to non-signaled after a single + // waiting thread has been released. + WaitableEvent(bool manual_reset, bool initially_signaled); + +#if defined(OS_WIN) + // Create a WaitableEvent from an Event HANDLE which has already been + // created. This objects takes ownership of the HANDLE and will close it when + // deleted. + explicit WaitableEvent(HANDLE event_handle); + + // Releases ownership of the handle from this object. + HANDLE Release(); +#endif + + ~WaitableEvent(); + + // Put the event in the un-signaled state. + void Reset(); + + // Put the event in the signaled state. Causing any thread blocked on Wait + // to be woken up. + void Signal(); + + // Returns true if the event is in the signaled state, else false. If this + // is not a manual reset event, then this test will cause a reset. + bool IsSignaled(); + + // Wait indefinitely for the event to be signaled. Returns true if the event + // was signaled, else false is returned to indicate that waiting failed. + bool Wait(); + + // Wait up until max_time has passed for the event to be signaled. Returns + // true if the event was signaled. If this method returns false, then it + // does not necessarily mean that max_time was exceeded. + bool TimedWait(const TimeDelta& max_time); + +#if defined(OS_WIN) + HANDLE handle() const { return handle_; } +#endif + + // Wait, synchronously, on multiple events. + // waitables: an array of WaitableEvent pointers + // count: the number of elements in @waitables + // + // returns: the index of a WaitableEvent which has been signaled. + // + // You MUST NOT delete any of the WaitableEvent objects while this wait is + // happening. + static size_t WaitMany(WaitableEvent** waitables, size_t count); + + // For asynchronous waiting, see WaitableEventWatcher + + // This is a private helper class. It's here because it's used by friends of + // this class (such as WaitableEventWatcher) to be able to enqueue elements + // of the wait-list + class Waiter { + public: + // Signal the waiter to wake up. + // + // Consider the case of a Waiter which is in multiple WaitableEvent's + // wait-lists. Each WaitableEvent is automatic-reset and two of them are + // signaled at the same time. Now, each will wake only the first waiter in + // the wake-list before resetting. However, if those two waiters happen to + // be the same object (as can happen if another thread didn't have a chance + // to dequeue the waiter from the other wait-list in time), two auto-resets + // will have happened, but only one waiter has been signaled! + // + // Because of this, a Waiter may "reject" a wake by returning false. In + // this case, the auto-reset WaitableEvent shouldn't act as if anything has + // been notified. + virtual bool Fire(WaitableEvent* signaling_event) = 0; + + // Waiters may implement this in order to provide an extra condition for + // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the + // pointers match then this function is called as a final check. See the + // comments in ~Handle for why. + virtual bool Compare(void* tag) = 0; + + protected: + virtual ~Waiter() {} + }; + + private: + friend class WaitableEventWatcher; + +#if defined(OS_WIN) + HANDLE handle_; +#else + // On Windows, one can close a HANDLE which is currently being waited on. The + // MSDN documentation says that the resulting behaviour is 'undefined', but + // it doesn't crash. However, if we were to include the following members + // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an + // event which gets deleted. This mismatch has bitten us several times now, + // so we have a kernel of the WaitableEvent, which is reference counted. + // WaitableEventWatchers may then take a reference and thus match the Windows + // behaviour. + struct WaitableEventKernel : + public RefCountedThreadSafe<WaitableEventKernel> { + public: + WaitableEventKernel(bool manual_reset, bool initially_signaled); + virtual ~WaitableEventKernel(); + + bool Dequeue(Waiter* waiter, void* tag); + + base::Lock lock_; + const bool manual_reset_; + bool signaled_; + std::list<Waiter*> waiters_; + }; + + typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex; + + // When dealing with arrays of WaitableEvent*, we want to sort by the address + // of the WaitableEvent in order to have a globally consistent locking order. + // In that case we keep them, in sorted order, in an array of pairs where the + // second element is the index of the WaitableEvent in the original, + // unsorted, array. + static size_t EnqueueMany(WaiterAndIndex* waitables, + size_t count, Waiter* waiter); + + bool SignalAll(); + bool SignalOne(); + void Enqueue(Waiter* waiter); + + scoped_refptr<WaitableEventKernel> kernel_; +#endif + + DISALLOW_COPY_AND_ASSIGN(WaitableEvent); +}; + +} // namespace base + +#endif // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_ diff --git a/base/template_util.h b/base/template_util.h new file mode 100644 index 000000000000..f19fb4b4ee04 --- /dev/null +++ b/base/template_util.h @@ -0,0 +1,109 @@ +// 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_TEMPLATE_UTIL_H_ +#define BASE_TEMPLATE_UTIL_H_ +#pragma once + +#include <cstddef> // For size_t. + +#include "build/build_config.h" + +namespace base { + +// template definitions from tr1 + +template<class T, T v> +struct integral_constant { + static const T value = v; + typedef T value_type; + typedef integral_constant<T, v> type; +}; + +template <class T, T v> const T integral_constant<T, v>::value; + +typedef integral_constant<bool, true> true_type; +typedef integral_constant<bool, false> false_type; + +template <class T> struct is_pointer : false_type {}; +template <class T> struct is_pointer<T*> : true_type {}; + +template <class T, class U> struct is_same : public false_type {}; +template <class T> struct is_same<T,T> : true_type {}; + +template<class> struct is_array : public false_type {}; +template<class T, size_t n> struct is_array<T[n]> : public true_type {}; +template<class T> struct is_array<T[]> : public true_type {}; + +template <class T> struct is_non_const_reference : false_type {}; +template <class T> struct is_non_const_reference<T&> : true_type {}; +template <class T> struct is_non_const_reference<const T&> : false_type {}; + +template <class T> struct is_void : false_type {}; +template <> struct is_void<void> : true_type {}; + +namespace internal { + +// Types YesType and NoType are guaranteed such that sizeof(YesType) < +// sizeof(NoType). +typedef char YesType; + +struct NoType { + YesType dummy[2]; +}; + +// This class is an implementation detail for is_convertible, and you +// don't need to know how it works to use is_convertible. For those +// who care: we declare two different functions, one whose argument is +// of type To and one with a variadic argument list. We give them +// return types of different size, so we can use sizeof to trick the +// compiler into telling us which function it would have chosen if we +// had called it with an argument of type From. See Alexandrescu's +// _Modern C++ Design_ for more details on this sort of trick. + +struct ConvertHelper { + template <typename To> + static YesType Test(To); + + template <typename To> + static NoType Test(...); + + template <typename From> + static From Create(); +}; + +// Used to determine if a type is a struct/union/class. Inspired by Boost's +// is_class type_trait implementation. +struct IsClassHelper { + template <typename C> + static YesType Test(void(C::*)(void)); + + template <typename C> + static NoType Test(...); +}; + +} // namespace internal + +// Inherits from true_type if From is convertible to To, false_type otherwise. +// +// Note that if the type is convertible, this will be a true_type REGARDLESS +// of whether or not the conversion would emit a warning. +template <typename From, typename To> +struct is_convertible + : integral_constant<bool, + sizeof(internal::ConvertHelper::Test<To>( + internal::ConvertHelper::Create<From>())) == + sizeof(internal::YesType)> { +}; + +template <typename T> +struct is_class + : integral_constant<bool, + sizeof(internal::IsClassHelper::Test<T>(0)) == + sizeof(internal::YesType)> { +}; + +} // namespace base + +#endif // BASE_TEMPLATE_UTIL_H_ diff --git a/base/third_party/dynamic_annotations/LICENSE b/base/third_party/dynamic_annotations/LICENSE new file mode 100644 index 000000000000..5c581a9391b9 --- /dev/null +++ b/base/third_party/dynamic_annotations/LICENSE @@ -0,0 +1,28 @@ +/* Copyright (c) 2008-2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * --- + * Author: Kostya Serebryany + */ diff --git a/base/third_party/dynamic_annotations/README.chromium b/base/third_party/dynamic_annotations/README.chromium new file mode 100644 index 000000000000..f78a98214386 --- /dev/null +++ b/base/third_party/dynamic_annotations/README.chromium @@ -0,0 +1,11 @@ +Name: dynamic annotations +URL: http://code.google.com/p/data-race-test/wiki/DynamicAnnotations + +One header and one source file (dynamic_annotations.h and dynamic_annotations.c) +in this directory define runtime macros useful for annotating synchronization +utilities and benign data races so data race detectors can handle Chromium code +with better precision. + +These files were taken from +http://code.google.com/p/data-race-test/source/browse/?r=2062#svn/trunk/dynamic_annotations +The files are covered under BSD license as described within the files. diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.c b/base/third_party/dynamic_annotations/dynamic_annotations.c new file mode 100644 index 000000000000..e7d44f4a647e --- /dev/null +++ b/base/third_party/dynamic_annotations/dynamic_annotations.c @@ -0,0 +1,257 @@ +/* Copyright (c) 2011, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _MSC_VER +# include <windows.h> +#endif + +#ifdef __cplusplus +# error "This file should be built as pure C to avoid name mangling" +#endif + +#include <stdlib.h> +#include <string.h> + +#include "base/third_party/dynamic_annotations/dynamic_annotations.h" + +#ifdef __GNUC__ +/* valgrind.h uses gcc extensions so it won't build with other compilers */ +# include "base/third_party/valgrind/valgrind.h" +#endif + +/* Each function is empty and called (via a macro) only in debug mode. + The arguments are captured by dynamic tools at runtime. */ + +#if DYNAMIC_ANNOTATIONS_ENABLED == 1 + +/* Identical code folding(-Wl,--icf=all) countermeasures. + This makes all Annotate* functions different, which prevents the linker from + folding them. */ +#ifdef __COUNTER__ +#define DYNAMIC_ANNOTATIONS_IMPL \ + volatile short lineno = (__LINE__ << 8) + __COUNTER__; (void)lineno; +#else +#define DYNAMIC_ANNOTATIONS_IMPL \ + volatile short lineno = (__LINE__ << 8); (void)lineno; +#endif + +/* WARNING: always add new annotations to the end of the list. + Otherwise, lineno (see above) numbers for different Annotate* functions may + conflict. */ +void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)( + const char *file, int line, const volatile void *lock) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)( + const char *file, int line, const volatile void *lock) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)( + const char *file, int line, const volatile void *lock, long is_w) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)( + const char *file, int line, const volatile void *lock, long is_w) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)( + const char *file, int line, const volatile void *barrier, long count, + long reinitialization_allowed) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)( + const char *file, int line, const volatile void *barrier) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)( + const char *file, int line, const volatile void *barrier) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)( + const char *file, int line, const volatile void *barrier) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)( + const char *file, int line, const volatile void *cv, + const volatile void *lock) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)( + const char *file, int line, const volatile void *cv) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)( + const char *file, int line, const volatile void *cv) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)( + const char *file, int line, const volatile void *obj) +{DYNAMIC_ANNOTATIONS_IMPL}; + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)( + const char *file, int line, const volatile void *obj) +{DYNAMIC_ANNOTATIONS_IMPL}; + +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)( + const char *file, int line, const volatile void *address, long size) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)( + const char *file, int line, const volatile void *address, long size) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)( + const char *file, int line, const volatile void *pcq) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)( + const char *file, int line, const volatile void *pcq) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)( + const char *file, int line, const volatile void *pcq) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)( + const char *file, int line, const volatile void *pcq) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)( + const char *file, int line, const volatile void *mem, long size) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)( + const char *file, int line, const volatile void *mem, + const char *description) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)( + const char *file, int line) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)( + const char *file, int line, const volatile void *mem, + const char *description) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)( + const char *file, int line, const volatile void *mem, long size, + const char *description) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)( + const char *file, int line, const volatile void *mu) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)( + const char *file, int line, const volatile void *mu) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)( + const char *file, int line, const volatile void *arg) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)( + const char *file, int line, const char *name) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)( + const char *file, int line) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)( + const char *file, int line) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)( + const char *file, int line) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)( + const char *file, int line) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)( + const char *file, int line) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)( + const char *file, int line) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)( + const char *file, int line, int enable) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)( + const char *file, int line, const volatile void *arg) +{DYNAMIC_ANNOTATIONS_IMPL} + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)( + const char *file, int line) +{DYNAMIC_ANNOTATIONS_IMPL} + +#endif /* DYNAMIC_ANNOTATIONS_ENABLED == 1 */ + +#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 +static int GetRunningOnValgrind(void) { +#ifdef RUNNING_ON_VALGRIND + if (RUNNING_ON_VALGRIND) return 1; +#endif + +#ifndef _MSC_VER + char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND"); + if (running_on_valgrind_str) { + return strcmp(running_on_valgrind_str, "0") != 0; + } +#else + /* Visual Studio issues warnings if we use getenv, + * so we use GetEnvironmentVariableA instead. + */ + char value[100] = "1"; + int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND", + value, sizeof(value)); + /* value will remain "1" if res == 0 or res >= sizeof(value). The latter + * can happen only if the given value is long, in this case it can't be "0". + */ + if (res > 0 && strcmp(value, "0") != 0) + return 1; +#endif + return 0; +} + +/* See the comments in dynamic_annotations.h */ +int RunningOnValgrind(void) { + static volatile int running_on_valgrind = -1; + /* C doesn't have thread-safe initialization of statics, and we + don't want to depend on pthread_once here, so hack it. */ + int local_running_on_valgrind = running_on_valgrind; + if (local_running_on_valgrind == -1) + running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind(); + return local_running_on_valgrind; +} + +#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */ diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.gyp b/base/third_party/dynamic_annotations/dynamic_annotations.gyp new file mode 100644 index 000000000000..47334d88360a --- /dev/null +++ b/base/third_party/dynamic_annotations/dynamic_annotations.gyp @@ -0,0 +1,45 @@ +# 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. + +{ + 'targets': [ + { + 'target_name': 'dynamic_annotations', + 'type': 'static_library', + 'include_dirs': [ + '../../../', + ], + 'sources': [ + 'dynamic_annotations.c', + 'dynamic_annotations.h', + ], + }, + ], + 'conditions': [ + ['OS == "win"', { + 'targets': [ + { + 'target_name': 'dynamic_annotations_win64', + 'type': 'static_library', + # We can't use dynamic_annotations target for win64 build since it is + # a 32-bit library. + # TODO(gregoryd): merge with dynamic_annotations when + # the win32/64 targets are merged. + 'include_dirs': [ + '../../../', + ], + 'sources': [ + 'dynamic_annotations.c', + 'dynamic_annotations.h', + ], + 'configurations': { + 'Common_Base': { + 'msvs_target_platform': 'x64', + }, + }, + }, + ], + }], + ], +} diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.h b/base/third_party/dynamic_annotations/dynamic_annotations.h new file mode 100644 index 000000000000..8d7f05202b70 --- /dev/null +++ b/base/third_party/dynamic_annotations/dynamic_annotations.h @@ -0,0 +1,595 @@ +/* Copyright (c) 2011, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* This file defines dynamic annotations for use with dynamic analysis + tool such as valgrind, PIN, etc. + + Dynamic annotation is a source code annotation that affects + the generated code (that is, the annotation is not a comment). + Each such annotation is attached to a particular + instruction and/or to a particular object (address) in the program. + + The annotations that should be used by users are macros in all upper-case + (e.g., ANNOTATE_NEW_MEMORY). + + Actual implementation of these macros may differ depending on the + dynamic analysis tool being used. + + See http://code.google.com/p/data-race-test/ for more information. + + This file supports the following dynamic analysis tools: + - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero). + Macros are defined empty. + - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1). + Macros are defined as calls to non-inlinable empty functions + that are intercepted by Valgrind. */ + +#ifndef __DYNAMIC_ANNOTATIONS_H__ +#define __DYNAMIC_ANNOTATIONS_H__ + +#ifndef DYNAMIC_ANNOTATIONS_PREFIX +# define DYNAMIC_ANNOTATIONS_PREFIX +#endif + +#ifndef DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND +# define DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND 1 +#endif + +#ifdef DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK +# ifdef __GNUC__ +# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK __attribute__((weak)) +# else +/* TODO(glider): for Windows support we may want to change this macro in order + to prepend __declspec(selectany) to the annotations' declarations. */ +# error weak annotations are not supported for your compiler +# endif +#else +# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK +#endif + +/* The following preprocessor magic prepends the value of + DYNAMIC_ANNOTATIONS_PREFIX to annotation function names. */ +#define DYNAMIC_ANNOTATIONS_GLUE0(A, B) A##B +#define DYNAMIC_ANNOTATIONS_GLUE(A, B) DYNAMIC_ANNOTATIONS_GLUE0(A, B) +#define DYNAMIC_ANNOTATIONS_NAME(name) \ + DYNAMIC_ANNOTATIONS_GLUE(DYNAMIC_ANNOTATIONS_PREFIX, name) + +#ifndef DYNAMIC_ANNOTATIONS_ENABLED +# define DYNAMIC_ANNOTATIONS_ENABLED 0 +#endif + +#if DYNAMIC_ANNOTATIONS_ENABLED != 0 + + /* ------------------------------------------------------------- + Annotations useful when implementing condition variables such as CondVar, + using conditional critical sections (Await/LockWhen) and when constructing + user-defined synchronization mechanisms. + + The annotations ANNOTATE_HAPPENS_BEFORE() and ANNOTATE_HAPPENS_AFTER() can + be used to define happens-before arcs in user-defined synchronization + mechanisms: the race detector will infer an arc from the former to the + latter when they share the same argument pointer. + + Example 1 (reference counting): + + void Unref() { + ANNOTATE_HAPPENS_BEFORE(&refcount_); + if (AtomicDecrementByOne(&refcount_) == 0) { + ANNOTATE_HAPPENS_AFTER(&refcount_); + delete this; + } + } + + Example 2 (message queue): + + void MyQueue::Put(Type *e) { + MutexLock lock(&mu_); + ANNOTATE_HAPPENS_BEFORE(e); + PutElementIntoMyQueue(e); + } + + Type *MyQueue::Get() { + MutexLock lock(&mu_); + Type *e = GetElementFromMyQueue(); + ANNOTATE_HAPPENS_AFTER(e); + return e; + } + + Note: when possible, please use the existing reference counting and message + queue implementations instead of inventing new ones. */ + + /* Report that wait on the condition variable at address "cv" has succeeded + and the lock at address "lock" is held. */ + #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, lock) + + /* Report that wait on the condition variable at "cv" has succeeded. Variant + w/o lock. */ + #define ANNOTATE_CONDVAR_WAIT(cv) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, NULL) + + /* Report that we are about to signal on the condition variable at address + "cv". */ + #define ANNOTATE_CONDVAR_SIGNAL(cv) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(__FILE__, __LINE__, cv) + + /* Report that we are about to signal_all on the condition variable at address + "cv". */ + #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(__FILE__, __LINE__, cv) + + /* Annotations for user-defined synchronization mechanisms. */ + #define ANNOTATE_HAPPENS_BEFORE(obj) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(__FILE__, __LINE__, obj) + #define ANNOTATE_HAPPENS_AFTER(obj) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(__FILE__, __LINE__, obj) + + /* DEPRECATED. Don't use it. */ + #define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(__FILE__, __LINE__, \ + pointer, size) + + /* DEPRECATED. Don't use it. */ + #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(__FILE__, __LINE__, \ + pointer, size) + + /* DEPRECATED. Don't use it. */ + #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size) \ + do { \ + ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size); \ + ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size); \ + } while (0) + + /* Instruct the tool to create a happens-before arc between mu->Unlock() and + mu->Lock(). This annotation may slow down the race detector and hide real + races. Normally it is used only when it would be difficult to annotate each + of the mutex's critical sections individually using the annotations above. + This annotation makes sense only for hybrid race detectors. For pure + happens-before detectors this is a no-op. For more details see + http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */ + #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \ + mu) + + /* Opposite to ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. + Instruct the tool to NOT create h-b arcs between Unlock and Lock, even in + pure happens-before mode. For a hybrid mode this is a no-op. */ + #define ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(mu) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(__FILE__, __LINE__, mu) + + /* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */ + #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \ + mu) + + /* ------------------------------------------------------------- + Annotations useful when defining memory allocators, or when memory that + was protected in one way starts to be protected in another. */ + + /* Report that a new memory at "address" of size "size" has been allocated. + This might be used when the memory has been retrieved from a free list and + is about to be reused, or when a the locking discipline for a variable + changes. */ + #define ANNOTATE_NEW_MEMORY(address, size) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(__FILE__, __LINE__, address, \ + size) + + /* ------------------------------------------------------------- + Annotations useful when defining FIFO queues that transfer data between + threads. */ + + /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at + address "pcq" has been created. The ANNOTATE_PCQ_* annotations + should be used only for FIFO queues. For non-FIFO queues use + ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */ + #define ANNOTATE_PCQ_CREATE(pcq) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(__FILE__, __LINE__, pcq) + + /* Report that the queue at address "pcq" is about to be destroyed. */ + #define ANNOTATE_PCQ_DESTROY(pcq) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(__FILE__, __LINE__, pcq) + + /* Report that we are about to put an element into a FIFO queue at address + "pcq". */ + #define ANNOTATE_PCQ_PUT(pcq) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(__FILE__, __LINE__, pcq) + + /* Report that we've just got an element from a FIFO queue at address + "pcq". */ + #define ANNOTATE_PCQ_GET(pcq) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(__FILE__, __LINE__, pcq) + + /* ------------------------------------------------------------- + Annotations that suppress errors. It is usually better to express the + program's synchronization using the other annotations, but these can + be used when all else fails. */ + + /* Report that we may have a benign race at "pointer", with size + "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the + point where "pointer" has been allocated, preferably close to the point + where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. */ + #define ANNOTATE_BENIGN_RACE(pointer, description) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \ + pointer, sizeof(*(pointer)), description) + + /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to + the memory range [address, address+size). */ + #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \ + address, size, description) + + /* Request the analysis tool to ignore all reads in the current thread + until ANNOTATE_IGNORE_READS_END is called. + Useful to ignore intentional racey reads, while still checking + other reads and all writes. + See also ANNOTATE_UNPROTECTED_READ. */ + #define ANNOTATE_IGNORE_READS_BEGIN() \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__) + + /* Stop ignoring reads. */ + #define ANNOTATE_IGNORE_READS_END() \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__) + + /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */ + #define ANNOTATE_IGNORE_WRITES_BEGIN() \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__) + + /* Stop ignoring writes. */ + #define ANNOTATE_IGNORE_WRITES_END() \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__) + + /* Start ignoring all memory accesses (reads and writes). */ + #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ + do {\ + ANNOTATE_IGNORE_READS_BEGIN();\ + ANNOTATE_IGNORE_WRITES_BEGIN();\ + }while(0)\ + + /* Stop ignoring all memory accesses. */ + #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \ + do {\ + ANNOTATE_IGNORE_WRITES_END();\ + ANNOTATE_IGNORE_READS_END();\ + }while(0)\ + + /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events: + RWLOCK* and CONDVAR*. */ + #define ANNOTATE_IGNORE_SYNC_BEGIN() \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(__FILE__, __LINE__) + + /* Stop ignoring sync events. */ + #define ANNOTATE_IGNORE_SYNC_END() \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(__FILE__, __LINE__) + + + /* Enable (enable!=0) or disable (enable==0) race detection for all threads. + This annotation could be useful if you want to skip expensive race analysis + during some period of program execution, e.g. during initialization. */ + #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(__FILE__, __LINE__, \ + enable) + + /* ------------------------------------------------------------- + Annotations useful for debugging. */ + + /* Request to trace every access to "address". */ + #define ANNOTATE_TRACE_MEMORY(address) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(__FILE__, __LINE__, address) + + /* Report the current thread name to a race detector. */ + #define ANNOTATE_THREAD_NAME(name) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(__FILE__, __LINE__, name) + + /* ------------------------------------------------------------- + Annotations useful when implementing locks. They are not + normally needed by modules that merely use locks. + The "lock" argument is a pointer to the lock object. */ + + /* Report that a lock has been created at address "lock". */ + #define ANNOTATE_RWLOCK_CREATE(lock) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(__FILE__, __LINE__, lock) + + /* Report that the lock at address "lock" is about to be destroyed. */ + #define ANNOTATE_RWLOCK_DESTROY(lock) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock) + + /* Report that the lock at address "lock" has been acquired. + is_w=1 for writer lock, is_w=0 for reader lock. */ + #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(__FILE__, __LINE__, lock, \ + is_w) + + /* Report that the lock at address "lock" is about to be released. */ + #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(__FILE__, __LINE__, lock, \ + is_w) + + /* ------------------------------------------------------------- + Annotations useful when implementing barriers. They are not + normally needed by modules that merely use barriers. + The "barrier" argument is a pointer to the barrier object. */ + + /* Report that the "barrier" has been initialized with initial "count". + If 'reinitialization_allowed' is true, initialization is allowed to happen + multiple times w/o calling barrier_destroy() */ + #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(__FILE__, __LINE__, barrier, \ + count, reinitialization_allowed) + + /* Report that we are about to enter barrier_wait("barrier"). */ + #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(__FILE__, __LINE__, \ + barrier) + + /* Report that we just exited barrier_wait("barrier"). */ + #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(__FILE__, __LINE__, \ + barrier) + + /* Report that the "barrier" has been destroyed. */ + #define ANNOTATE_BARRIER_DESTROY(barrier) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(__FILE__, __LINE__, \ + barrier) + + /* ------------------------------------------------------------- + Annotations useful for testing race detectors. */ + + /* Report that we expect a race on the variable at "address". + Use only in unit tests for a race detector. */ + #define ANNOTATE_EXPECT_RACE(address, description) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(__FILE__, __LINE__, address, \ + description) + + #define ANNOTATE_FLUSH_EXPECTED_RACES() \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(__FILE__, __LINE__) + + /* A no-op. Insert where you like to test the interceptors. */ + #define ANNOTATE_NO_OP(arg) \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(__FILE__, __LINE__, arg) + + /* Force the race detector to flush its state. The actual effect depends on + * the implementation of the detector. */ + #define ANNOTATE_FLUSH_STATE() \ + DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(__FILE__, __LINE__) + + +#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ + + #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */ + #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ + #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ + #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ + #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */ + #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */ + #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */ + #define ANNOTATE_BARRIER_DESTROY(barrier) /* empty */ + #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */ + #define ANNOTATE_CONDVAR_WAIT(cv) /* empty */ + #define ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */ + #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */ + #define ANNOTATE_HAPPENS_BEFORE(obj) /* empty */ + #define ANNOTATE_HAPPENS_AFTER(obj) /* empty */ + #define ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */ + #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size) /* empty */ + #define ANNOTATE_SWAP_MEMORY_RANGE(address, size) /* empty */ + #define ANNOTATE_PCQ_CREATE(pcq) /* empty */ + #define ANNOTATE_PCQ_DESTROY(pcq) /* empty */ + #define ANNOTATE_PCQ_PUT(pcq) /* empty */ + #define ANNOTATE_PCQ_GET(pcq) /* empty */ + #define ANNOTATE_NEW_MEMORY(address, size) /* empty */ + #define ANNOTATE_EXPECT_RACE(address, description) /* empty */ + #define ANNOTATE_FLUSH_EXPECTED_RACES(address, description) /* empty */ + #define ANNOTATE_BENIGN_RACE(address, description) /* empty */ + #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ + #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */ + #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */ + #define ANNOTATE_TRACE_MEMORY(arg) /* empty */ + #define ANNOTATE_THREAD_NAME(name) /* empty */ + #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */ + #define ANNOTATE_IGNORE_READS_END() /* empty */ + #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ + #define ANNOTATE_IGNORE_WRITES_END() /* empty */ + #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ + #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ + #define ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */ + #define ANNOTATE_IGNORE_SYNC_END() /* empty */ + #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ + #define ANNOTATE_NO_OP(arg) /* empty */ + #define ANNOTATE_FLUSH_STATE() /* empty */ + +#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ + +/* Use the macros above rather than using these functions directly. */ +#ifdef __cplusplus +extern "C" { +#endif + + +void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)( + const char *file, int line, + const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)( + const char *file, int line, + const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)( + const char *file, int line, + const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)( + const char *file, int line, + const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)( + const char *file, int line, const volatile void *barrier, long count, + long reinitialization_allowed) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)( + const char *file, int line, + const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)( + const char *file, int line, + const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)( + const char *file, int line, + const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)( + const char *file, int line, const volatile void *cv, + const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)( + const char *file, int line, + const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)( + const char *file, int line, + const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)( + const char *file, int line, + const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)( + const char *file, int line, + const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)( + const char *file, int line, + const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)( + const char *file, int line, + const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)( + const char *file, int line, + const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)( + const char *file, int line, + const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)( + const char *file, int line, + const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)( + const char *file, int line, + const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)( + const char *file, int line, + const volatile void *mem, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)( + const char *file, int line, const volatile void *mem, + const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)( + const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)( + const char *file, int line, const volatile void *mem, + const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)( + const char *file, int line, const volatile void *mem, long size, + const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)( + const char *file, int line, + const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)( + const char *file, int line, + const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)( + const char *file, int line, + const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)( + const char *file, int line, + const char *name) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)( + const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)( + const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)( + const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)( + const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)( + const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)( + const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)( + const char *file, int line, int enable) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)( + const char *file, int line, + const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)( + const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; + +#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 +/* Return non-zero value if running under valgrind. + + If "valgrind.h" is included into dynamic_annotations.c, + the regular valgrind mechanism will be used. + See http://valgrind.org/docs/manual/manual-core-adv.html about + RUNNING_ON_VALGRIND and other valgrind "client requests". + The file "valgrind.h" may be obtained by doing + svn co svn://svn.valgrind.org/valgrind/trunk/include + + If for some reason you can't use "valgrind.h" or want to fake valgrind, + there are two ways to make this function return non-zero: + - Use environment variable: export RUNNING_ON_VALGRIND=1 + - Make your tool intercept the function RunningOnValgrind() and + change its return value. + */ +int RunningOnValgrind(void) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK; +#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */ + +#ifdef __cplusplus +} +#endif + +#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) + + /* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. + + Instead of doing + ANNOTATE_IGNORE_READS_BEGIN(); + ... = x; + ANNOTATE_IGNORE_READS_END(); + one can use + ... = ANNOTATE_UNPROTECTED_READ(x); */ + template <class T> + inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) { + ANNOTATE_IGNORE_READS_BEGIN(); + T res = x; + ANNOTATE_IGNORE_READS_END(); + return res; + } + /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ + #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ + namespace { \ + class static_var ## _annotator { \ + public: \ + static_var ## _annotator() { \ + ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ + sizeof(static_var), \ + # static_var ": " description); \ + } \ + }; \ + static static_var ## _annotator the ## static_var ## _annotator;\ + } +#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */ + + #define ANNOTATE_UNPROTECTED_READ(x) (x) + #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ + +#endif /* DYNAMIC_ANNOTATIONS_ENABLED */ + +#endif /* __DYNAMIC_ANNOTATIONS_H__ */ diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h new file mode 100644 index 000000000000..8382bbeb0179 --- /dev/null +++ b/base/threading/platform_thread.h @@ -0,0 +1,115 @@ +// 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. + +// WARNING: You should *NOT* be using this class directly. PlatformThread is +// the low-level platform-specific abstraction to the OS's threading interface. +// You should instead be using a message-loop driven Thread, see thread.h. + +#ifndef BASE_THREADING_PLATFORM_THREAD_H_ +#define BASE_THREADING_PLATFORM_THREAD_H_ +#pragma once + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(OS_POSIX) +#include <pthread.h> +#if defined(OS_MACOSX) +#include <mach/mach.h> +#else // OS_POSIX && !OS_MACOSX +#include <unistd.h> +#endif +#endif + +namespace base { + +// PlatformThreadHandle should not be assumed to be a numeric type, since the +// standard intends to allow pthread_t to be a structure. This means you +// should not initialize it to a value, like 0. If it's a member variable, the +// constructor can safely "value initialize" using () in the initializer list. +#if defined(OS_WIN) +typedef DWORD PlatformThreadId; +typedef void* PlatformThreadHandle; // HANDLE +const PlatformThreadHandle kNullThreadHandle = NULL; +#elif defined(OS_POSIX) +typedef pthread_t PlatformThreadHandle; +const PlatformThreadHandle kNullThreadHandle = 0; +#if defined(OS_MACOSX) +typedef mach_port_t PlatformThreadId; +#else // OS_POSIX && !OS_MACOSX +typedef pid_t PlatformThreadId; +#endif +#endif + +const PlatformThreadId kInvalidThreadId = 0; + +// Valid values for SetThreadPriority() +enum ThreadPriority{ + kThreadPriority_Normal, + // Suitable for low-latency, glitch-resistant audio. + kThreadPriority_RealtimeAudio +}; + +// A namespace for low-level thread functions. +class BASE_EXPORT PlatformThread { + public: + // Implement this interface to run code on a background thread. Your + // ThreadMain method will be called on the newly created thread. + class BASE_EXPORT Delegate { + public: + virtual ~Delegate() {} + virtual void ThreadMain() = 0; + }; + + // Gets the current thread id, which may be useful for logging purposes. + static PlatformThreadId CurrentId(); + + // Yield the current thread so another thread can be scheduled. + static void YieldCurrentThread(); + + // Sleeps for the specified duration (units are milliseconds). + static void Sleep(int duration_ms); + + // Sets the thread name visible to debuggers/tools. This has no effect + // otherwise. This name pointer is not copied internally. Thus, it must stay + // valid until the thread ends. + static void SetName(const char* name); + + // Gets the thread name, if previously set by SetName. + static const char* GetName(); + + // Creates a new thread. The |stack_size| parameter can be 0 to indicate + // that the default stack size should be used. Upon success, + // |*thread_handle| will be assigned a handle to the newly created thread, + // and |delegate|'s ThreadMain method will be executed on the newly created + // thread. + // NOTE: When you are done with the thread handle, you must call Join to + // release system resources associated with the thread. You must ensure that + // the Delegate object outlives the thread. + static bool Create(size_t stack_size, Delegate* delegate, + PlatformThreadHandle* thread_handle); + + // CreateNonJoinable() does the same thing as Create() except the thread + // cannot be Join()'d. Therefore, it also does not output a + // PlatformThreadHandle. + static bool CreateNonJoinable(size_t stack_size, Delegate* delegate); + + // Joins with a thread created via the Create function. This function blocks + // the caller until the designated thread exits. This will invalidate + // |thread_handle|. + static void Join(PlatformThreadHandle thread_handle); + + static void SetThreadPriority(PlatformThreadHandle handle, + ThreadPriority priority); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread); +}; + +} // namespace base + +#endif // BASE_THREADING_PLATFORM_THREAD_H_ diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc new file mode 100644 index 000000000000..c924a16d384c --- /dev/null +++ b/base/threading/platform_thread_posix.cc @@ -0,0 +1,262 @@ +// 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/threading/platform_thread.h" + +#include <errno.h> +#include <sched.h> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/safe_strerror_posix.h" +#include "base/threading/thread_local.h" +#include "base/threading/thread_restrictions.h" + +#if defined(OS_MACOSX) +#include <mach/mach.h> +#include <sys/resource.h> +#include <algorithm> +#endif + +#if defined(OS_LINUX) +#include <dlfcn.h> +#include <sys/prctl.h> +#include <sys/syscall.h> +#include <unistd.h> +#endif + +#if defined(OS_ANDROID) +#include "base/android/jni_android.h" +#endif + +#if defined(OS_NACL) +#include <sys/nacl_syscalls.h> +#endif + +namespace base { + +#if defined(OS_MACOSX) +void InitThreading(); +#endif + +namespace { + +static ThreadLocalPointer<char> current_thread_name; + +struct ThreadParams { + PlatformThread::Delegate* delegate; + bool joinable; +}; + +void* ThreadFunc(void* params) { + ThreadParams* thread_params = static_cast<ThreadParams*>(params); + PlatformThread::Delegate* delegate = thread_params->delegate; + if (!thread_params->joinable) + base::ThreadRestrictions::SetSingletonAllowed(false); + delete thread_params; + delegate->ThreadMain(); +#if defined(OS_ANDROID) + base::android::DetachFromVM(); +#endif + return NULL; +} + +bool CreateThread(size_t stack_size, bool joinable, + PlatformThread::Delegate* delegate, + PlatformThreadHandle* thread_handle) { +#if defined(OS_MACOSX) + base::InitThreading(); +#endif // OS_MACOSX + + bool success = false; + pthread_attr_t attributes; + pthread_attr_init(&attributes); + + // Pthreads are joinable by default, so only specify the detached attribute if + // the thread should be non-joinable. + if (!joinable) { + pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); + } + +#if defined(OS_MACOSX) + // The Mac OS X default for a pthread stack size is 512kB. + // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses + // DEFAULT_STACK_SIZE for this purpose. + // + // 512kB isn't quite generous enough for some deeply recursive threads that + // otherwise request the default stack size by specifying 0. Here, adopt + // glibc's behavior as on Linux, which is to use the current stack size + // limit (ulimit -s) as the default stack size. See + // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To + // avoid setting the limit below the Mac OS X default or the minimum usable + // stack size, these values are also considered. If any of these values + // can't be determined, or if stack size is unlimited (ulimit -s unlimited), + // stack_size is left at 0 to get the system default. + // + // Mac OS X normally only applies ulimit -s to the main thread stack. On + // contemporary OS X and Linux systems alike, this value is generally 8MB + // or in that neighborhood. + if (stack_size == 0) { + size_t default_stack_size; + struct rlimit stack_rlimit; + if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 && + getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 && + stack_rlimit.rlim_cur != RLIM_INFINITY) { + stack_size = std::max(std::max(default_stack_size, + static_cast<size_t>(PTHREAD_STACK_MIN)), + static_cast<size_t>(stack_rlimit.rlim_cur)); + } + } +#endif // OS_MACOSX + + if (stack_size > 0) + pthread_attr_setstacksize(&attributes, stack_size); + + ThreadParams* params = new ThreadParams; + params->delegate = delegate; + params->joinable = joinable; + success = !pthread_create(thread_handle, &attributes, ThreadFunc, params); + + pthread_attr_destroy(&attributes); + if (!success) + delete params; + return success; +} + +} // namespace + +// static +PlatformThreadId PlatformThread::CurrentId() { + // Pthreads doesn't have the concept of a thread ID, so we have to reach down + // into the kernel. +#if defined(OS_MACOSX) + return mach_thread_self(); +#elif defined(OS_LINUX) + return syscall(__NR_gettid); +#elif defined(OS_ANDROID) + return gettid(); +#elif defined(OS_FREEBSD) + // TODO(BSD): find a better thread ID + return reinterpret_cast<int64>(pthread_self()); +#elif defined(OS_NACL) || defined(OS_SOLARIS) + return pthread_self(); +#endif +} + +// static +void PlatformThread::YieldCurrentThread() { + sched_yield(); +} + +// static +void PlatformThread::Sleep(int duration_ms) { + struct timespec sleep_time, remaining; + + // Contains the portion of duration_ms >= 1 sec. + sleep_time.tv_sec = duration_ms / 1000; + duration_ms -= sleep_time.tv_sec * 1000; + + // Contains the portion of duration_ms < 1 sec. + sleep_time.tv_nsec = duration_ms * 1000 * 1000; // nanoseconds. + + while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) + sleep_time = remaining; +} + +// Linux SetName is currently disabled, as we need to distinguish between +// helper threads (where it's ok to make this call) and the main thread +// (where making this call renames our process, causing tools like killall +// to stop working). +#if 0 && defined(OS_LINUX) +// static +void PlatformThread::SetName(const char* name) { + // have to cast away const because ThreadLocalPointer does not support const + // void* + current_thread_name.Set(const_cast<char*>(name)); + + // http://0pointer.de/blog/projects/name-your-threads.html + + // glibc recently added support for pthread_setname_np, but it's not + // commonly available yet. So test for it at runtime. + int (*dynamic_pthread_setname_np)(pthread_t, const char*); + *reinterpret_cast<void**>(&dynamic_pthread_setname_np) = + dlsym(RTLD_DEFAULT, "pthread_setname_np"); + + if (dynamic_pthread_setname_np) { + // This limit comes from glibc, which gets it from the kernel + // (TASK_COMM_LEN). + const int kMaxNameLength = 15; + std::string shortened_name = std::string(name).substr(0, kMaxNameLength); + int err = dynamic_pthread_setname_np(pthread_self(), + shortened_name.c_str()); + if (err < 0) + LOG(ERROR) << "pthread_setname_np: " << safe_strerror(err); + } else { + // Implementing this function without glibc is simple enough. (We + // don't do the name length clipping as above because it will be + // truncated by the callee (see TASK_COMM_LEN above).) + int err = prctl(PR_SET_NAME, name); + if (err < 0) + PLOG(ERROR) << "prctl(PR_SET_NAME)"; + } +} +#elif defined(OS_MACOSX) +// Mac is implemented in platform_thread_mac.mm. +#else +// static +void PlatformThread::SetName(const char* name) { + // have to cast away const because ThreadLocalPointer does not support const + // void* + current_thread_name.Set(const_cast<char*>(name)); + + // (This should be relatively simple to implement for the BSDs; I + // just don't have one handy to test the code on.) +} +#endif // defined(OS_LINUX) + + +#if !defined(OS_MACOSX) +// Mac is implemented in platform_thread_mac.mm. +// static +const char* PlatformThread::GetName() { + return current_thread_name.Get(); +} +#endif + +// static +bool PlatformThread::Create(size_t stack_size, Delegate* delegate, + PlatformThreadHandle* thread_handle) { + return CreateThread(stack_size, true /* joinable thread */, + delegate, thread_handle); +} + +// static +bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { + PlatformThreadHandle unused; + + bool result = CreateThread(stack_size, false /* non-joinable thread */, + delegate, &unused); + return result; +} + +// static +void PlatformThread::Join(PlatformThreadHandle thread_handle) { + // Joining another thread may block the current thread for a long time, since + // the thread referred to by |thread_handle| may still be running long-lived / + // blocking tasks. + base::ThreadRestrictions::AssertIOAllowed(); + pthread_join(thread_handle, NULL); +} + +#if !defined(OS_MACOSX) +// Mac OS X uses lower-level mach APIs + +// static +void PlatformThread::SetThreadPriority(PlatformThreadHandle, ThreadPriority) { + // TODO(crogers): implement + NOTIMPLEMENTED(); +} +#endif + +} // namespace base diff --git a/base/threading/thread.cc b/base/threading/thread.cc new file mode 100644 index 000000000000..616aac8933a5 --- /dev/null +++ b/base/threading/thread.cc @@ -0,0 +1,177 @@ +// 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/threading/thread.h" + +#include "base/lazy_instance.h" +#include "base/third_party/dynamic_annotations/dynamic_annotations.h" +#include "base/threading/thread_local.h" +#include "base/synchronization/waitable_event.h" + +namespace base { + +namespace { + +// We use this thread-local variable to record whether or not a thread exited +// because its Stop method was called. This allows us to catch cases where +// MessageLoop::Quit() is called directly, which is unexpected when using a +// Thread to setup and run a MessageLoop. +base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool( + base::LINKER_INITIALIZED); + +} // namespace + +// This task is used to trigger the message loop to exit. +class ThreadQuitTask : public Task { + public: + virtual void Run() { + MessageLoop::current()->Quit(); + Thread::SetThreadWasQuitProperly(true); + } +}; + +// Used to pass data to ThreadMain. This structure is allocated on the stack +// from within StartWithOptions. +struct Thread::StartupData { + // We get away with a const reference here because of how we are allocated. + const Thread::Options& options; + + // Used to synchronize thread startup. + WaitableEvent event; + + explicit StartupData(const Options& opt) + : options(opt), + event(false, false) {} +}; + +Thread::Thread(const char* name) + : started_(false), + stopping_(false), + startup_data_(NULL), + thread_(0), + message_loop_(NULL), + thread_id_(kInvalidThreadId), + name_(name) { +} + +Thread::~Thread() { + Stop(); +} + +bool Thread::Start() { + return StartWithOptions(Options()); +} + +bool Thread::StartWithOptions(const Options& options) { + DCHECK(!message_loop_); + + SetThreadWasQuitProperly(false); + + StartupData startup_data(options); + startup_data_ = &startup_data; + + if (!PlatformThread::Create(options.stack_size, this, &thread_)) { + DLOG(ERROR) << "failed to create thread"; + startup_data_ = NULL; + return false; + } + + // Wait for the thread to start and initialize message_loop_ + startup_data.event.Wait(); + + // set it to NULL so we don't keep a pointer to some object on the stack. + startup_data_ = NULL; + started_ = true; + + DCHECK(message_loop_); + return true; +} + +void Thread::Stop() { + if (!thread_was_started()) + return; + + StopSoon(); + + // Wait for the thread to exit. + // + // TODO(darin): Unfortunately, we need to keep message_loop_ around until + // the thread exits. Some consumers are abusing the API. Make them stop. + // + PlatformThread::Join(thread_); + + // The thread should NULL message_loop_ on exit. + DCHECK(!message_loop_); + + // The thread no longer needs to be joined. + started_ = false; + + stopping_ = false; +} + +void Thread::StopSoon() { + // We should only be called on the same thread that started us. + + // Reading thread_id_ without a lock can lead to a benign data race + // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer. + DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId()); + + if (stopping_ || !message_loop_) + return; + + stopping_ = true; + message_loop_->PostTask(FROM_HERE, new ThreadQuitTask()); +} + +void Thread::Run(MessageLoop* message_loop) { + message_loop->Run(); +} + +void Thread::SetThreadWasQuitProperly(bool flag) { + lazy_tls_bool.Pointer()->Set(flag); +} + +bool Thread::GetThreadWasQuitProperly() { + bool quit_properly = true; +#ifndef NDEBUG + quit_properly = lazy_tls_bool.Pointer()->Get(); +#endif + return quit_properly; +} + +void Thread::ThreadMain() { + { + // The message loop for this thread. + MessageLoop message_loop(startup_data_->options.message_loop_type); + + // Complete the initialization of our Thread object. + thread_id_ = PlatformThread::CurrentId(); + PlatformThread::SetName(name_.c_str()); + ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. + message_loop.set_thread_name(name_); + message_loop_ = &message_loop; + + // Let the thread do extra initialization. + // Let's do this before signaling we are started. + Init(); + + startup_data_->event.Signal(); + // startup_data_ can't be touched anymore since the starting thread is now + // unlocked. + + Run(message_loop_); + + // Let the thread do extra cleanup. + CleanUp(); + + // Assert that MessageLoop::Quit was called by ThreadQuitTask. + DCHECK(GetThreadWasQuitProperly()); + + // We can't receive messages anymore. + message_loop_ = NULL; + } + thread_id_ = kInvalidThreadId; +} + +} // namespace base diff --git a/base/threading/thread.h b/base/threading/thread.h new file mode 100644 index 000000000000..d7451ec58ab9 --- /dev/null +++ b/base/threading/thread.h @@ -0,0 +1,191 @@ +// 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_THREAD_H_ +#define BASE_THREAD_H_ +#pragma once + +#include <string> + +#include "base/base_export.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/threading/platform_thread.h" + +namespace base { + +// A simple thread abstraction that establishes a MessageLoop on a new thread. +// The consumer uses the MessageLoop of the thread to cause code to execute on +// the thread. When this object is destroyed the thread is terminated. All +// pending tasks queued on the thread's message loop will run to completion +// before the thread is terminated. +// +// After the thread is stopped, the destruction sequence is: +// +// (1) Thread::CleanUp() +// (2) MessageLoop::~MessageLoop +// (3.b) MessageLoop::DestructionObserver::WillDestroyCurrentMessageLoop +class BASE_EXPORT Thread : PlatformThread::Delegate { + public: + struct Options { + Options() : message_loop_type(MessageLoop::TYPE_DEFAULT), stack_size(0) {} + Options(MessageLoop::Type type, size_t size) + : message_loop_type(type), stack_size(size) {} + + // Specifies the type of message loop that will be allocated on the thread. + MessageLoop::Type message_loop_type; + + // Specifies the maximum stack size that the thread is allowed to use. + // This does not necessarily correspond to the thread's initial stack size. + // A value of 0 indicates that the default maximum should be used. + size_t stack_size; + }; + + // Constructor. + // name is a display string to identify the thread. + explicit Thread(const char* name); + + // Destroys the thread, stopping it if necessary. + // + // NOTE: If you are subclassing from Thread, and you wish for your CleanUp + // method to be called, then you need to call Stop() from your destructor. + // + virtual ~Thread(); + + // Starts the thread. Returns true if the thread was successfully started; + // otherwise, returns false. Upon successful return, the message_loop() + // getter will return non-null. + // + // Note: This function can't be called on Windows with the loader lock held; + // i.e. during a DllMain, global object construction or destruction, atexit() + // callback. + bool Start(); + + // Starts the thread. Behaves exactly like Start in addition to allow to + // override the default options. + // + // Note: This function can't be called on Windows with the loader lock held; + // i.e. during a DllMain, global object construction or destruction, atexit() + // callback. + bool StartWithOptions(const Options& options); + + // Signals the thread to exit and returns once the thread has exited. After + // this method returns, the Thread object is completely reset and may be used + // as if it were newly constructed (i.e., Start may be called again). + // + // Stop may be called multiple times and is simply ignored if the thread is + // already stopped. + // + // NOTE: This method is optional. It is not strictly necessary to call this + // method as the Thread's destructor will take care of stopping the thread if + // necessary. + // + void Stop(); + + // Signals the thread to exit in the near future. + // + // WARNING: This function is not meant to be commonly used. Use at your own + // risk. Calling this function will cause message_loop() to become invalid in + // the near future. This function was created to workaround a specific + // deadlock on Windows with printer worker thread. In any other case, Stop() + // should be used. + // + // StopSoon should not be called multiple times as it is risky to do so. It + // could cause a timing issue in message_loop() access. Call Stop() to reset + // the thread object once it is known that the thread has quit. + void StopSoon(); + + // Returns the message loop for this thread. Use the MessageLoop's + // PostTask methods to execute code on the thread. This only returns + // non-null after a successful call to Start. After Stop has been called, + // this will return NULL. + // + // NOTE: You must not call this MessageLoop's Quit method directly. Use + // the Thread's Stop method instead. + // + MessageLoop* message_loop() const { return message_loop_; } + + // Returns a MessageLoopProxy for this thread. Use the MessageLoopProxy's + // PostTask methods to execute code on the thread. This only returns + // non-NULL after a successful call to Start. After Stop has been called, + // this will return NULL. Callers can hold on to this even after the thread + // is gone. + // TODO(sanjeevr): Look into merging MessageLoop and MessageLoopProxy. + scoped_refptr<MessageLoopProxy> message_loop_proxy() const { + return message_loop_->message_loop_proxy(); + } + + // Set the name of this thread (for display in debugger too). + const std::string &thread_name() { return name_; } + + // The native thread handle. + PlatformThreadHandle thread_handle() { return thread_; } + + // The thread ID. + PlatformThreadId thread_id() const { return thread_id_; } + + // Returns true if the thread has been started, and not yet stopped. + // When a thread is running, |thread_id_| is a valid id. + bool IsRunning() const { return thread_id_ != kInvalidThreadId; } + + protected: + // Called just prior to starting the message loop + virtual void Init() {} + + // Called to start the message loop + virtual void Run(MessageLoop* message_loop); + + // Called just after the message loop ends + virtual void CleanUp() {} + + // Called after the message loop has been deleted. In general clients + // should prefer to use CleanUp(). This method is used when code needs to + // be run after all of the MessageLoop::DestructionObservers have completed. + virtual void CleanUpAfterMessageLoopDestruction() {} + + static void SetThreadWasQuitProperly(bool flag); + static bool GetThreadWasQuitProperly(); + + void set_message_loop(MessageLoop* message_loop) { + message_loop_ = message_loop; + } + + private: + bool thread_was_started() const { return started_; } + + // PlatformThread::Delegate methods: + virtual void ThreadMain(); + + // Whether we successfully started the thread. + bool started_; + + // If true, we're in the middle of stopping, and shouldn't access + // |message_loop_|. It may non-NULL and invalid. + bool stopping_; + + // Used to pass data to ThreadMain. + struct StartupData; + StartupData* startup_data_; + + // The thread's handle. + PlatformThreadHandle thread_; + + // The thread's message loop. Valid only while the thread is alive. Set + // by the created thread. + MessageLoop* message_loop_; + + // Our thread's ID. + PlatformThreadId thread_id_; + + // The name of the thread. Used for debugging purposes. + std::string name_; + + friend class ThreadQuitTask; + + DISALLOW_COPY_AND_ASSIGN(Thread); +}; + +} // namespace base + +#endif // BASE_THREAD_H_ diff --git a/base/threading/thread_collision_warner.cc b/base/threading/thread_collision_warner.cc new file mode 100644 index 000000000000..547e11ca66f9 --- /dev/null +++ b/base/threading/thread_collision_warner.cc @@ -0,0 +1,64 @@ +// 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. + +#include "base/threading/thread_collision_warner.h" + +#include "base/logging.h" +#include "base/threading/platform_thread.h" + +namespace base { + +void DCheckAsserter::warn() { + NOTREACHED() << "Thread Collision"; +} + +static subtle::Atomic32 CurrentThread() { + const PlatformThreadId current_thread_id = PlatformThread::CurrentId(); + // We need to get the thread id into an atomic data type. This might be a + // truncating conversion, but any loss-of-information just increases the + // chance of a fault negative, not a false positive. + const subtle::Atomic32 atomic_thread_id = + static_cast<subtle::Atomic32>(current_thread_id); + + return atomic_thread_id; +} + +void ThreadCollisionWarner::EnterSelf() { + // If the active thread is 0 then I'll write the current thread ID + // if two or more threads arrive here only one will succeed to + // write on valid_thread_id_ the current thread ID. + subtle::Atomic32 current_thread_id = CurrentThread(); + + int previous_value = subtle::NoBarrier_CompareAndSwap(&valid_thread_id_, + 0, + current_thread_id); + if (previous_value != 0 && previous_value != current_thread_id) { + // gotcha! a thread is trying to use the same class and that is + // not current thread. + asserter_->warn(); + } + + subtle::NoBarrier_AtomicIncrement(&counter_, 1); +} + +void ThreadCollisionWarner::Enter() { + subtle::Atomic32 current_thread_id = CurrentThread(); + + if (subtle::NoBarrier_CompareAndSwap(&valid_thread_id_, + 0, + current_thread_id) != 0) { + // gotcha! another thread is trying to use the same class. + asserter_->warn(); + } + + subtle::NoBarrier_AtomicIncrement(&counter_, 1); +} + +void ThreadCollisionWarner::Leave() { + if (subtle::Barrier_AtomicIncrement(&counter_, -1) == 0) { + subtle::NoBarrier_Store(&valid_thread_id_, 0); + } +} + +} // namespace base diff --git a/base/threading/thread_collision_warner.h b/base/threading/thread_collision_warner.h new file mode 100644 index 000000000000..4460602c6c40 --- /dev/null +++ b/base/threading/thread_collision_warner.h @@ -0,0 +1,244 @@ +// 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_THREADING_THREAD_COLLISION_WARNER_H_ +#define BASE_THREADING_THREAD_COLLISION_WARNER_H_ +#pragma once + +#include <memory> + +#include "base/base_export.h" +#include "base/atomicops.h" + +// A helper class alongside macros to be used to verify assumptions about thread +// safety of a class. +// +// Example: Queue implementation non thread-safe but still usable if clients +// are synchronized somehow. +// +// In this case the macro DFAKE_SCOPED_LOCK has to be +// used, it checks that if a thread is inside the push/pop then +// noone else is still inside the pop/push +// +// class NonThreadSafeQueue { +// public: +// ... +// void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... } +// int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... } +// ... +// private: +// DFAKE_MUTEX(push_pop_); +// }; +// +// +// Example: Queue implementation non thread-safe but still usable if clients +// are synchronized somehow, it calls a method to "protect" from +// a "protected" method +// +// In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK +// has to be used, it checks that if a thread is inside the push/pop +// then noone else is still inside the pop/push +// +// class NonThreadSafeQueue { +// public: +// void push(int) { +// DFAKE_SCOPED_LOCK(push_pop_); +// ... +// } +// int pop() { +// DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); +// bar(); +// ... +// } +// void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... } +// ... +// private: +// DFAKE_MUTEX(push_pop_); +// }; +// +// +// Example: Queue implementation not usable even if clients are synchronized, +// so only one thread in the class life cycle can use the two members +// push/pop. +// +// In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the +// specified +// critical section the first time a thread enters push or pop, from +// that time on only that thread is allowed to execute push or pop. +// +// class NonThreadSafeQueue { +// public: +// ... +// void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } +// int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } +// ... +// private: +// DFAKE_MUTEX(push_pop_); +// }; +// +// +// Example: Class that has to be contructed/destroyed on same thread, it has +// a "shareable" method (with external syncronization) and a not +// shareable method (even with external synchronization). +// +// In this case 3 Critical sections have to be defined +// +// class ExoticClass { +// public: +// ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } +// ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } +// +// void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... } +// void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } +// ... +// private: +// DFAKE_MUTEX(ctor_dtor_); +// DFAKE_MUTEX(shareable_section_); +// }; + + +#if !defined(NDEBUG) + +// Defines a class member that acts like a mutex. It is used only as a +// verification tool. +#define DFAKE_MUTEX(obj) \ + mutable base::ThreadCollisionWarner obj +// Asserts the call is never called simultaneously in two threads. Used at +// member function scope. +#define DFAKE_SCOPED_LOCK(obj) \ + base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj) +// Asserts the call is never called simultaneously in two threads. Used at +// member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks. +#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \ + base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj) +// Asserts the code is always executed in the same thread. +#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \ + base::ThreadCollisionWarner::Check check_##obj(&obj) + +#else + +#define DFAKE_MUTEX(obj) +#define DFAKE_SCOPED_LOCK(obj) ((void)0) +#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0) +#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0) + +#endif + +namespace base { + +// The class ThreadCollisionWarner uses an Asserter to notify the collision +// AsserterBase is the interfaces and DCheckAsserter is the default asserter +// used. During the unit tests is used another class that doesn't "DCHECK" +// in case of collision (check thread_collision_warner_unittests.cc) +struct BASE_EXPORT AsserterBase { + virtual ~AsserterBase() {} + virtual void warn() = 0; +}; + +struct BASE_EXPORT DCheckAsserter : public AsserterBase { + virtual ~DCheckAsserter() {} + virtual void warn(); +}; + +class BASE_EXPORT ThreadCollisionWarner { + public: + // The parameter asserter is there only for test purpose + ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter()) + : valid_thread_id_(0), + counter_(0), + asserter_(asserter) {} + + ~ThreadCollisionWarner() { + delete asserter_; + } + + // This class is meant to be used through the macro + // DFAKE_SCOPED_LOCK_THREAD_LOCKED + // it doesn't leave the critical section, as opposed to ScopedCheck, + // because the critical section being pinned is allowed to be used only + // from one thread + class BASE_EXPORT Check { + public: + explicit Check(ThreadCollisionWarner* warner) + : warner_(warner) { + warner_->EnterSelf(); + } + + ~Check() {} + + private: + ThreadCollisionWarner* warner_; + + DISALLOW_COPY_AND_ASSIGN(Check); + }; + + // This class is meant to be used through the macro + // DFAKE_SCOPED_LOCK + class BASE_EXPORT ScopedCheck { + public: + explicit ScopedCheck(ThreadCollisionWarner* warner) + : warner_(warner) { + warner_->Enter(); + } + + ~ScopedCheck() { + warner_->Leave(); + } + + private: + ThreadCollisionWarner* warner_; + + DISALLOW_COPY_AND_ASSIGN(ScopedCheck); + }; + + // This class is meant to be used through the macro + // DFAKE_SCOPED_RECURSIVE_LOCK + class BASE_EXPORT ScopedRecursiveCheck { + public: + explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner) + : warner_(warner) { + warner_->EnterSelf(); + } + + ~ScopedRecursiveCheck() { + warner_->Leave(); + } + + private: + ThreadCollisionWarner* warner_; + + DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck); + }; + + private: + // This method stores the current thread identifier and does a DCHECK + // if a another thread has already done it, it is safe if same thread + // calls this multiple time (recursion allowed). + void EnterSelf(); + + // Same as EnterSelf but recursion is not allowed. + void Enter(); + + // Removes the thread_id stored in order to allow other threads to + // call EnterSelf or Enter. + void Leave(); + + // This stores the thread id that is inside the critical section, if the + // value is 0 then no thread is inside. + volatile subtle::Atomic32 valid_thread_id_; + + // Counter to trace how many time a critical section was "pinned" + // (when allowed) in order to unpin it when counter_ reaches 0. + volatile subtle::Atomic32 counter_; + + // Here only for class unit tests purpose, during the test I need to not + // DCHECK but notify the collision with something else. + AsserterBase* asserter_; + + DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner); +}; + +} // namespace base + +#endif // BASE_THREADING_THREAD_COLLISION_WARNER_H_ diff --git a/base/time.h b/base/time.h new file mode 100644 index 000000000000..aa97f0ab4f42 --- /dev/null +++ b/base/time.h @@ -0,0 +1,566 @@ +// 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. + +// Time represents an absolute point in time, internally represented as +// microseconds (s/1,000,000) since a platform-dependent epoch. Each +// platform's epoch, along with other system-dependent clock interface +// routines, is defined in time_PLATFORM.cc. +// +// TimeDelta represents a duration of time, internally represented in +// microseconds. +// +// TimeTicks represents an abstract time that is always incrementing for use +// in measuring time durations. It is internally represented in microseconds. +// It can not be converted to a human-readable time, but is guaranteed not to +// decrease (if the user changes the computer clock, Time::Now() may actually +// decrease or jump). +// +// These classes are represented as only a 64-bit value, so they can be +// efficiently passed by value. + +#ifndef BASE_TIME_H_ +#define BASE_TIME_H_ +#pragma once + +#include <time.h> + +#include "base/atomicops.h" +#include "base/base_export.h" +#include "base/basictypes.h" + +#if defined(OS_POSIX) +// For struct timeval. +#include <sys/time.h> +#endif + +#if defined(OS_WIN) +// For FILETIME in FromFileTime, until it moves to a new converter class. +// See TODO(iyengar) below. +#include <windows.h> +#endif + +namespace base { + +class Time; +class TimeTicks; + +// TimeDelta ------------------------------------------------------------------ + +class BASE_EXPORT TimeDelta { + public: + TimeDelta() : delta_(0) { + } + + // Converts units of time to TimeDeltas. + static TimeDelta FromDays(int64 days); + static TimeDelta FromHours(int64 hours); + static TimeDelta FromMinutes(int64 minutes); + static TimeDelta FromSeconds(int64 secs); + static TimeDelta FromMilliseconds(int64 ms); + static TimeDelta FromMicroseconds(int64 us); + + // Returns the internal numeric value of the TimeDelta object. Please don't + // use this and do arithmetic on it, as it is more error prone than using the + // provided operators. + int64 ToInternalValue() const { + return delta_; + } + +#if defined(OS_POSIX) + struct timespec ToTimeSpec() const; +#endif + + // Returns the time delta in some unit. The F versions return a floating + // point value, the "regular" versions return a rounded-down value. + // + // InMillisecondsRoundedUp() instead returns an integer that is rounded up + // to the next full millisecond. + int InDays() const; + int InHours() const; + int InMinutes() const; + double InSecondsF() const; + int64 InSeconds() const; + double InMillisecondsF() const; + int64 InMilliseconds() const; + int64 InMillisecondsRoundedUp() const; + int64 InMicroseconds() const; + + TimeDelta& operator=(TimeDelta other) { + delta_ = other.delta_; + return *this; + } + + // Computations with other deltas. + TimeDelta operator+(TimeDelta other) const { + return TimeDelta(delta_ + other.delta_); + } + TimeDelta operator-(TimeDelta other) const { + return TimeDelta(delta_ - other.delta_); + } + + TimeDelta& operator+=(TimeDelta other) { + delta_ += other.delta_; + return *this; + } + TimeDelta& operator-=(TimeDelta other) { + delta_ -= other.delta_; + return *this; + } + TimeDelta operator-() const { + return TimeDelta(-delta_); + } + + // Computations with ints, note that we only allow multiplicative operations + // with ints, and additive operations with other deltas. + TimeDelta operator*(int64 a) const { + return TimeDelta(delta_ * a); + } + TimeDelta operator/(int64 a) const { + return TimeDelta(delta_ / a); + } + TimeDelta& operator*=(int64 a) { + delta_ *= a; + return *this; + } + TimeDelta& operator/=(int64 a) { + delta_ /= a; + return *this; + } + int64 operator/(TimeDelta a) const { + return delta_ / a.delta_; + } + + // Defined below because it depends on the definition of the other classes. + Time operator+(Time t) const; + TimeTicks operator+(TimeTicks t) const; + + // Comparison operators. + bool operator==(TimeDelta other) const { + return delta_ == other.delta_; + } + bool operator!=(TimeDelta other) const { + return delta_ != other.delta_; + } + bool operator<(TimeDelta other) const { + return delta_ < other.delta_; + } + bool operator<=(TimeDelta other) const { + return delta_ <= other.delta_; + } + bool operator>(TimeDelta other) const { + return delta_ > other.delta_; + } + bool operator>=(TimeDelta other) const { + return delta_ >= other.delta_; + } + + private: + friend class Time; + friend class TimeTicks; + friend TimeDelta operator*(int64 a, TimeDelta td); + + // Constructs a delta given the duration in microseconds. This is private + // to avoid confusion by callers with an integer constructor. Use + // FromSeconds, FromMilliseconds, etc. instead. + explicit TimeDelta(int64 delta_us) : delta_(delta_us) { + } + + // Delta in microseconds. + int64 delta_; +}; + +inline TimeDelta operator*(int64 a, TimeDelta td) { + return TimeDelta(a * td.delta_); +} + +// Time ----------------------------------------------------------------------- + +// Represents a wall clock time. +class BASE_EXPORT Time { + public: + static const int64 kMillisecondsPerSecond = 1000; + static const int64 kMicrosecondsPerMillisecond = 1000; + static const int64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond * + kMillisecondsPerSecond; + static const int64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60; + static const int64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60; + static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * 24; + static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7; + static const int64 kNanosecondsPerMicrosecond = 1000; + static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond * + kMicrosecondsPerSecond; + +#if !defined(OS_WIN) + // On Mac & Linux, this value is the delta from the Windows epoch of 1601 to + // the Posix delta of 1970. This is used for migrating between the old + // 1970-based epochs to the new 1601-based ones. It should be removed from + // this global header and put in the platform-specific ones when we remove the + // migration code. + static const int64 kWindowsEpochDeltaMicroseconds; +#endif + + // Represents an exploded time that can be formatted nicely. This is kind of + // like the Win32 SYSTEMTIME structure or the Unix "struct tm" with a few + // additions and changes to prevent errors. + struct BASE_EXPORT Exploded { + int year; // Four digit year "2007" + int month; // 1-based month (values 1 = January, etc.) + int day_of_week; // 0-based day of week (0 = Sunday, etc.) + int day_of_month; // 1-based day of month (1-31) + int hour; // Hour within the current day (0-23) + int minute; // Minute within the current hour (0-59) + int second; // Second within the current minute (0-59 plus leap + // seconds which may take it up to 60). + int millisecond; // Milliseconds within the current second (0-999) + + // A cursory test for whether the data members are within their + // respective ranges. A 'true' return value does not guarantee the + // Exploded value can be successfully converted to a Time value. + bool HasValidValues() const; + }; + + // Contains the NULL time. Use Time::Now() to get the current time. + explicit Time() : us_(0) { + } + + // Returns true if the time object has not been initialized. + bool is_null() const { + return us_ == 0; + } + + // Returns the time for epoch in Unix-like system (Jan 1, 1970). + static Time UnixEpoch(); + + // Returns the current time. Watch out, the system might adjust its clock + // in which case time will actually go backwards. We don't guarantee that + // times are increasing, or that two calls to Now() won't be the same. + static Time Now(); + + // Returns the current time. Same as Now() except that this function always + // uses system time so that there are no discrepancies between the returned + // time and system time even on virtual environments including our test bot. + // For timing sensitive unittests, this function should be used. + static Time NowFromSystemTime(); + + // Converts to/from time_t in UTC and a Time class. + // TODO(brettw) this should be removed once everybody starts using the |Time| + // class. + static Time FromTimeT(time_t tt); + time_t ToTimeT() const; + + // Converts time to/from a double which is the number of seconds since epoch + // (Jan 1, 1970). Webkit uses this format to represent time. + // Because WebKit initializes double time value to 0 to indicate "not + // initialized", we map it to empty Time object that also means "not + // initialized". + static Time FromDoubleT(double dt); + double ToDoubleT() const; + +#if defined(OS_POSIX) + struct timeval ToTimeVal() const; +#endif + +#if defined(OS_WIN) + static Time FromFileTime(FILETIME ft); + FILETIME ToFileTime() const; + + // The minimum time of a low resolution timer. This is basically a windows + // constant of ~15.6ms. While it does vary on some older OS versions, we'll + // treat it as static across all windows versions. + static const int kMinLowResolutionThresholdMs = 16; + + // Enable or disable Windows high resolution timer. If the high resolution + // timer is not enabled, calls to ActivateHighResolutionTimer will fail. + // When disabling the high resolution timer, this function will not cause + // the high resolution timer to be deactivated, but will prevent future + // activations. + // Must be called from the main thread. + // For more details see comments in time_win.cc. + static void EnableHighResolutionTimer(bool enable); + + // Activates or deactivates the high resolution timer based on the |activate| + // flag. If the HighResolutionTimer is not Enabled (see + // EnableHighResolutionTimer), this function will return false. Otherwise + // returns true. Each successful activate call must be paired with a + // subsequent deactivate call. + // All callers to activate the high resolution timer must eventually call + // this function to deactivate the high resolution timer. + static bool ActivateHighResolutionTimer(bool activate); + + // Returns true if the high resolution timer is both enabled and activated. + // This is provided for testing only, and is not tracked in a thread-safe + // way. + static bool IsHighResolutionTimerInUse(); +#endif + + // Converts an exploded structure representing either the local time or UTC + // into a Time class. + static Time FromUTCExploded(const Exploded& exploded) { + return FromExploded(false, exploded); + } + static Time FromLocalExploded(const Exploded& exploded) { + return FromExploded(true, exploded); + } + + // Converts an integer value representing Time to a class. This is used + // when deserializing a |Time| structure, using a value known to be + // compatible. It is not provided as a constructor because the integer type + // may be unclear from the perspective of a caller. + static Time FromInternalValue(int64 us) { + return Time(us); + } + + // Converts a string representation of time to a Time object. + // An example of a time string which is converted is as below:- + // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified + // in the input string, we assume local time. + // TODO(iyengar) Move the FromString/FromTimeT/ToTimeT/FromFileTime to + // a new time converter class. + static bool FromString(const char* time_string, Time* parsed_time); + + // For serializing, use FromInternalValue to reconstitute. Please don't use + // this and do arithmetic on it, as it is more error prone than using the + // provided operators. + int64 ToInternalValue() const { + return us_; + } + + // Fills the given exploded structure with either the local time or UTC from + // this time structure (containing UTC). + void UTCExplode(Exploded* exploded) const { + return Explode(false, exploded); + } + void LocalExplode(Exploded* exploded) const { + return Explode(true, exploded); + } + + // Rounds this time down to the nearest day in local time. It will represent + // midnight on that day. + Time LocalMidnight() const; + + Time& operator=(Time other) { + us_ = other.us_; + return *this; + } + + // Compute the difference between two times. + TimeDelta operator-(Time other) const { + return TimeDelta(us_ - other.us_); + } + + // Modify by some time delta. + Time& operator+=(TimeDelta delta) { + us_ += delta.delta_; + return *this; + } + Time& operator-=(TimeDelta delta) { + us_ -= delta.delta_; + return *this; + } + + // Return a new time modified by some delta. + Time operator+(TimeDelta delta) const { + return Time(us_ + delta.delta_); + } + Time operator-(TimeDelta delta) const { + return Time(us_ - delta.delta_); + } + + // Comparison operators + bool operator==(Time other) const { + return us_ == other.us_; + } + bool operator!=(Time other) const { + return us_ != other.us_; + } + bool operator<(Time other) const { + return us_ < other.us_; + } + bool operator<=(Time other) const { + return us_ <= other.us_; + } + bool operator>(Time other) const { + return us_ > other.us_; + } + bool operator>=(Time other) const { + return us_ >= other.us_; + } + + private: + friend class TimeDelta; + + explicit Time(int64 us) : us_(us) { + } + + // Explodes the given time to either local time |is_local = true| or UTC + // |is_local = false|. + void Explode(bool is_local, Exploded* exploded) const; + + // Unexplodes a given time assuming the source is either local time + // |is_local = true| or UTC |is_local = false|. + static Time FromExploded(bool is_local, const Exploded& exploded); + + // The representation of Jan 1, 1970 UTC in microseconds since the + // platform-dependent epoch. + static const int64 kTimeTToMicrosecondsOffset; + +#if defined(OS_WIN) + // Indicates whether fast timers are usable right now. For instance, + // when using battery power, we might elect to prevent high speed timers + // which would draw more power. + static bool high_resolution_timer_enabled_; + // Count of activations on the high resolution timer. Only use in tests + // which are single threaded. + static int high_resolution_timer_activated_; +#endif + + // Time in microseconds in UTC. + int64 us_; +}; + +// Inline the TimeDelta factory methods, for fast TimeDelta construction. + +// static +inline TimeDelta TimeDelta::FromDays(int64 days) { + return TimeDelta(days * Time::kMicrosecondsPerDay); +} + +// static +inline TimeDelta TimeDelta::FromHours(int64 hours) { + return TimeDelta(hours * Time::kMicrosecondsPerHour); +} + +// static +inline TimeDelta TimeDelta::FromMinutes(int64 minutes) { + return TimeDelta(minutes * Time::kMicrosecondsPerMinute); +} + +// static +inline TimeDelta TimeDelta::FromSeconds(int64 secs) { + return TimeDelta(secs * Time::kMicrosecondsPerSecond); +} + +// static +inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) { + return TimeDelta(ms * Time::kMicrosecondsPerMillisecond); +} + +// static +inline TimeDelta TimeDelta::FromMicroseconds(int64 us) { + return TimeDelta(us); +} + +inline Time TimeDelta::operator+(Time t) const { + return Time(t.us_ + delta_); +} + +// TimeTicks ------------------------------------------------------------------ + +class BASE_EXPORT TimeTicks { + public: + TimeTicks() : ticks_(0) { + } + + // Platform-dependent tick count representing "right now." + // The resolution of this clock is ~1-15ms. Resolution varies depending + // on hardware/operating system configuration. + static TimeTicks Now(); + + // Returns a platform-dependent high-resolution tick count. Implementation + // is hardware dependent and may or may not return sub-millisecond + // resolution. THIS CALL IS GENERALLY MUCH MORE EXPENSIVE THAN Now() AND + // SHOULD ONLY BE USED WHEN IT IS REALLY NEEDED. + static TimeTicks HighResNow(); + +#if defined(OS_WIN) + // Get the absolute value of QPC time drift. For testing. + static int64 GetQPCDriftMicroseconds(); + + // Returns true if the high resolution clock is working on this system. + // This is only for testing. + static bool IsHighResClockWorking(); +#endif + + // Returns true if this object has not been initialized. + bool is_null() const { + return ticks_ == 0; + } + + // Returns the internal numeric value of the TimeTicks object. + int64 ToInternalValue() const { + return ticks_; + } + + TimeTicks& operator=(TimeTicks other) { + ticks_ = other.ticks_; + return *this; + } + + // Compute the difference between two times. + TimeDelta operator-(TimeTicks other) const { + return TimeDelta(ticks_ - other.ticks_); + } + + // Modify by some time delta. + TimeTicks& operator+=(TimeDelta delta) { + ticks_ += delta.delta_; + return *this; + } + TimeTicks& operator-=(TimeDelta delta) { + ticks_ -= delta.delta_; + return *this; + } + + // Return a new TimeTicks modified by some delta. + TimeTicks operator+(TimeDelta delta) const { + return TimeTicks(ticks_ + delta.delta_); + } + TimeTicks operator-(TimeDelta delta) const { + return TimeTicks(ticks_ - delta.delta_); + } + + // Comparison operators + bool operator==(TimeTicks other) const { + return ticks_ == other.ticks_; + } + bool operator!=(TimeTicks other) const { + return ticks_ != other.ticks_; + } + bool operator<(TimeTicks other) const { + return ticks_ < other.ticks_; + } + bool operator<=(TimeTicks other) const { + return ticks_ <= other.ticks_; + } + bool operator>(TimeTicks other) const { + return ticks_ > other.ticks_; + } + bool operator>=(TimeTicks other) const { + return ticks_ >= other.ticks_; + } + + protected: + friend class TimeDelta; + + // Please use Now() to create a new object. This is for internal use + // and testing. Ticks is in microseconds. + explicit TimeTicks(int64 ticks) : ticks_(ticks) { + } + + // Tick count in microseconds. + int64 ticks_; + +#if defined(OS_WIN) + typedef DWORD (*TickFunctionType)(void); + static TickFunctionType SetMockTickFunction(TickFunctionType ticker); +#endif +}; + +inline TimeTicks TimeDelta::operator+(TimeTicks t) const { + return TimeTicks(t.ticks_ + delta_); +} + +} // namespace base + +#endif // BASE_TIME_H_ diff --git a/base/tuple.h b/base/tuple.h new file mode 100644 index 000000000000..65d0908a0fad --- /dev/null +++ b/base/tuple.h @@ -0,0 +1,1056 @@ +// 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. + +// A Tuple is a generic templatized container, similar in concept to std::pair. +// There are classes Tuple0 to Tuple6, cooresponding to the number of elements +// it contains. The convenient MakeTuple() function takes 0 to 6 arguments, +// and will construct and return the appropriate Tuple object. The functions +// DispatchToMethod and DispatchToFunction take a function pointer or instance +// and method pointer, and unpack a tuple into arguments to the call. +// +// Tuple elements are copied by value, and stored in the tuple. See the unit +// tests for more details of how/when the values are copied. +// +// Example usage: +// // These two methods of creating a Tuple are identical. +// Tuple2<int, const char*> tuple_a(1, "wee"); +// Tuple2<int, const char*> tuple_b = MakeTuple(1, "wee"); +// +// void SomeFunc(int a, const char* b) { } +// DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee") +// DispatchToFunction( +// &SomeFunc, MakeTuple(10, "foo")); // SomeFunc(10, "foo") +// +// struct { void SomeMeth(int a, int b, int c) { } } foo; +// DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3)); +// // foo->SomeMeth(1, 2, 3); + +#ifndef BASE_TUPLE_H__ +#define BASE_TUPLE_H__ +#pragma once + +#if defined(OS_CHROMEOS) +// To troubleshoot crosbug.com/7327. +#include "base/logging.h" +#endif +// Traits ---------------------------------------------------------------------- +// +// A simple traits class for tuple arguments. +// +// ValueType: the bare, nonref version of a type (same as the type for nonrefs). +// RefType: the ref version of a type (same as the type for refs). +// ParamType: what type to pass to functions (refs should not be constified). + +template <class P> +struct TupleTraits { + typedef P ValueType; + typedef P& RefType; + typedef const P& ParamType; +}; + +template <class P> +struct TupleTraits<P&> { + typedef P ValueType; + typedef P& RefType; + typedef P& ParamType; +}; + +template <class P> +struct TupleTypes { }; + +// Tuple ----------------------------------------------------------------------- +// +// This set of classes is useful for bundling 0 or more heterogeneous data types +// into a single variable. The advantage of this is that it greatly simplifies +// function objects that need to take an arbitrary number of parameters; see +// RunnableMethod and IPC::MessageWithTuple. +// +// Tuple0 is supplied to act as a 'void' type. It can be used, for example, +// when dispatching to a function that accepts no arguments (see the +// Dispatchers below). +// Tuple1<A> is rarely useful. One such use is when A is non-const ref that you +// want filled by the dispatchee, and the tuple is merely a container for that +// output (a "tier"). See MakeRefTuple and its usages. + +struct Tuple0 { + typedef Tuple0 ValueTuple; + typedef Tuple0 RefTuple; + typedef Tuple0 ParamTuple; +}; + +template <class A> +struct Tuple1 { + public: + typedef A TypeA; + + Tuple1() {} + explicit Tuple1(typename TupleTraits<A>::ParamType a) : a(a) {} + + A a; +}; + +template <class A, class B> +struct Tuple2 { + public: + typedef A TypeA; + typedef B TypeB; + + Tuple2() {} + Tuple2(typename TupleTraits<A>::ParamType a, + typename TupleTraits<B>::ParamType b) + : a(a), b(b) { + } + + A a; + B b; +}; + +template <class A, class B, class C> +struct Tuple3 { + public: + typedef A TypeA; + typedef B TypeB; + typedef C TypeC; + + Tuple3() {} + Tuple3(typename TupleTraits<A>::ParamType a, + typename TupleTraits<B>::ParamType b, + typename TupleTraits<C>::ParamType c) + : a(a), b(b), c(c){ + } + + A a; + B b; + C c; +}; + +template <class A, class B, class C, class D> +struct Tuple4 { + public: + typedef A TypeA; + typedef B TypeB; + typedef C TypeC; + typedef D TypeD; + + Tuple4() {} + Tuple4(typename TupleTraits<A>::ParamType a, + typename TupleTraits<B>::ParamType b, + typename TupleTraits<C>::ParamType c, + typename TupleTraits<D>::ParamType d) + : a(a), b(b), c(c), d(d) { + } + + A a; + B b; + C c; + D d; +}; + +template <class A, class B, class C, class D, class E> +struct Tuple5 { + public: + typedef A TypeA; + typedef B TypeB; + typedef C TypeC; + typedef D TypeD; + typedef E TypeE; + + Tuple5() {} + Tuple5(typename TupleTraits<A>::ParamType a, + typename TupleTraits<B>::ParamType b, + typename TupleTraits<C>::ParamType c, + typename TupleTraits<D>::ParamType d, + typename TupleTraits<E>::ParamType e) + : a(a), b(b), c(c), d(d), e(e) { + } + + A a; + B b; + C c; + D d; + E e; +}; + +template <class A, class B, class C, class D, class E, class F> +struct Tuple6 { + public: + typedef A TypeA; + typedef B TypeB; + typedef C TypeC; + typedef D TypeD; + typedef E TypeE; + typedef F TypeF; + + Tuple6() {} + Tuple6(typename TupleTraits<A>::ParamType a, + typename TupleTraits<B>::ParamType b, + typename TupleTraits<C>::ParamType c, + typename TupleTraits<D>::ParamType d, + typename TupleTraits<E>::ParamType e, + typename TupleTraits<F>::ParamType f) + : a(a), b(b), c(c), d(d), e(e), f(f) { + } + + A a; + B b; + C c; + D d; + E e; + F f; +}; + +template <class A, class B, class C, class D, class E, class F, class G> +struct Tuple7 { + public: + typedef A TypeA; + typedef B TypeB; + typedef C TypeC; + typedef D TypeD; + typedef E TypeE; + typedef F TypeF; + typedef G TypeG; + + Tuple7() {} + Tuple7(typename TupleTraits<A>::ParamType a, + typename TupleTraits<B>::ParamType b, + typename TupleTraits<C>::ParamType c, + typename TupleTraits<D>::ParamType d, + typename TupleTraits<E>::ParamType e, + typename TupleTraits<F>::ParamType f, + typename TupleTraits<G>::ParamType g) + : a(a), b(b), c(c), d(d), e(e), f(f), g(g) { + } + + A a; + B b; + C c; + D d; + E e; + F f; + G g; +}; + +template <class A, class B, class C, class D, class E, class F, class G, + class H> +struct Tuple8 { + public: + typedef A TypeA; + typedef B TypeB; + typedef C TypeC; + typedef D TypeD; + typedef E TypeE; + typedef F TypeF; + typedef G TypeG; + typedef H TypeH; + + Tuple8() {} + Tuple8(typename TupleTraits<A>::ParamType a, + typename TupleTraits<B>::ParamType b, + typename TupleTraits<C>::ParamType c, + typename TupleTraits<D>::ParamType d, + typename TupleTraits<E>::ParamType e, + typename TupleTraits<F>::ParamType f, + typename TupleTraits<G>::ParamType g, + typename TupleTraits<H>::ParamType h) + : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) { + } + + A a; + B b; + C c; + D d; + E e; + F f; + G g; + H h; +}; + +// Tuple types ---------------------------------------------------------------- +// +// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the +// definitions of class types the tuple takes as parameters. + +template <> +struct TupleTypes< Tuple0 > { + typedef Tuple0 ValueTuple; + typedef Tuple0 RefTuple; + typedef Tuple0 ParamTuple; +}; + +template <class A> +struct TupleTypes< Tuple1<A> > { + typedef Tuple1<typename TupleTraits<A>::ValueType> ValueTuple; + typedef Tuple1<typename TupleTraits<A>::RefType> RefTuple; + typedef Tuple1<typename TupleTraits<A>::ParamType> ParamTuple; +}; + +template <class A, class B> +struct TupleTypes< Tuple2<A, B> > { + typedef Tuple2<typename TupleTraits<A>::ValueType, + typename TupleTraits<B>::ValueType> ValueTuple; +typedef Tuple2<typename TupleTraits<A>::RefType, + typename TupleTraits<B>::RefType> RefTuple; + typedef Tuple2<typename TupleTraits<A>::ParamType, + typename TupleTraits<B>::ParamType> ParamTuple; +}; + +template <class A, class B, class C> +struct TupleTypes< Tuple3<A, B, C> > { + typedef Tuple3<typename TupleTraits<A>::ValueType, + typename TupleTraits<B>::ValueType, + typename TupleTraits<C>::ValueType> ValueTuple; +typedef Tuple3<typename TupleTraits<A>::RefType, + typename TupleTraits<B>::RefType, + typename TupleTraits<C>::RefType> RefTuple; + typedef Tuple3<typename TupleTraits<A>::ParamType, + typename TupleTraits<B>::ParamType, + typename TupleTraits<C>::ParamType> ParamTuple; +}; + +template <class A, class B, class C, class D> +struct TupleTypes< Tuple4<A, B, C, D> > { + typedef Tuple4<typename TupleTraits<A>::ValueType, + typename TupleTraits<B>::ValueType, + typename TupleTraits<C>::ValueType, + typename TupleTraits<D>::ValueType> ValueTuple; +typedef Tuple4<typename TupleTraits<A>::RefType, + typename TupleTraits<B>::RefType, + typename TupleTraits<C>::RefType, + typename TupleTraits<D>::RefType> RefTuple; + typedef Tuple4<typename TupleTraits<A>::ParamType, + typename TupleTraits<B>::ParamType, + typename TupleTraits<C>::ParamType, + typename TupleTraits<D>::ParamType> ParamTuple; +}; + +template <class A, class B, class C, class D, class E> +struct TupleTypes< Tuple5<A, B, C, D, E> > { + typedef Tuple5<typename TupleTraits<A>::ValueType, + typename TupleTraits<B>::ValueType, + typename TupleTraits<C>::ValueType, + typename TupleTraits<D>::ValueType, + typename TupleTraits<E>::ValueType> ValueTuple; +typedef Tuple5<typename TupleTraits<A>::RefType, + typename TupleTraits<B>::RefType, + typename TupleTraits<C>::RefType, + typename TupleTraits<D>::RefType, + typename TupleTraits<E>::RefType> RefTuple; + typedef Tuple5<typename TupleTraits<A>::ParamType, + typename TupleTraits<B>::ParamType, + typename TupleTraits<C>::ParamType, + typename TupleTraits<D>::ParamType, + typename TupleTraits<E>::ParamType> ParamTuple; +}; + +template <class A, class B, class C, class D, class E, class F> +struct TupleTypes< Tuple6<A, B, C, D, E, F> > { + typedef Tuple6<typename TupleTraits<A>::ValueType, + typename TupleTraits<B>::ValueType, + typename TupleTraits<C>::ValueType, + typename TupleTraits<D>::ValueType, + typename TupleTraits<E>::ValueType, + typename TupleTraits<F>::ValueType> ValueTuple; +typedef Tuple6<typename TupleTraits<A>::RefType, + typename TupleTraits<B>::RefType, + typename TupleTraits<C>::RefType, + typename TupleTraits<D>::RefType, + typename TupleTraits<E>::RefType, + typename TupleTraits<F>::RefType> RefTuple; + typedef Tuple6<typename TupleTraits<A>::ParamType, + typename TupleTraits<B>::ParamType, + typename TupleTraits<C>::ParamType, + typename TupleTraits<D>::ParamType, + typename TupleTraits<E>::ParamType, + typename TupleTraits<F>::ParamType> ParamTuple; +}; + +template <class A, class B, class C, class D, class E, class F, class G> +struct TupleTypes< Tuple7<A, B, C, D, E, F, G> > { + typedef Tuple7<typename TupleTraits<A>::ValueType, + typename TupleTraits<B>::ValueType, + typename TupleTraits<C>::ValueType, + typename TupleTraits<D>::ValueType, + typename TupleTraits<E>::ValueType, + typename TupleTraits<F>::ValueType, + typename TupleTraits<G>::ValueType> ValueTuple; +typedef Tuple7<typename TupleTraits<A>::RefType, + typename TupleTraits<B>::RefType, + typename TupleTraits<C>::RefType, + typename TupleTraits<D>::RefType, + typename TupleTraits<E>::RefType, + typename TupleTraits<F>::RefType, + typename TupleTraits<G>::RefType> RefTuple; + typedef Tuple7<typename TupleTraits<A>::ParamType, + typename TupleTraits<B>::ParamType, + typename TupleTraits<C>::ParamType, + typename TupleTraits<D>::ParamType, + typename TupleTraits<E>::ParamType, + typename TupleTraits<F>::ParamType, + typename TupleTraits<G>::ParamType> ParamTuple; +}; + +template <class A, class B, class C, class D, class E, class F, class G, + class H> +struct TupleTypes< Tuple8<A, B, C, D, E, F, G, H> > { + typedef Tuple8<typename TupleTraits<A>::ValueType, + typename TupleTraits<B>::ValueType, + typename TupleTraits<C>::ValueType, + typename TupleTraits<D>::ValueType, + typename TupleTraits<E>::ValueType, + typename TupleTraits<F>::ValueType, + typename TupleTraits<G>::ValueType, + typename TupleTraits<H>::ValueType> ValueTuple; +typedef Tuple8<typename TupleTraits<A>::RefType, + typename TupleTraits<B>::RefType, + typename TupleTraits<C>::RefType, + typename TupleTraits<D>::RefType, + typename TupleTraits<E>::RefType, + typename TupleTraits<F>::RefType, + typename TupleTraits<G>::RefType, + typename TupleTraits<H>::RefType> RefTuple; + typedef Tuple8<typename TupleTraits<A>::ParamType, + typename TupleTraits<B>::ParamType, + typename TupleTraits<C>::ParamType, + typename TupleTraits<D>::ParamType, + typename TupleTraits<E>::ParamType, + typename TupleTraits<F>::ParamType, + typename TupleTraits<G>::ParamType, + typename TupleTraits<H>::ParamType> ParamTuple; +}; + +// Tuple creators ------------------------------------------------------------- +// +// Helper functions for constructing tuples while inferring the template +// argument types. + +inline Tuple0 MakeTuple() { + return Tuple0(); +} + +template <class A> +inline Tuple1<A> MakeTuple(const A& a) { + return Tuple1<A>(a); +} + +template <class A, class B> +inline Tuple2<A, B> MakeTuple(const A& a, const B& b) { + return Tuple2<A, B>(a, b); +} + +template <class A, class B, class C> +inline Tuple3<A, B, C> MakeTuple(const A& a, const B& b, const C& c) { + return Tuple3<A, B, C>(a, b, c); +} + +template <class A, class B, class C, class D> +inline Tuple4<A, B, C, D> MakeTuple(const A& a, const B& b, const C& c, + const D& d) { + return Tuple4<A, B, C, D>(a, b, c, d); +} + +template <class A, class B, class C, class D, class E> +inline Tuple5<A, B, C, D, E> MakeTuple(const A& a, const B& b, const C& c, + const D& d, const E& e) { + return Tuple5<A, B, C, D, E>(a, b, c, d, e); +} + +template <class A, class B, class C, class D, class E, class F> +inline Tuple6<A, B, C, D, E, F> MakeTuple(const A& a, const B& b, const C& c, + const D& d, const E& e, const F& f) { + return Tuple6<A, B, C, D, E, F>(a, b, c, d, e, f); +} + +template <class A, class B, class C, class D, class E, class F, class G> +inline Tuple7<A, B, C, D, E, F, G> MakeTuple(const A& a, const B& b, const C& c, + const D& d, const E& e, const F& f, + const G& g) { + return Tuple7<A, B, C, D, E, F, G>(a, b, c, d, e, f, g); +} + +template <class A, class B, class C, class D, class E, class F, class G, + class H> +inline Tuple8<A, B, C, D, E, F, G, H> MakeTuple(const A& a, const B& b, + const C& c, const D& d, + const E& e, const F& f, + const G& g, const H& h) { + return Tuple8<A, B, C, D, E, F, G, H>(a, b, c, d, e, f, g, h); +} + +// The following set of helpers make what Boost refers to as "Tiers" - a tuple +// of references. + +template <class A> +inline Tuple1<A&> MakeRefTuple(A& a) { + return Tuple1<A&>(a); +} + +template <class A, class B> +inline Tuple2<A&, B&> MakeRefTuple(A& a, B& b) { + return Tuple2<A&, B&>(a, b); +} + +template <class A, class B, class C> +inline Tuple3<A&, B&, C&> MakeRefTuple(A& a, B& b, C& c) { + return Tuple3<A&, B&, C&>(a, b, c); +} + +template <class A, class B, class C, class D> +inline Tuple4<A&, B&, C&, D&> MakeRefTuple(A& a, B& b, C& c, D& d) { + return Tuple4<A&, B&, C&, D&>(a, b, c, d); +} + +template <class A, class B, class C, class D, class E> +inline Tuple5<A&, B&, C&, D&, E&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e) { + return Tuple5<A&, B&, C&, D&, E&>(a, b, c, d, e); +} + +template <class A, class B, class C, class D, class E, class F> +inline Tuple6<A&, B&, C&, D&, E&, F&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e, + F& f) { + return Tuple6<A&, B&, C&, D&, E&, F&>(a, b, c, d, e, f); +} + +template <class A, class B, class C, class D, class E, class F, class G> +inline Tuple7<A&, B&, C&, D&, E&, F&, G&> MakeRefTuple(A& a, B& b, C& c, D& d, + E& e, F& f, G& g) { + return Tuple7<A&, B&, C&, D&, E&, F&, G&>(a, b, c, d, e, f, g); +} + +template <class A, class B, class C, class D, class E, class F, class G, + class H> +inline Tuple8<A&, B&, C&, D&, E&, F&, G&, H&> MakeRefTuple(A& a, B& b, C& c, + D& d, E& e, F& f, + G& g, H& h) { + return Tuple8<A&, B&, C&, D&, E&, F&, G&, H&>(a, b, c, d, e, f, g, h); +} + +// Dispatchers ---------------------------------------------------------------- +// +// Helper functions that call the given method on an object, with the unpacked +// tuple arguments. Notice that they all have the same number of arguments, +// so you need only write: +// DispatchToMethod(object, &Object::method, args); +// This is very useful for templated dispatchers, since they don't need to know +// what type |args| is. + +// Non-Static Dispatchers with no out params. + +template <class ObjT, class Method> +inline void DispatchToMethod(ObjT* obj, Method method, const Tuple0& arg) { + (obj->*method)(); +} + +template <class ObjT, class Method, class A> +inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) { + (obj->*method)(arg); +} + +template <class ObjT, class Method, class A> +inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1<A>& arg) { + (obj->*method)(arg.a); +} + +template<class ObjT, class Method, class A, class B> +inline void DispatchToMethod(ObjT* obj, + Method method, + const Tuple2<A, B>& arg) { + (obj->*method)(arg.a, arg.b); +} + +template<class ObjT, class Method, class A, class B, class C> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple3<A, B, C>& arg) { + (obj->*method)(arg.a, arg.b, arg.c); +} + +template<class ObjT, class Method, class A, class B, class C, class D> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple4<A, B, C, D>& arg) { + (obj->*method)(arg.a, arg.b, arg.c, arg.d); +} + +template<class ObjT, class Method, class A, class B, class C, class D, class E> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple5<A, B, C, D, E>& arg) { + (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e); +} + +template<class ObjT, class Method, class A, class B, class C, class D, class E, + class F> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple6<A, B, C, D, E, F>& arg) { + (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f); +} + +template<class ObjT, class Method, class A, class B, class C, class D, class E, + class F, class G> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple7<A, B, C, D, E, F, G>& arg) { + (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g); +} + +template<class ObjT, class Method, class A, class B, class C, class D, class E, + class F, class G, class H> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple8<A, B, C, D, E, F, G, H>& arg) { + (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g, arg.h); +} + +// Static Dispatchers with no out params. + +template <class Function> +inline void DispatchToFunction(Function function, const Tuple0& arg) { + (*function)(); +} + +template <class Function, class A> +inline void DispatchToFunction(Function function, const A& arg) { + (*function)(arg); +} + +template <class Function, class A> +inline void DispatchToFunction(Function function, const Tuple1<A>& arg) { + (*function)(arg.a); +} + +template<class Function, class A, class B> +inline void DispatchToFunction(Function function, const Tuple2<A, B>& arg) { + (*function)(arg.a, arg.b); +} + +template<class Function, class A, class B, class C> +inline void DispatchToFunction(Function function, const Tuple3<A, B, C>& arg) { + (*function)(arg.a, arg.b, arg.c); +} + +template<class Function, class A, class B, class C, class D> +inline void DispatchToFunction(Function function, + const Tuple4<A, B, C, D>& arg) { + (*function)(arg.a, arg.b, arg.c, arg.d); +} + +template<class Function, class A, class B, class C, class D, class E> +inline void DispatchToFunction(Function function, + const Tuple5<A, B, C, D, E>& arg) { + (*function)(arg.a, arg.b, arg.c, arg.d, arg.e); +} + +template<class Function, class A, class B, class C, class D, class E, class F> +inline void DispatchToFunction(Function function, + const Tuple6<A, B, C, D, E, F>& arg) { + (*function)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f); +} + +template<class Function, class A, class B, class C, class D, class E, class F, + class G> +inline void DispatchToFunction(Function function, + const Tuple7<A, B, C, D, E, F, G>& arg) { + (*function)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g); +} + +template<class Function, class A, class B, class C, class D, class E, class F, + class G, class H> +inline void DispatchToFunction(Function function, + const Tuple8<A, B, C, D, E, F, G, H>& arg) { + (*function)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g, arg.h); +} + +// Dispatchers with 0 out param (as a Tuple0). + +template <class ObjT, class Method> +inline void DispatchToMethod(ObjT* obj, + Method method, + const Tuple0& arg, Tuple0*) { + (obj->*method)(); +} + +template <class ObjT, class Method, class A> +inline void DispatchToMethod(ObjT* obj, Method method, const A& arg, Tuple0*) { + (obj->*method)(arg); +} + +template <class ObjT, class Method, class A> +inline void DispatchToMethod(ObjT* obj, + Method method, + const Tuple1<A>& arg, Tuple0*) { + (obj->*method)(arg.a); +} + +template<class ObjT, class Method, class A, class B> +inline void DispatchToMethod(ObjT* obj, + Method method, + const Tuple2<A, B>& arg, Tuple0*) { + (obj->*method)(arg.a, arg.b); +} + +template<class ObjT, class Method, class A, class B, class C> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple3<A, B, C>& arg, Tuple0*) { + (obj->*method)(arg.a, arg.b, arg.c); +} + +template<class ObjT, class Method, class A, class B, class C, class D> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple4<A, B, C, D>& arg, Tuple0*) { + (obj->*method)(arg.a, arg.b, arg.c, arg.d); +} + +template<class ObjT, class Method, class A, class B, class C, class D, class E> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple5<A, B, C, D, E>& arg, Tuple0*) { + (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e); +} + +template<class ObjT, class Method, class A, class B, class C, class D, class E, + class F> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple6<A, B, C, D, E, F>& arg, Tuple0*) { + (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f); +} + +// Dispatchers with 1 out param. + +template<class ObjT, class Method, + class OutA> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple0& in, + Tuple1<OutA>* out) { + (obj->*method)(&out->a); +} + +template<class ObjT, class Method, class InA, + class OutA> +inline void DispatchToMethod(ObjT* obj, Method method, + const InA& in, + Tuple1<OutA>* out) { + (obj->*method)(in, &out->a); +} + +template<class ObjT, class Method, class InA, + class OutA> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple1<InA>& in, + Tuple1<OutA>* out) { + (obj->*method)(in.a, &out->a); +} + +template<class ObjT, class Method, class InA, class InB, + class OutA> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple2<InA, InB>& in, + Tuple1<OutA>* out) { + (obj->*method)(in.a, in.b, &out->a); +} + +template<class ObjT, class Method, class InA, class InB, class InC, + class OutA> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple3<InA, InB, InC>& in, + Tuple1<OutA>* out) { + (obj->*method)(in.a, in.b, in.c, &out->a); +} + +template<class ObjT, class Method, class InA, class InB, class InC, class InD, + class OutA> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple4<InA, InB, InC, InD>& in, + Tuple1<OutA>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, &out->a); +} + +template<class ObjT, class Method, class InA, class InB, class InC, class InD, + class InE, class OutA> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple5<InA, InB, InC, InD, InE>& in, + Tuple1<OutA>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, &out->a); +} + +template<class ObjT, class Method, + class InA, class InB, class InC, class InD, class InE, class InF, + class OutA> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple6<InA, InB, InC, InD, InE, InF>& in, + Tuple1<OutA>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, &out->a); +} + +// Dispatchers with 2 out params. + +template<class ObjT, class Method, + class OutA, class OutB> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple0& in, + Tuple2<OutA, OutB>* out) { + (obj->*method)(&out->a, &out->b); +} + +template<class ObjT, class Method, class InA, + class OutA, class OutB> +inline void DispatchToMethod(ObjT* obj, Method method, + const InA& in, + Tuple2<OutA, OutB>* out) { + (obj->*method)(in, &out->a, &out->b); +} + +template<class ObjT, class Method, class InA, + class OutA, class OutB> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple1<InA>& in, + Tuple2<OutA, OutB>* out) { + (obj->*method)(in.a, &out->a, &out->b); +} + +template<class ObjT, class Method, class InA, class InB, + class OutA, class OutB> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple2<InA, InB>& in, + Tuple2<OutA, OutB>* out) { + (obj->*method)(in.a, in.b, &out->a, &out->b); +} + +template<class ObjT, class Method, class InA, class InB, class InC, + class OutA, class OutB> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple3<InA, InB, InC>& in, + Tuple2<OutA, OutB>* out) { + (obj->*method)(in.a, in.b, in.c, &out->a, &out->b); +} + +template<class ObjT, class Method, class InA, class InB, class InC, class InD, + class OutA, class OutB> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple4<InA, InB, InC, InD>& in, + Tuple2<OutA, OutB>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b); +} + +template<class ObjT, class Method, + class InA, class InB, class InC, class InD, class InE, + class OutA, class OutB> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple5<InA, InB, InC, InD, InE>& in, + Tuple2<OutA, OutB>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, &out->a, &out->b); +} + +template<class ObjT, class Method, + class InA, class InB, class InC, class InD, class InE, class InF, + class OutA, class OutB> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple6<InA, InB, InC, InD, InE, InF>& in, + Tuple2<OutA, OutB>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, &out->a, &out->b); +} + +// Dispatchers with 3 out params. + +template<class ObjT, class Method, + class OutA, class OutB, class OutC> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple0& in, + Tuple3<OutA, OutB, OutC>* out) { + (obj->*method)(&out->a, &out->b, &out->c); +} + +template<class ObjT, class Method, class InA, + class OutA, class OutB, class OutC> +inline void DispatchToMethod(ObjT* obj, Method method, + const InA& in, + Tuple3<OutA, OutB, OutC>* out) { + (obj->*method)(in, &out->a, &out->b, &out->c); +} + +template<class ObjT, class Method, class InA, + class OutA, class OutB, class OutC> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple1<InA>& in, + Tuple3<OutA, OutB, OutC>* out) { + (obj->*method)(in.a, &out->a, &out->b, &out->c); +} + +template<class ObjT, class Method, class InA, class InB, + class OutA, class OutB, class OutC> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple2<InA, InB>& in, + Tuple3<OutA, OutB, OutC>* out) { + (obj->*method)(in.a, in.b, &out->a, &out->b, &out->c); +} + +template<class ObjT, class Method, class InA, class InB, class InC, + class OutA, class OutB, class OutC> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple3<InA, InB, InC>& in, + Tuple3<OutA, OutB, OutC>* out) { + (obj->*method)(in.a, in.b, in.c, &out->a, &out->b, &out->c); +} + +template<class ObjT, class Method, class InA, class InB, class InC, class InD, + class OutA, class OutB, class OutC> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple4<InA, InB, InC, InD>& in, + Tuple3<OutA, OutB, OutC>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b, &out->c); +} + +template<class ObjT, class Method, + class InA, class InB, class InC, class InD, class InE, + class OutA, class OutB, class OutC> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple5<InA, InB, InC, InD, InE>& in, + Tuple3<OutA, OutB, OutC>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, &out->a, &out->b, &out->c); +} + +template<class ObjT, class Method, + class InA, class InB, class InC, class InD, class InE, class InF, + class OutA, class OutB, class OutC> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple6<InA, InB, InC, InD, InE, InF>& in, + Tuple3<OutA, OutB, OutC>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, &out->a, &out->b, &out->c); +} + +// Dispatchers with 4 out params. + +template<class ObjT, class Method, + class OutA, class OutB, class OutC, class OutD> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple0& in, + Tuple4<OutA, OutB, OutC, OutD>* out) { + (obj->*method)(&out->a, &out->b, &out->c, &out->d); +} + +template<class ObjT, class Method, class InA, + class OutA, class OutB, class OutC, class OutD> +inline void DispatchToMethod(ObjT* obj, Method method, + const InA& in, + Tuple4<OutA, OutB, OutC, OutD>* out) { + (obj->*method)(in, &out->a, &out->b, &out->c, &out->d); +} + +template<class ObjT, class Method, class InA, + class OutA, class OutB, class OutC, class OutD> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple1<InA>& in, + Tuple4<OutA, OutB, OutC, OutD>* out) { + (obj->*method)(in.a, &out->a, &out->b, &out->c, &out->d); +} + +template<class ObjT, class Method, class InA, class InB, + class OutA, class OutB, class OutC, class OutD> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple2<InA, InB>& in, + Tuple4<OutA, OutB, OutC, OutD>* out) { + (obj->*method)(in.a, in.b, &out->a, &out->b, &out->c, &out->d); +} + +template<class ObjT, class Method, class InA, class InB, class InC, + class OutA, class OutB, class OutC, class OutD> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple3<InA, InB, InC>& in, + Tuple4<OutA, OutB, OutC, OutD>* out) { + (obj->*method)(in.a, in.b, in.c, &out->a, &out->b, &out->c, &out->d); +} + +template<class ObjT, class Method, class InA, class InB, class InC, class InD, + class OutA, class OutB, class OutC, class OutD> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple4<InA, InB, InC, InD>& in, + Tuple4<OutA, OutB, OutC, OutD>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b, &out->c, &out->d); +} + +template<class ObjT, class Method, + class InA, class InB, class InC, class InD, class InE, + class OutA, class OutB, class OutC, class OutD> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple5<InA, InB, InC, InD, InE>& in, + Tuple4<OutA, OutB, OutC, OutD>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, + &out->a, &out->b, &out->c, &out->d); +} + +template<class ObjT, class Method, + class InA, class InB, class InC, class InD, class InE, class InF, + class OutA, class OutB, class OutC, class OutD> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple6<InA, InB, InC, InD, InE, InF>& in, + Tuple4<OutA, OutB, OutC, OutD>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, + &out->a, &out->b, &out->c, &out->d); +} + +// Dispatchers with 5 out params. + +template<class ObjT, class Method, + class OutA, class OutB, class OutC, class OutD, class OutE> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple0& in, + Tuple5<OutA, OutB, OutC, OutD, OutE>* out) { + (obj->*method)(&out->a, &out->b, &out->c, &out->d, &out->e); +} + +template<class ObjT, class Method, class InA, + class OutA, class OutB, class OutC, class OutD, class OutE> +inline void DispatchToMethod(ObjT* obj, Method method, + const InA& in, + Tuple5<OutA, OutB, OutC, OutD, OutE>* out) { + (obj->*method)(in, &out->a, &out->b, &out->c, &out->d, &out->e); +} + +template<class ObjT, class Method, class InA, + class OutA, class OutB, class OutC, class OutD, class OutE> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple1<InA>& in, + Tuple5<OutA, OutB, OutC, OutD, OutE>* out) { + (obj->*method)(in.a, &out->a, &out->b, &out->c, &out->d, &out->e); +} + +template<class ObjT, class Method, class InA, class InB, + class OutA, class OutB, class OutC, class OutD, class OutE> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple2<InA, InB>& in, + Tuple5<OutA, OutB, OutC, OutD, OutE>* out) { + (obj->*method)(in.a, in.b, &out->a, &out->b, &out->c, &out->d, &out->e); +} + +template<class ObjT, class Method, class InA, class InB, class InC, + class OutA, class OutB, class OutC, class OutD, class OutE> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple3<InA, InB, InC>& in, + Tuple5<OutA, OutB, OutC, OutD, OutE>* out) { + (obj->*method)(in.a, in.b, in.c, &out->a, &out->b, &out->c, &out->d, &out->e); +} + +template<class ObjT, class Method, class InA, class InB, class InC, class InD, + class OutA, class OutB, class OutC, class OutD, class OutE> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple4<InA, InB, InC, InD>& in, + Tuple5<OutA, OutB, OutC, OutD, OutE>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b, &out->c, &out->d, + &out->e); +} + +template<class ObjT, class Method, + class InA, class InB, class InC, class InD, class InE, + class OutA, class OutB, class OutC, class OutD, class OutE> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple5<InA, InB, InC, InD, InE>& in, + Tuple5<OutA, OutB, OutC, OutD, OutE>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, + &out->a, &out->b, &out->c, &out->d, &out->e); +} + +template<class ObjT, class Method, + class InA, class InB, class InC, class InD, class InE, class InF, + class OutA, class OutB, class OutC, class OutD, class OutE> +inline void DispatchToMethod(ObjT* obj, Method method, + const Tuple6<InA, InB, InC, InD, InE, InF>& in, + Tuple5<OutA, OutB, OutC, OutD, OutE>* out) { + (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, + &out->a, &out->b, &out->c, &out->d, &out->e); +} + +#endif // BASE_TUPLE_H__ diff --git a/base/values.cc b/base/values.cc new file mode 100644 index 000000000000..7a364bd8ff0f --- /dev/null +++ b/base/values.cc @@ -0,0 +1,905 @@ +// 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/values.h" + +#include "base/logging.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" + +namespace { + +// Make a deep copy of |node|, but don't include empty lists or dictionaries +// in the copy. It's possible for this function to return NULL and it +// expects |node| to always be non-NULL. +Value* CopyWithoutEmptyChildren(Value* node) { + DCHECK(node); + switch (node->GetType()) { + case Value::TYPE_LIST: { + ListValue* list = static_cast<ListValue*>(node); + ListValue* copy = new ListValue; + for (ListValue::const_iterator it = list->begin(); it != list->end(); + ++it) { + Value* child_copy = CopyWithoutEmptyChildren(*it); + if (child_copy) + copy->Append(child_copy); + } + if (!copy->empty()) + return copy; + + delete copy; + return NULL; + } + + case Value::TYPE_DICTIONARY: { + DictionaryValue* dict = static_cast<DictionaryValue*>(node); + DictionaryValue* copy = new DictionaryValue; + for (DictionaryValue::key_iterator it = dict->begin_keys(); + it != dict->end_keys(); ++it) { + Value* child = NULL; + bool rv = dict->GetWithoutPathExpansion(*it, &child); + DCHECK(rv); + Value* child_copy = CopyWithoutEmptyChildren(child); + if (child_copy) + copy->SetWithoutPathExpansion(*it, child_copy); + } + if (!copy->empty()) + return copy; + + delete copy; + return NULL; + } + + default: + // For everything else, just make a copy. + return node->DeepCopy(); + } +} + +} // namespace + +namespace base { + +///////////////////// Value //////////////////// + +Value::~Value() { +} + +// static +Value* Value::CreateNullValue() { + return new Value(TYPE_NULL); +} + +// static +FundamentalValue* Value::CreateBooleanValue(bool in_value) { + return new FundamentalValue(in_value); +} + +// static +FundamentalValue* Value::CreateIntegerValue(int in_value) { + return new FundamentalValue(in_value); +} + +// static +FundamentalValue* Value::CreateDoubleValue(double in_value) { + return new FundamentalValue(in_value); +} + +// static +StringValue* Value::CreateStringValue(const std::string& in_value) { + return new StringValue(in_value); +} + +// static +StringValue* Value::CreateStringValue(const string16& in_value) { + return new StringValue(in_value); +} + +bool Value::GetAsBoolean(bool* out_value) const { + return false; +} + +bool Value::GetAsInteger(int* out_value) const { + return false; +} + +bool Value::GetAsDouble(double* out_value) const { + return false; +} + +bool Value::GetAsString(std::string* out_value) const { + return false; +} + +bool Value::GetAsString(string16* out_value) const { + return false; +} + +bool Value::GetAsList(ListValue** out_value) { + return false; +} + +bool Value::GetAsList(const ListValue** out_value) const { + return false; +} + +Value* Value::DeepCopy() const { + // This method should only be getting called for null Values--all subclasses + // need to provide their own implementation;. + DCHECK(IsType(TYPE_NULL)); + return CreateNullValue(); +} + +bool Value::Equals(const Value* other) const { + // This method should only be getting called for null Values--all subclasses + // need to provide their own implementation;. + DCHECK(IsType(TYPE_NULL)); + return other->IsType(TYPE_NULL); +} + +// static +bool Value::Equals(const Value* a, const Value* b) { + if ((a == NULL) && (b == NULL)) return true; + if ((a == NULL) ^ (b == NULL)) return false; + return a->Equals(b); +} + +Value::Value(Type type) : type_(type) { +} + +///////////////////// FundamentalValue //////////////////// + +FundamentalValue::FundamentalValue(bool in_value) + : Value(TYPE_BOOLEAN), boolean_value_(in_value) { +} + +FundamentalValue::FundamentalValue(int in_value) + : Value(TYPE_INTEGER), integer_value_(in_value) { +} + +FundamentalValue::FundamentalValue(double in_value) + : Value(TYPE_DOUBLE), double_value_(in_value) { +} + +FundamentalValue::~FundamentalValue() { +} + +bool FundamentalValue::GetAsBoolean(bool* out_value) const { + if (out_value && IsType(TYPE_BOOLEAN)) + *out_value = boolean_value_; + return (IsType(TYPE_BOOLEAN)); +} + +bool FundamentalValue::GetAsInteger(int* out_value) const { + if (out_value && IsType(TYPE_INTEGER)) + *out_value = integer_value_; + return (IsType(TYPE_INTEGER)); +} + +bool FundamentalValue::GetAsDouble(double* out_value) const { + if (out_value && IsType(TYPE_DOUBLE)) + *out_value = double_value_; + else if (out_value && IsType(TYPE_INTEGER)) + *out_value = integer_value_; + return (IsType(TYPE_DOUBLE) || IsType(TYPE_INTEGER)); +} + +FundamentalValue* FundamentalValue::DeepCopy() const { + switch (GetType()) { + case TYPE_BOOLEAN: + return CreateBooleanValue(boolean_value_); + + case TYPE_INTEGER: + return CreateIntegerValue(integer_value_); + + case TYPE_DOUBLE: + return CreateDoubleValue(double_value_); + + default: + NOTREACHED(); + return NULL; + } +} + +bool FundamentalValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + + switch (GetType()) { + case TYPE_BOOLEAN: { + bool lhs, rhs; + return GetAsBoolean(&lhs) && other->GetAsBoolean(&rhs) && lhs == rhs; + } + case TYPE_INTEGER: { + int lhs, rhs; + return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs; + } + case TYPE_DOUBLE: { + double lhs, rhs; + return GetAsDouble(&lhs) && other->GetAsDouble(&rhs) && lhs == rhs; + } + default: + NOTREACHED(); + return false; + } +} + +///////////////////// StringValue //////////////////// + +StringValue::StringValue(const std::string& in_value) + : Value(TYPE_STRING), + value_(in_value) { + DCHECK(IsStringUTF8(in_value)); +} + +StringValue::StringValue(const string16& in_value) + : Value(TYPE_STRING), + value_(UTF16ToUTF8(in_value)) { +} + +StringValue::~StringValue() { +} + +bool StringValue::GetAsString(std::string* out_value) const { + if (out_value) + *out_value = value_; + return true; +} + +bool StringValue::GetAsString(string16* out_value) const { + if (out_value) + *out_value = UTF8ToUTF16(value_); + return true; +} + +StringValue* StringValue::DeepCopy() const { + return CreateStringValue(value_); +} + +bool StringValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + std::string lhs, rhs; + return GetAsString(&lhs) && other->GetAsString(&rhs) && lhs == rhs; +} + +///////////////////// BinaryValue //////////////////// + +BinaryValue::~BinaryValue() { + DCHECK(buffer_); + if (buffer_) + delete[] buffer_; +} + +// static +BinaryValue* BinaryValue::Create(char* buffer, size_t size) { + if (!buffer) + return NULL; + + return new BinaryValue(buffer, size); +} + +// static +BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer, + size_t size) { + if (!buffer) + return NULL; + + char* buffer_copy = new char[size]; + memcpy(buffer_copy, buffer, size); + return new BinaryValue(buffer_copy, size); +} + +BinaryValue* BinaryValue::DeepCopy() const { + return CreateWithCopiedBuffer(buffer_, size_); +} + +bool BinaryValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + const BinaryValue* other_binary = static_cast<const BinaryValue*>(other); + if (other_binary->size_ != size_) + return false; + return !memcmp(buffer_, other_binary->buffer_, size_); +} + +BinaryValue::BinaryValue(char* buffer, size_t size) + : Value(TYPE_BINARY), + buffer_(buffer), + size_(size) { + DCHECK(buffer_); +} + +///////////////////// DictionaryValue //////////////////// + +DictionaryValue::DictionaryValue() + : Value(TYPE_DICTIONARY) { +} + +DictionaryValue::~DictionaryValue() { + Clear(); +} + +bool DictionaryValue::HasKey(const std::string& key) const { + DCHECK(IsStringUTF8(key)); + ValueMap::const_iterator current_entry = dictionary_.find(key); + DCHECK((current_entry == dictionary_.end()) || current_entry->second); + return current_entry != dictionary_.end(); +} + +void DictionaryValue::Clear() { + ValueMap::iterator dict_iterator = dictionary_.begin(); + while (dict_iterator != dictionary_.end()) { + delete dict_iterator->second; + ++dict_iterator; + } + + dictionary_.clear(); +} + +void DictionaryValue::Set(const std::string& path, Value* in_value) { + DCHECK(IsStringUTF8(path)); + DCHECK(in_value); + + std::string current_path(path); + DictionaryValue* current_dictionary = this; + for (size_t delimiter_position = current_path.find('.'); + delimiter_position != std::string::npos; + delimiter_position = current_path.find('.')) { + // Assume that we're indexing into a dictionary. + std::string key(current_path, 0, delimiter_position); + DictionaryValue* child_dictionary = NULL; + if (!current_dictionary->GetDictionary(key, &child_dictionary)) { + child_dictionary = new DictionaryValue; + current_dictionary->SetWithoutPathExpansion(key, child_dictionary); + } + + current_dictionary = child_dictionary; + current_path.erase(0, delimiter_position + 1); + } + + current_dictionary->SetWithoutPathExpansion(current_path, in_value); +} + +void DictionaryValue::SetBoolean(const std::string& path, bool in_value) { + Set(path, CreateBooleanValue(in_value)); +} + +void DictionaryValue::SetInteger(const std::string& path, int in_value) { + Set(path, CreateIntegerValue(in_value)); +} + +void DictionaryValue::SetDouble(const std::string& path, double in_value) { + Set(path, CreateDoubleValue(in_value)); +} + +void DictionaryValue::SetString(const std::string& path, + const std::string& in_value) { + Set(path, CreateStringValue(in_value)); +} + +void DictionaryValue::SetString(const std::string& path, + const string16& in_value) { + Set(path, CreateStringValue(in_value)); +} + +void DictionaryValue::SetWithoutPathExpansion(const std::string& key, + Value* in_value) { + // If there's an existing value here, we need to delete it, because + // we own all our children. + if (HasKey(key)) { + DCHECK(dictionary_[key] != in_value); // This would be bogus + delete dictionary_[key]; + } + + dictionary_[key] = in_value; +} + +bool DictionaryValue::Get(const std::string& path, Value** out_value) const { + DCHECK(IsStringUTF8(path)); + std::string current_path(path); + const DictionaryValue* current_dictionary = this; + for (size_t delimiter_position = current_path.find('.'); + delimiter_position != std::string::npos; + delimiter_position = current_path.find('.')) { + DictionaryValue* child_dictionary = NULL; + if (!current_dictionary->GetDictionary( + current_path.substr(0, delimiter_position), &child_dictionary)) + return false; + + current_dictionary = child_dictionary; + current_path.erase(0, delimiter_position + 1); + } + + return current_dictionary->GetWithoutPathExpansion(current_path, out_value); +} + +bool DictionaryValue::GetBoolean(const std::string& path, + bool* bool_value) const { + Value* value; + if (!Get(path, &value)) + return false; + + return value->GetAsBoolean(bool_value); +} + +bool DictionaryValue::GetInteger(const std::string& path, + int* out_value) const { + Value* value; + if (!Get(path, &value)) + return false; + + return value->GetAsInteger(out_value); +} + +bool DictionaryValue::GetDouble(const std::string& path, + double* out_value) const { + Value* value; + if (!Get(path, &value)) + return false; + + return value->GetAsDouble(out_value); +} + +bool DictionaryValue::GetString(const std::string& path, + std::string* out_value) const { + Value* value; + if (!Get(path, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool DictionaryValue::GetString(const std::string& path, + string16* out_value) const { + Value* value; + if (!Get(path, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool DictionaryValue::GetStringASCII(const std::string& path, + std::string* out_value) const { + std::string out; + if (!GetString(path, &out)) + return false; + + if (!IsStringASCII(out)) { + NOTREACHED(); + return false; + } + + out_value->assign(out); + return true; +} + +bool DictionaryValue::GetBinary(const std::string& path, + BinaryValue** out_value) const { + Value* value; + bool result = Get(path, &value); + if (!result || !value->IsType(TYPE_BINARY)) + return false; + + if (out_value) + *out_value = static_cast<BinaryValue*>(value); + + return true; +} + +bool DictionaryValue::GetDictionary(const std::string& path, + DictionaryValue** out_value) const { + Value* value; + bool result = Get(path, &value); + if (!result || !value->IsType(TYPE_DICTIONARY)) + return false; + + if (out_value) + *out_value = static_cast<DictionaryValue*>(value); + + return true; +} + +bool DictionaryValue::GetList(const std::string& path, + ListValue** out_value) const { + Value* value; + bool result = Get(path, &value); + if (!result || !value->IsType(TYPE_LIST)) + return false; + + if (out_value) + *out_value = static_cast<ListValue*>(value); + + return true; +} + +bool DictionaryValue::GetWithoutPathExpansion(const std::string& key, + Value** out_value) const { + DCHECK(IsStringUTF8(key)); + ValueMap::const_iterator entry_iterator = dictionary_.find(key); + if (entry_iterator == dictionary_.end()) + return false; + + Value* entry = entry_iterator->second; + if (out_value) + *out_value = entry; + return true; +} + +bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key, + int* out_value) const { + Value* value; + if (!GetWithoutPathExpansion(key, &value)) + return false; + + return value->GetAsInteger(out_value); +} + +bool DictionaryValue::GetDoubleWithoutPathExpansion(const std::string& key, + double* out_value) const { + Value* value; + if (!GetWithoutPathExpansion(key, &value)) + return false; + + return value->GetAsDouble(out_value); +} + +bool DictionaryValue::GetStringWithoutPathExpansion( + const std::string& key, + std::string* out_value) const { + Value* value; + if (!GetWithoutPathExpansion(key, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool DictionaryValue::GetStringWithoutPathExpansion( + const std::string& key, + string16* out_value) const { + Value* value; + if (!GetWithoutPathExpansion(key, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool DictionaryValue::GetDictionaryWithoutPathExpansion( + const std::string& key, + DictionaryValue** out_value) const { + Value* value; + bool result = GetWithoutPathExpansion(key, &value); + if (!result || !value->IsType(TYPE_DICTIONARY)) + return false; + + if (out_value) + *out_value = static_cast<DictionaryValue*>(value); + + return true; +} + +bool DictionaryValue::GetListWithoutPathExpansion(const std::string& key, + ListValue** out_value) const { + Value* value; + bool result = GetWithoutPathExpansion(key, &value); + if (!result || !value->IsType(TYPE_LIST)) + return false; + + if (out_value) + *out_value = static_cast<ListValue*>(value); + + return true; +} + +bool DictionaryValue::Remove(const std::string& path, Value** out_value) { + DCHECK(IsStringUTF8(path)); + std::string current_path(path); + DictionaryValue* current_dictionary = this; + size_t delimiter_position = current_path.rfind('.'); + if (delimiter_position != std::string::npos) { + if (!GetDictionary(current_path.substr(0, delimiter_position), + ¤t_dictionary)) + return false; + current_path.erase(0, delimiter_position + 1); + } + + return current_dictionary->RemoveWithoutPathExpansion(current_path, + out_value); +} + +bool DictionaryValue::RemoveWithoutPathExpansion(const std::string& key, + Value** out_value) { + DCHECK(IsStringUTF8(key)); + ValueMap::iterator entry_iterator = dictionary_.find(key); + if (entry_iterator == dictionary_.end()) + return false; + + Value* entry = entry_iterator->second; + if (out_value) + *out_value = entry; + else + delete entry; + dictionary_.erase(entry_iterator); + return true; +} + +DictionaryValue* DictionaryValue::DeepCopyWithoutEmptyChildren() { + Value* copy = CopyWithoutEmptyChildren(this); + return copy ? static_cast<DictionaryValue*>(copy) : new DictionaryValue; +} + +void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) { + for (DictionaryValue::key_iterator key(dictionary->begin_keys()); + key != dictionary->end_keys(); ++key) { + Value* merge_value; + if (dictionary->GetWithoutPathExpansion(*key, &merge_value)) { + // Check whether we have to merge dictionaries. + if (merge_value->IsType(Value::TYPE_DICTIONARY)) { + DictionaryValue* sub_dict; + if (GetDictionaryWithoutPathExpansion(*key, &sub_dict)) { + sub_dict->MergeDictionary( + static_cast<const DictionaryValue*>(merge_value)); + continue; + } + } + // All other cases: Make a copy and hook it up. + SetWithoutPathExpansion(*key, merge_value->DeepCopy()); + } + } +} + +DictionaryValue* DictionaryValue::DeepCopy() const { + DictionaryValue* result = new DictionaryValue; + + for (ValueMap::const_iterator current_entry(dictionary_.begin()); + current_entry != dictionary_.end(); ++current_entry) { + result->SetWithoutPathExpansion(current_entry->first, + current_entry->second->DeepCopy()); + } + + return result; +} + +bool DictionaryValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + + const DictionaryValue* other_dict = + static_cast<const DictionaryValue*>(other); + key_iterator lhs_it(begin_keys()); + key_iterator rhs_it(other_dict->begin_keys()); + while (lhs_it != end_keys() && rhs_it != other_dict->end_keys()) { + Value* lhs; + Value* rhs; + if (*lhs_it != *rhs_it || + !GetWithoutPathExpansion(*lhs_it, &lhs) || + !other_dict->GetWithoutPathExpansion(*rhs_it, &rhs) || + !lhs->Equals(rhs)) { + return false; + } + ++lhs_it; + ++rhs_it; + } + if (lhs_it != end_keys() || rhs_it != other_dict->end_keys()) + return false; + + return true; +} + +///////////////////// ListValue //////////////////// + +ListValue::ListValue() : Value(TYPE_LIST) { +} + +ListValue::~ListValue() { + Clear(); +} + +void ListValue::Clear() { + for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) + delete *i; + list_.clear(); +} + +bool ListValue::Set(size_t index, Value* in_value) { + if (!in_value) + return false; + + if (index >= list_.size()) { + // Pad out any intermediate indexes with null settings + while (index > list_.size()) + Append(CreateNullValue()); + Append(in_value); + } else { + DCHECK(list_[index] != in_value); + delete list_[index]; + list_[index] = in_value; + } + return true; +} + +bool ListValue::Get(size_t index, Value** out_value) const { + if (index >= list_.size()) + return false; + + if (out_value) + *out_value = list_[index]; + + return true; +} + +bool ListValue::GetBoolean(size_t index, bool* bool_value) const { + Value* value; + if (!Get(index, &value)) + return false; + + return value->GetAsBoolean(bool_value); +} + +bool ListValue::GetInteger(size_t index, int* out_value) const { + Value* value; + if (!Get(index, &value)) + return false; + + return value->GetAsInteger(out_value); +} + +bool ListValue::GetDouble(size_t index, double* out_value) const { + Value* value; + if (!Get(index, &value)) + return false; + + return value->GetAsDouble(out_value); +} + +bool ListValue::GetString(size_t index, std::string* out_value) const { + Value* value; + if (!Get(index, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool ListValue::GetString(size_t index, string16* out_value) const { + Value* value; + if (!Get(index, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool ListValue::GetBinary(size_t index, BinaryValue** out_value) const { + Value* value; + bool result = Get(index, &value); + if (!result || !value->IsType(TYPE_BINARY)) + return false; + + if (out_value) + *out_value = static_cast<BinaryValue*>(value); + + return true; +} + +bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) const { + Value* value; + bool result = Get(index, &value); + if (!result || !value->IsType(TYPE_DICTIONARY)) + return false; + + if (out_value) + *out_value = static_cast<DictionaryValue*>(value); + + return true; +} + +bool ListValue::GetList(size_t index, ListValue** out_value) const { + Value* value; + bool result = Get(index, &value); + if (!result || !value->IsType(TYPE_LIST)) + return false; + + if (out_value) + *out_value = static_cast<ListValue*>(value); + + return true; +} + +bool ListValue::Remove(size_t index, Value** out_value) { + if (index >= list_.size()) + return false; + + if (out_value) + *out_value = list_[index]; + else + delete list_[index]; + + list_.erase(list_.begin() + index); + return true; +} + +bool ListValue::Remove(const Value& value, size_t* index) { + for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) { + if ((*i)->Equals(&value)) { + size_t previous_index = i - list_.begin(); + delete *i; + list_.erase(i); + + if (index) + *index = previous_index; + return true; + } + } + return false; +} + +void ListValue::Append(Value* in_value) { + DCHECK(in_value); + list_.push_back(in_value); +} + +bool ListValue::AppendIfNotPresent(Value* in_value) { + DCHECK(in_value); + for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) { + if ((*i)->Equals(in_value)) { + delete in_value; + return false; + } + } + list_.push_back(in_value); + return true; +} + +bool ListValue::Insert(size_t index, Value* in_value) { + DCHECK(in_value); + if (index > list_.size()) + return false; + + list_.insert(list_.begin() + index, in_value); + return true; +} + +bool ListValue::GetAsList(ListValue** out_value) { + if (out_value) + *out_value = this; + return true; +} + +bool ListValue::GetAsList(const ListValue** out_value) const { + if (out_value) + *out_value = this; + return true; +} + +ListValue* ListValue::DeepCopy() const { + ListValue* result = new ListValue; + + for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) + result->Append((*i)->DeepCopy()); + + return result; +} + +bool ListValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + + const ListValue* other_list = + static_cast<const ListValue*>(other); + const_iterator lhs_it, rhs_it; + for (lhs_it = begin(), rhs_it = other_list->begin(); + lhs_it != end() && rhs_it != other_list->end(); + ++lhs_it, ++rhs_it) { + if (!(*lhs_it)->Equals(*rhs_it)) + return false; + } + if (lhs_it != end() || rhs_it != other_list->end()) + return false; + + return true; +} + +ValueSerializer::~ValueSerializer() { +} + +} // namespace base diff --git a/base/values.h b/base/values.h new file mode 100644 index 000000000000..a30791bc6357 --- /dev/null +++ b/base/values.h @@ -0,0 +1,470 @@ +// 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 specifies a recursive data storage class called Value intended for +// storing setting and other persistable data. It includes the ability to +// specify (recursive) lists and dictionaries, so it's fairly expressive. +// However, the API is optimized for the common case, namely storing a +// hierarchical tree of simple values. Given a DictionaryValue root, you can +// easily do things like: +// +// root->SetString("global.pages.homepage", "http://goateleporter.com"); +// std::string homepage = "http://google.com"; // default/fallback value +// root->GetString("global.pages.homepage", &homepage); +// +// where "global" and "pages" are also DictionaryValues, and "homepage" is a +// string setting. If some elements of the path didn't exist yet, the +// SetString() method would create the missing elements and attach them to root +// before attaching the homepage value. + +#ifndef BASE_VALUES_H_ +#define BASE_VALUES_H_ +#pragma once + +#include <iterator> +#include <map> +#include <string> +#include <vector> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/string16.h" + +// This file declares "using base::Value", etc. at the bottom, so that +// current code can use these classes without the base namespace. In +// new code, please always use base::Value, etc. or add your own +// "using" declaration. +// http://crbug.com/88666 +namespace base { + +class BinaryValue; +class DictionaryValue; +class FundamentalValue; +class ListValue; +class StringValue; +class Value; + +typedef std::vector<Value*> ValueVector; +typedef std::map<std::string, Value*> ValueMap; + +// The Value class is the base class for Values. A Value can be instantiated +// via the Create*Value() factory methods, or by directly creating instances of +// the subclasses. +class BASE_EXPORT Value { + public: + enum Type { + TYPE_NULL = 0, + TYPE_BOOLEAN, + TYPE_INTEGER, + TYPE_DOUBLE, + TYPE_STRING, + TYPE_BINARY, + TYPE_DICTIONARY, + TYPE_LIST + }; + + virtual ~Value(); + + // Convenience methods for creating Value objects for various + // kinds of values without thinking about which class implements them. + // These can always be expected to return a valid Value*. + static Value* CreateNullValue(); + static FundamentalValue* CreateBooleanValue(bool in_value); + static FundamentalValue* CreateIntegerValue(int in_value); + static FundamentalValue* CreateDoubleValue(double in_value); + static StringValue* CreateStringValue(const std::string& in_value); + static StringValue* CreateStringValue(const string16& in_value); + + // Returns the type of the value stored by the current Value object. + // Each type will be implemented by only one subclass of Value, so it's + // safe to use the Type to determine whether you can cast from + // Value* to (Implementing Class)*. Also, a Value object never changes + // its type after construction. + Type GetType() const { return type_; } + + // Returns true if the current object represents a given type. + bool IsType(Type type) const { return type == type_; } + + // These methods allow the convenient retrieval of settings. + // If the current setting object can be converted into the given type, + // the value is returned through the |out_value| parameter and true is + // returned; otherwise, false is returned and |out_value| is unchanged. + virtual bool GetAsBoolean(bool* out_value) const; + virtual bool GetAsInteger(int* out_value) const; + virtual bool GetAsDouble(double* out_value) const; + virtual bool GetAsString(std::string* out_value) const; + virtual bool GetAsString(string16* out_value) const; + virtual bool GetAsList(ListValue** out_value); + virtual bool GetAsList(const ListValue** out_value) const; + + // This creates a deep copy of the entire Value tree, and returns a pointer + // to the copy. The caller gets ownership of the copy, of course. + // + // Subclasses return their own type directly in their overrides; + // this works because C++ supports covariant return types. + virtual Value* DeepCopy() const; + + // Compares if two Value objects have equal contents. + virtual bool Equals(const Value* other) const; + + // Compares if two Value objects have equal contents. Can handle NULLs. + // NULLs are considered equal but different from Value::CreateNullValue(). + static bool Equals(const Value* a, const Value* b); + + protected: + // This isn't safe for end-users (they should use the Create*Value() + // static methods above), but it's useful for subclasses. + explicit Value(Type type); + + private: + Value(); + + Type type_; + + DISALLOW_COPY_AND_ASSIGN(Value); +}; + +// FundamentalValue represents the simple fundamental types of values. +class BASE_EXPORT FundamentalValue : public Value { + public: + explicit FundamentalValue(bool in_value); + explicit FundamentalValue(int in_value); + explicit FundamentalValue(double in_value); + virtual ~FundamentalValue(); + + // Overridden from Value: + virtual bool GetAsBoolean(bool* out_value) const OVERRIDE; + virtual bool GetAsInteger(int* out_value) const OVERRIDE; + virtual bool GetAsDouble(double* out_value) const OVERRIDE; + virtual FundamentalValue* DeepCopy() const OVERRIDE; + virtual bool Equals(const Value* other) const OVERRIDE; + + private: + union { + bool boolean_value_; + int integer_value_; + double double_value_; + }; + + DISALLOW_COPY_AND_ASSIGN(FundamentalValue); +}; + +class BASE_EXPORT StringValue : public Value { + public: + // Initializes a StringValue with a UTF-8 narrow character string. + explicit StringValue(const std::string& in_value); + + // Initializes a StringValue with a string16. + explicit StringValue(const string16& in_value); + + virtual ~StringValue(); + + // Overridden from Value: + virtual bool GetAsString(std::string* out_value) const OVERRIDE; + virtual bool GetAsString(string16* out_value) const OVERRIDE; + virtual StringValue* DeepCopy() const OVERRIDE; + virtual bool Equals(const Value* other) const OVERRIDE; + + private: + std::string value_; + + DISALLOW_COPY_AND_ASSIGN(StringValue); +}; + +class BASE_EXPORT BinaryValue: public Value { + public: + virtual ~BinaryValue(); + + // Creates a Value to represent a binary buffer. The new object takes + // ownership of the pointer passed in, if successful. + // Returns NULL if buffer is NULL. + static BinaryValue* Create(char* buffer, size_t size); + + // For situations where you want to keep ownership of your buffer, this + // factory method creates a new BinaryValue by copying the contents of the + // buffer that's passed in. + // Returns NULL if buffer is NULL. + static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size); + + size_t GetSize() const { return size_; } + char* GetBuffer() { return buffer_; } + const char* GetBuffer() const { return buffer_; } + + // Overridden from Value: + virtual BinaryValue* DeepCopy() const OVERRIDE; + virtual bool Equals(const Value* other) const OVERRIDE; + + private: + // Constructor is private so that only objects with valid buffer pointers + // and size values can be created. + BinaryValue(char* buffer, size_t size); + + char* buffer_; + size_t size_; + + DISALLOW_COPY_AND_ASSIGN(BinaryValue); +}; + +// DictionaryValue provides a key-value dictionary with (optional) "path" +// parsing for recursive access; see the comment at the top of the file. Keys +// are |std::string|s and should be UTF-8 encoded. +class BASE_EXPORT DictionaryValue : public Value { + public: + DictionaryValue(); + virtual ~DictionaryValue(); + + // Returns true if the current dictionary has a value for the given key. + bool HasKey(const std::string& key) const; + + // Returns the number of Values in this dictionary. + size_t size() const { return dictionary_.size(); } + + // Returns whether the dictionary is empty. + bool empty() const { return dictionary_.empty(); } + + // Clears any current contents of this dictionary. + void Clear(); + + // Sets the Value associated with the given path starting from this object. + // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes + // into the next DictionaryValue down. Obviously, "." can't be used + // within a key, but there are no other restrictions on keys. + // If the key at any step of the way doesn't exist, or exists but isn't + // a DictionaryValue, a new DictionaryValue will be created and attached + // to the path in that location. + // Note that the dictionary takes ownership of the value referenced by + // |in_value|, and therefore |in_value| must be non-NULL. + void Set(const std::string& path, Value* in_value); + + // Convenience forms of Set(). These methods will replace any existing + // value at that path, even if it has a different type. + void SetBoolean(const std::string& path, bool in_value); + void SetInteger(const std::string& path, int in_value); + void SetDouble(const std::string& path, double in_value); + void SetString(const std::string& path, const std::string& in_value); + void SetString(const std::string& path, const string16& in_value); + + // Like Set(), but without special treatment of '.'. This allows e.g. URLs to + // be used as paths. + void SetWithoutPathExpansion(const std::string& key, Value* in_value); + + // Gets the Value associated with the given path starting from this object. + // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes + // into the next DictionaryValue down. If the path can be resolved + // successfully, the value for the last key in the path will be returned + // through the |out_value| parameter, and the function will return true. + // Otherwise, it will return false and |out_value| will be untouched. + // Note that the dictionary always owns the value that's returned. + bool Get(const std::string& path, Value** out_value) const; + + // These are convenience forms of Get(). The value will be retrieved + // and the return value will be true if the path is valid and the value at + // the end of the path can be returned in the form specified. + bool GetBoolean(const std::string& path, bool* out_value) const; + bool GetInteger(const std::string& path, int* out_value) const; + bool GetDouble(const std::string& path, double* out_value) const; + bool GetString(const std::string& path, std::string* out_value) const; + bool GetString(const std::string& path, string16* out_value) const; + bool GetStringASCII(const std::string& path, std::string* out_value) const; + bool GetBinary(const std::string& path, BinaryValue** out_value) const; + bool GetDictionary(const std::string& path, + DictionaryValue** out_value) const; + bool GetList(const std::string& path, ListValue** out_value) const; + + // Like Get(), but without special treatment of '.'. This allows e.g. URLs to + // be used as paths. + bool GetWithoutPathExpansion(const std::string& key, + Value** out_value) const; + bool GetIntegerWithoutPathExpansion(const std::string& key, + int* out_value) const; + bool GetDoubleWithoutPathExpansion(const std::string& key, + double* out_value) const; + bool GetStringWithoutPathExpansion(const std::string& key, + std::string* out_value) const; + bool GetStringWithoutPathExpansion(const std::string& key, + string16* out_value) const; + bool GetDictionaryWithoutPathExpansion(const std::string& key, + DictionaryValue** out_value) const; + bool GetListWithoutPathExpansion(const std::string& key, + ListValue** out_value) const; + + // Removes the Value with the specified path from this dictionary (or one + // of its child dictionaries, if the path is more than just a local key). + // If |out_value| is non-NULL, the removed Value AND ITS OWNERSHIP will be + // passed out via out_value. If |out_value| is NULL, the removed value will + // be deleted. This method returns true if |path| is a valid path; otherwise + // it will return false and the DictionaryValue object will be unchanged. + bool Remove(const std::string& path, Value** out_value); + + // Like Remove(), but without special treatment of '.'. This allows e.g. URLs + // to be used as paths. + bool RemoveWithoutPathExpansion(const std::string& key, Value** out_value); + + // Makes a copy of |this| but doesn't include empty dictionaries and lists in + // the copy. This never returns NULL, even if |this| itself is empty. + DictionaryValue* DeepCopyWithoutEmptyChildren(); + + // Merge a given dictionary into this dictionary. This is done recursively, + // i.e. any subdictionaries will be merged as well. In case of key collisions, + // the passed in dictionary takes precedence and data already present will be + // replaced. + void MergeDictionary(const DictionaryValue* dictionary); + + // Swaps contents with the |other| dictionary. + void Swap(DictionaryValue* other) { + dictionary_.swap(other->dictionary_); + } + + // This class provides an iterator for the keys in the dictionary. + // It can't be used to modify the dictionary. + // + // YOU SHOULD ALWAYS USE THE XXXWithoutPathExpansion() APIs WITH THESE, NOT + // THE NORMAL XXX() APIs. This makes sure things will work correctly if any + // keys have '.'s in them. + class key_iterator + : private std::iterator<std::input_iterator_tag, const std::string> { + public: + explicit key_iterator(ValueMap::const_iterator itr) { itr_ = itr; } + key_iterator operator++() { + ++itr_; + return *this; + } + const std::string& operator*() { return itr_->first; } + bool operator!=(const key_iterator& other) { return itr_ != other.itr_; } + bool operator==(const key_iterator& other) { return itr_ == other.itr_; } + + private: + ValueMap::const_iterator itr_; + }; + + key_iterator begin_keys() const { return key_iterator(dictionary_.begin()); } + key_iterator end_keys() const { return key_iterator(dictionary_.end()); } + + // Overridden from Value: + virtual DictionaryValue* DeepCopy() const OVERRIDE; + virtual bool Equals(const Value* other) const OVERRIDE; + + private: + ValueMap dictionary_; + + DISALLOW_COPY_AND_ASSIGN(DictionaryValue); +}; + +// This type of Value represents a list of other Value values. +class BASE_EXPORT ListValue : public Value { + public: + typedef ValueVector::iterator iterator; + typedef ValueVector::const_iterator const_iterator; + + ListValue(); + virtual ~ListValue(); + + // Clears the contents of this ListValue + void Clear(); + + // Returns the number of Values in this list. + size_t GetSize() const { return list_.size(); } + + // Returns whether the list is empty. + bool empty() const { return list_.empty(); } + + // Sets the list item at the given index to be the Value specified by + // the value given. If the index beyond the current end of the list, null + // Values will be used to pad out the list. + // Returns true if successful, or false if the index was negative or + // the value is a null pointer. + bool Set(size_t index, Value* in_value); + + // Gets the Value at the given index. Modifies |out_value| (and returns true) + // only if the index falls within the current list range. + // Note that the list always owns the Value passed out via |out_value|. + bool Get(size_t index, Value** out_value) const; + + // Convenience forms of Get(). Modifies |out_value| (and returns true) + // only if the index is valid and the Value at that index can be returned + // in the specified form. + bool GetBoolean(size_t index, bool* out_value) const; + bool GetInteger(size_t index, int* out_value) const; + bool GetDouble(size_t index, double* out_value) const; + bool GetString(size_t index, std::string* out_value) const; + bool GetString(size_t index, string16* out_value) const; + bool GetBinary(size_t index, BinaryValue** out_value) const; + bool GetDictionary(size_t index, DictionaryValue** out_value) const; + bool GetList(size_t index, ListValue** out_value) const; + + // Removes the Value with the specified index from this list. + // If |out_value| is non-NULL, the removed Value AND ITS OWNERSHIP will be + // passed out via |out_value|. If |out_value| is NULL, the removed value will + // be deleted. This method returns true if |index| is valid; otherwise + // it will return false and the ListValue object will be unchanged. + bool Remove(size_t index, Value** out_value); + + // Removes the first instance of |value| found in the list, if any, and + // deletes it. |index| is the location where |value| was found. Returns false + // if not found. + bool Remove(const Value& value, size_t* index); + + // Appends a Value to the end of the list. + void Append(Value* in_value); + + // Appends a Value if it's not already present. Takes ownership of the + // |in_value|. Returns true if successful, or false if the value was already + // present. If the value was already present the |in_value| is deleted. + bool AppendIfNotPresent(Value* in_value); + + // Insert a Value at index. + // Returns true if successful, or false if the index was out of range. + bool Insert(size_t index, Value* in_value); + + // Swaps contents with the |other| list. + void Swap(ListValue* other) { + list_.swap(other->list_); + } + + // Iteration. + iterator begin() { return list_.begin(); } + iterator end() { return list_.end(); } + + const_iterator begin() const { return list_.begin(); } + const_iterator end() const { return list_.end(); } + + // Overridden from Value: + virtual bool GetAsList(ListValue** out_value) OVERRIDE; + virtual bool GetAsList(const ListValue** out_value) const OVERRIDE; + virtual ListValue* DeepCopy() const OVERRIDE; + virtual bool Equals(const Value* other) const OVERRIDE; + + private: + ValueVector list_; + + DISALLOW_COPY_AND_ASSIGN(ListValue); +}; + +// This interface is implemented by classes that know how to serialize and +// deserialize Value objects. +class BASE_EXPORT ValueSerializer { + public: + virtual ~ValueSerializer(); + + virtual bool Serialize(const Value& root) = 0; + + // This method deserializes the subclass-specific format into a Value object. + // If the return value is non-NULL, the caller takes ownership of returned + // Value. If the return value is NULL, and if error_code is non-NULL, + // error_code will be set with the underlying error. + // If |error_message| is non-null, it will be filled in with a formatted + // error message including the location of the error if appropriate. + virtual Value* Deserialize(int* error_code, std::string* error_str) = 0; +}; + +} // namespace base + +// http://crbug.com/88666 +using base::DictionaryValue; +using base::ListValue; +using base::StringValue; +using base::Value; + +#endif // BASE_VALUES_H_ |